Skip to content

Commit

Permalink
Bugfix for ShareScreen crashing when saving recognized item into My L…
Browse files Browse the repository at this point in the history
…ibrary,

Updating UI of ShareScreen to change icon and title according to recognized item's data.

Upping versionCode to 136
  • Loading branch information
Dima-Android committed Feb 20, 2025
1 parent bc27884 commit 95c97a6
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import org.zotero.android.api.mappers.CreatorResponseMapper
import org.zotero.android.api.mappers.ItemResponseMapper
import org.zotero.android.api.mappers.TagResponseMapper
import org.zotero.android.api.pojo.sync.ItemResponse
import org.zotero.android.api.pojo.sync.KeyBaseKeyPair
import org.zotero.android.api.pojo.sync.LibraryResponse
import org.zotero.android.api.pojo.sync.TagResponse
import org.zotero.android.architecture.Defaults
Expand All @@ -19,6 +20,8 @@ import org.zotero.android.architecture.core.EventStream
import org.zotero.android.architecture.coroutines.Dispatchers
import org.zotero.android.database.DbWrapperMain
import org.zotero.android.database.objects.Attachment
import org.zotero.android.database.objects.FieldKeys
import org.zotero.android.database.objects.ItemTypes
import org.zotero.android.database.objects.RItem
import org.zotero.android.database.requests.CreateTranslatedItemsDbRequest
import org.zotero.android.database.requests.LinkAttachmentToParentItemDbRequest
Expand Down Expand Up @@ -118,11 +121,62 @@ class PdfWorkerController @Inject constructor(
)
}
if (state is LookupData.State.translatedOnly) {
this.itemResponse = state.itemResponse
observable.emitAsync(Update.recognizedAndKeptInMemory)
val itemResponse = state.itemResponse
this.itemResponse = itemResponse
val (title, typeIconName) = getTitleAndContentTypeFromResponse(itemResponse)
observable.emitAsync(
Update.recognizedAndKeptInMemory(
recognizedTitle = title,
recognizedTypeIcon = typeIconName
)
)
}
}
}
}

private fun getTitleAndContentTypeFromResponse(itemResponse: ItemResponse): Pair<String, String> {
val title = getTitleFromResponse(itemResponse)
val contentType = getContentTypeFromResponse(itemResponse) ?: ""
val typeIconName = ItemTypes.iconName(
rawType = itemResponse.rawType,
contentType = contentType
)
return Pair(title, typeIconName)
}

private fun getTitleFromResponse(response: ItemResponse): String {
val title: String
val _title = response.fields[KeyBaseKeyPair(
key = FieldKeys.Item.title,
baseKey = null
)]
if (_title != null) {
title = _title
} else {
val _title = response.fields.entries.firstOrNull {
this.schemaController.baseKey(
type = response.rawType,
field = it.key.key
) == FieldKeys.Item.title
}?.value
title = _title ?: ""
}
return title
}

private fun getContentTypeFromResponse(data: ItemResponse): String? {
var contentType: String? = null
val allFieldKeys = data.fields.keys.toTypedArray()
for (keyPair in allFieldKeys) {
val value = data.fields[keyPair] ?: ""
when {
keyPair.key == FieldKeys.Item.Attachment.contentType || keyPair.baseKey == FieldKeys.Item.Attachment.contentType -> {
contentType = value
}
}
}
return contentType
}

private fun updateItemAndPostProgress(
Expand Down Expand Up @@ -191,7 +245,11 @@ class PdfWorkerController @Inject constructor(
}
PdfWorkerMode.recognizeAndWait -> {
this.itemResponse = item
observable.emitAsync(Update.recognizedAndKeptInMemory)
val (title, typeIconName) = getTitleAndContentTypeFromResponse(item)
observable.emitAsync(Update.recognizedAndKeptInMemory(
recognizedTitle = title,
recognizedTypeIcon = typeIconName
))
}
}
}
Expand Down Expand Up @@ -348,6 +406,6 @@ class PdfWorkerController @Inject constructor(
object recognizedDataIsEmpty: Update
data class recognizeError(val errorMessage: String) : Update
data class recognizedAndSaved(val recognizedTitle: String) : Update
object recognizedAndKeptInMemory : Update
data class recognizedAndKeptInMemory(val recognizedTitle: String, val recognizedTypeIcon: String) : Update
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,18 @@ internal class RetrieveMetadataViewModel @Inject constructor(
is PdfWorkerController.Update.recognizeError -> {
updateState { copy(retrieveMetadataState = RetrieveMetadataState.failed(update.errorMessage)) }
}

is PdfWorkerController.Update.recognizedAndSaved -> {
updateState {
copy(retrieveMetadataState = RetrieveMetadataState.success(update.recognizedTitle))
copy(
retrieveMetadataState = RetrieveMetadataState.success(
recognizedTitle = update.recognizedTitle,
recognizedTypeIcon = "" //no-op
)
)
}
}

is PdfWorkerController.Update.recognizedAndKeptInMemory -> {
//no-op
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ sealed interface RetrieveMetadataState {
object loading : RetrieveMetadataState
object recognizedDataIsEmpty : RetrieveMetadataState
data class failed(val message: String) : RetrieveMetadataState
data class success(val recognizedTitle: String) : RetrieveMetadataState
data class success(val recognizedTitle: String, val recognizedTypeIcon: String) : RetrieveMetadataState
object fileIsNotPdf : RetrieveMetadataState
}
73 changes: 66 additions & 7 deletions app/src/main/java/org/zotero/android/screens/share/ShareScreen.kt
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
package org.zotero.android.screens.share

import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.core.text.HtmlCompat
import androidx.hilt.navigation.compose.hiltViewModel
import org.zotero.android.androidx.content.getDrawableByItemType
import org.zotero.android.screens.retrievemetadata.data.RetrieveMetadataState
import org.zotero.android.screens.share.ShareViewEffect.NavigateBack
import org.zotero.android.screens.share.ShareViewEffect.NavigateToCollectionPickerScreen
Expand Down Expand Up @@ -78,13 +90,19 @@ internal fun ShareScreen(
.padding(horizontal = 16.dp)
) {
item {
ParsedShareItemSection(
item = viewState.expectedItem,
attachment = viewState.expectedAttachment,
attachmentState = viewState.attachmentState,
title = viewState.title,
itemTitle = viewModel::itemTitle
)
val retrieveMetadataState = viewState.retrieveMetadataState
if (retrieveMetadataState is RetrieveMetadataState.success) {
RecognizeItemSection(retrieveMetadataState)
} else {
ParsedShareItemSection(
item = viewState.expectedItem,
attachment = viewState.expectedAttachment,
attachmentState = viewState.attachmentState,
title = viewState.title,
itemTitle = viewModel::itemTitle
)
}

}

item {
Expand Down Expand Up @@ -120,3 +138,44 @@ internal fun ShareScreen(
}
}
}

@Composable
private fun RecognizeItemSection(retrieveMetadataState: RetrieveMetadataState.success) {
Spacer(modifier = Modifier.height(20.dp))
ShareSection {
RecognizedItemRow(
retrieveMetadataState.recognizedTitle,
retrieveMetadataState.recognizedTypeIcon
)
}
}

@Composable
fun RecognizedItemRow(title: String, typeIconName: String) {
Row(
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 44.dp)
.background(CustomTheme.colors.surface),
verticalAlignment = Alignment.CenterVertically
) {
Spacer(modifier = Modifier.width(16.dp))
Image(
modifier = Modifier.size(22.dp),
painter = painterResource(id = LocalContext.current.getDrawableByItemType(typeIconName)),
contentDescription = null,
)
Spacer(modifier = Modifier.width(16.dp))
Text(
modifier = Modifier.padding(end = 8.dp),
text = HtmlCompat.fromHtml(
title,
HtmlCompat.FROM_HTML_MODE_LEGACY
).toString(),
style = CustomTheme.typography.newBody,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -1001,10 +1001,11 @@ internal class ShareViewModel @Inject constructor(
private fun maybeSaveCachedDataInPdfWorker() {
if (viewState.retrieveMetadataState is RetrieveMetadataState.success) {
val tags = viewState.tags.map { TagResponse(tag = it.name, type = it.type) }
val collectionKeys = this.selectedCollectionId.keyGet?.let { setOf(it) } ?: emptySet()
pdfWorkerController.saveCachedData(
attachmentItemKey = this.attachmentKey,
libraryId = this.selectedLibraryId,
collectionKeys = setOf(this.selectedCollectionId.keyGet!!),
collectionKeys = collectionKeys,
tags = tags
)
} else {
Expand Down Expand Up @@ -1077,7 +1078,10 @@ internal class ShareViewModel @Inject constructor(
}
is PdfWorkerController.Update.recognizedAndKeptInMemory -> {
updateState {
copy(retrieveMetadataState = RetrieveMetadataState.success(""))
copy(retrieveMetadataState = RetrieveMetadataState.success(
recognizedTitle = update.recognizedTitle,
recognizedTypeIcon = update.recognizedTypeIcon
))
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/BuildConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ object BuildConfig {
const val compileSdkVersion = 34
const val targetSdk = 34

val versionCode = 135 // Must be updated on every build
val versionCode = 136 // Must be updated on every build
val version = Version(
major = 1,
minor = 0,
Expand Down

0 comments on commit 95c97a6

Please sign in to comment.