Skip to content

Commit

Permalink
[optimize|fix|build] Optimize AddScreen; mitigated https://issuetrack…
Browse files Browse the repository at this point in the history
  • Loading branch information
SkyD666 committed Feb 3, 2025
1 parent 4e6e6cc commit c34a837
Show file tree
Hide file tree
Showing 17 changed files with 173 additions and 190 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ android {
minSdk = 24
targetSdk = 35
versionCode = 67
versionName = "2.3-rc10"
versionName = "2.3-rc11"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
Expand Down
7 changes: 5 additions & 2 deletions app/src/main/java/com/skyd/rays/di/PagingModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import javax.inject.Singleton
object PagingModule {
@Provides
@Singleton
fun providePagingConfig(): PagingConfig =
PagingConfig(pageSize = 20, enablePlaceholders = false)
// enablePlaceholders must be true
// https://issuetracker.google.com/issues/214253526
fun providePagingConfig(): PagingConfig = PagingConfig(
pageSize = 20, enablePlaceholders = true
)
}
22 changes: 0 additions & 22 deletions app/src/main/java/com/skyd/rays/ext/LazyPagingExt.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import android.os.Parcelable
import androidx.compose.runtime.Immutable
import com.skyd.rays.base.BaseBean
import kotlinx.parcelize.Parcelize
import kotlin.random.Random

@Immutable
@Parcelize
data class UriWithStickerUuidBean(
val uri: Uri? = null,
val stickerUuid: String = "",
val id: Long = System.currentTimeMillis() - Random.nextInt(),
) : BaseBean, Parcelable
153 changes: 75 additions & 78 deletions app/src/main/java/com/skyd/rays/model/respository/AddRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@ import com.skyd.rays.model.preference.ai.ClassificationThresholdPreference
import com.skyd.rays.model.preference.ai.TextRecognizeThresholdPreference
import com.skyd.rays.util.image.ImageFormatChecker
import com.skyd.rays.util.image.format.ImageFormat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.zip
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
Expand Down Expand Up @@ -91,87 +94,81 @@ class AddRepository @Inject constructor(
}.getOrElse { return flowOnIo { throw it } }
val dataStore = appContext.dataStore
val textRecognizeThreshold = dataStore.getOrDefault(TextRecognizeThresholdPreference)
return flowOnIo {
emit(suspendCancellableCoroutine { cont ->
TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS)
.process(image)
.addOnSuccessListener {
cont.resume(getTexts(it, textRecognizeThreshold), onCancellation = null)
}
.addOnFailureListener { cont.resumeWithException(it) }
})
}.zip(flowOnIo {
emit(suspendCancellableCoroutine { cont ->
TextRecognition.getClient(ChineseTextRecognizerOptions.Builder().build())
.process(image)
.addOnSuccessListener {
cont.resume(getTexts(it, textRecognizeThreshold), onCancellation = null)
}
.addOnFailureListener { cont.resumeWithException(it) }
})
}) { other, chinese ->
chinese + other
}.zip(flowOnIo {
emit(suspendCancellableCoroutine { cont ->
TextRecognition.getClient(JapaneseTextRecognizerOptions.Builder().build())
.process(image)
.addOnSuccessListener {
cont.resume(
getTexts(it, textRecognizeThreshold), onCancellation = null
)
}
.addOnFailureListener { cont.resumeWithException(it) }
})
}) { other, japanese ->
other + japanese
}.zip(flowOnIo {
emit(suspendCancellableCoroutine { cont ->
TextRecognition.getClient(KoreanTextRecognizerOptions.Builder().build())
.process(image)
.addOnSuccessListener {
cont.resume(
getTexts(it, textRecognizeThreshold), onCancellation = null
)
}
.addOnFailureListener { cont.resumeWithException(it) }
})
}) { other, korean ->
other + korean
}.zip(flowOnIo {
emit(suspendCancellableCoroutine { cont ->
val model = dataStore.getOrDefault(StickerClassificationModelPreference)
val classificationThreshold =
dataStore.getOrDefault(ClassificationThresholdPreference)
return combine(
flow {
emit(suspendCancellableCoroutine { cont ->
TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS)
.process(image)
.addOnSuccessListener {
cont.resume(getTexts(it, textRecognizeThreshold), onCancellation = null)
}
.addOnFailureListener { cont.resumeWithException(it) }
})
},
flow {
emit(suspendCancellableCoroutine { cont ->
TextRecognition.getClient(ChineseTextRecognizerOptions.Builder().build())
.process(image)
.addOnSuccessListener {
cont.resume(getTexts(it, textRecognizeThreshold), onCancellation = null)
}
.addOnFailureListener { cont.resumeWithException(it) }
})
},
flow {
emit(suspendCancellableCoroutine { cont ->
TextRecognition.getClient(JapaneseTextRecognizerOptions.Builder().build())
.process(image)
.addOnSuccessListener {
cont.resume(getTexts(it, textRecognizeThreshold), onCancellation = null)
}
.addOnFailureListener { cont.resumeWithException(it) }
})
},
flow {
emit(suspendCancellableCoroutine { cont ->
TextRecognition.getClient(KoreanTextRecognizerOptions.Builder().build())
.process(image)
.addOnSuccessListener {
cont.resume(getTexts(it, textRecognizeThreshold), onCancellation = null)
}
.addOnFailureListener { cont.resumeWithException(it) }
})
},
flow {
emit(suspendCancellableCoroutine { cont ->
val model = dataStore.getOrDefault(StickerClassificationModelPreference)
val classificationThreshold =
dataStore.getOrDefault(ClassificationThresholdPreference)

val localModel = LocalModel.Builder()
.apply {
if (model.isBlank()) {
setAssetFilePath("stickerclassification/sticker_classification.tflite")
} else {
setAbsoluteFilePath(File(CLASSIFICATION_MODEL_DIR_FILE, model).path)
val localModel = LocalModel.Builder()
.apply {
if (model.isBlank()) {
setAssetFilePath("stickerclassification/sticker_classification.tflite")
} else {
setAbsoluteFilePath(File(CLASSIFICATION_MODEL_DIR_FILE, model).path)
}
}
}
.build()
.build()

val customImageLabelerOptions = CustomImageLabelerOptions.Builder(localModel)
.setConfidenceThreshold(classificationThreshold)
.setMaxResultCount(3)
.build()
val customImageLabelerOptions = CustomImageLabelerOptions.Builder(localModel)
.setConfidenceThreshold(classificationThreshold)
.setMaxResultCount(3)
.build()

ImageLabeling.getClient(customImageLabelerOptions).process(image)
.addOnSuccessListener { labels ->
cont.resume(
labels.map { translateClassification(it.text) },
onCancellation = null,
)
}
.addOnFailureListener { e ->
cont.resumeWithException(e)
}
})
}) { other, classification ->
(classification + other).toSet()
}.catchMap { emptySet() }
ImageLabeling.getClient(customImageLabelerOptions).process(image)
.addOnSuccessListener { labels ->
cont.resume(
labels.map { translateClassification(it.text) },
onCancellation = null,
)
}
.addOnFailureListener { e -> cont.resumeWithException(e) }
})
}
) { other, chinese, japanese, korean, classification ->
other.toSet() + chinese + japanese + korean + classification
}.flowOn(Dispatchers.IO).catchMap { emptySet() }
}

private fun getTexts(result: Text, confidence: Float): List<String> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import android.database.DatabaseUtils
import android.net.Uri
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.sqlite.db.SimpleSQLiteQuery
import com.skyd.rays.appContext
import com.skyd.rays.base.BaseRepository
Expand Down Expand Up @@ -76,10 +75,11 @@ class SearchRepository @Inject constructor(
.catchMap { emptyList() }
}

fun requestStickerWithTagsListWithAllSearchDomain(keyword: String): Flow<PagingData<StickerWithTags>> {
return flow { emit(genSql(k = keyword, useSearchDomain = { _, _ -> true })) }
.flatMapLatest { Pager(pagingConfig) { stickerDao.getStickerWithTagsPaging(it) }.flow }
.flowOn(Dispatchers.IO)
fun requestStickerWithTagsListWithAllSearchDomain(keyword: String): Flow<Pager<Int, StickerWithTags>> {
return flow {
val sql = genSql(k = keyword, useSearchDomain = { _, _ -> true })
emit(Pager(pagingConfig) { stickerDao.getStickerWithTagsPaging(sql) })
}.flowOn(Dispatchers.IO)
}

data class SearchResult(
Expand Down
2 changes: 0 additions & 2 deletions app/src/main/java/com/skyd/rays/ui/screen/add/AddEvent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,5 @@ sealed interface AddEvent : MviSingleEvent {
data class Failed(val msg: String) : AddStickersResultEvent
}

data class RemoveWaitingListSingleStickerFailedEvent(val msg: String) : AddEvent

data class InitFailed(val msg: String) : AddEvent
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.skyd.rays.ui.screen.add

import android.util.Log
import com.skyd.rays.model.bean.StickerWithTags
import com.skyd.rays.model.bean.UriWithStickerUuidBean

Expand Down Expand Up @@ -77,36 +78,31 @@ internal sealed interface AddPartialStateChange {
}
}

interface RemoveWaitingListSingleSticker : AddPartialStateChange {
data class Success(
val willSticker: UriWithStickerUuidBean,
val getStickersWithTagsState: (oldState: AddState) -> GetStickersWithTagsState = { it.getStickersWithTagsState },
val suggestTags: List<String>? = null,
val similarStickers: List<StickerWithTags>? = null,
val currentStickerChanged: Boolean = false,
) : RemoveWaitingListSingleSticker {
override fun reduce(oldState: AddState): AddState {
val getStickersWithTagsState = getStickersWithTagsState(oldState)
val stickerWithTags =
(getStickersWithTagsState as? GetStickersWithTagsState.Success)?.stickerWithTags
return oldState.copy(
waitingList = oldState.waitingList.toMutableList()
.apply { remove(willSticker) },
getStickersWithTagsState = getStickersWithTagsState,
suggestTags = suggestTags ?: oldState.suggestTags,
addedTags = if (currentStickerChanged) {
stickerWithTags?.tags?.map { it.tag }.orEmpty()
} else oldState.addedTags,
titleText = if (currentStickerChanged) {
stickerWithTags?.sticker?.title.orEmpty()
} else oldState.titleText,
similarStickers = similarStickers ?: oldState.similarStickers,
)
}
}

data class Failed(val msg: String) : RemoveWaitingListSingleSticker {
override fun reduce(oldState: AddState) = oldState
data class RemoveWaitingListSingleSticker(
val willRemove: UriWithStickerUuidBean,
val getStickersWithTagsState: (oldState: AddState) -> GetStickersWithTagsState = { it.getStickersWithTagsState },
val suggestTags: List<String>? = null,
val similarStickers: List<StickerWithTags>? = null,
val currentStickerChanged: Boolean = false,
) : AddPartialStateChange {
override fun reduce(oldState: AddState): AddState {
val getStickersWithTagsState = getStickersWithTagsState(oldState)
val stickerWithTags =
(getStickersWithTagsState as? GetStickersWithTagsState.Success)?.stickerWithTags
Log.w("RemoveWaitingListSingleSticker reduce", "Fuck $this")
return oldState.copy(
waitingList = oldState.waitingList.toMutableList()
.apply { remove(willRemove) },
getStickersWithTagsState = getStickersWithTagsState,
suggestTags = suggestTags ?: oldState.suggestTags,
addedTags = if (currentStickerChanged) {
stickerWithTags?.tags?.map { it.tag }.orEmpty()
} else oldState.addedTags,
titleText = if (currentStickerChanged) {
stickerWithTags?.sticker?.title.orEmpty()
} else oldState.titleText,
similarStickers = similarStickers ?: oldState.similarStickers,
)
}
}

Expand Down
12 changes: 2 additions & 10 deletions app/src/main/java/com/skyd/rays/ui/screen/add/AddScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ fun AddScreen(
}

var currentReplaceIndex = rememberSaveable { 0 }
val pickStickerLauncher = rememberImagePicker(multiple = false) { result ->
val replaceStickerLauncher = rememberImagePicker(multiple = false) { result ->
if (result.firstOrNull() != null) {
val waitingList = uiState.waitingList
if (waitingList.isNotEmpty()) {
Expand Down Expand Up @@ -282,7 +282,7 @@ fun AddScreen(
onSelectStickersClick = { pickStickersLauncher.launchImagePicker() },
onReplaceStickerClick = { index ->
currentReplaceIndex = index
pickStickerLauncher.launchImagePicker()
replaceStickerLauncher.launchImagePicker()
},
onRemoveStickerFromWaitingListClick = { index ->
dispatch(
Expand Down Expand Up @@ -351,14 +351,6 @@ fun AddScreen(
)
}

is AddEvent.RemoveWaitingListSingleStickerFailedEvent -> {
Log.w("AddScreen", "Fuck RemoveWaitingListSingleStickerFailedEvent")
saveButtonEnable = true
snackbarHostState.showSnackbar(
context.getString(R.string.failed_info, event.msg)
)
}

is AddEvent.AddStickersResultEvent.Success -> {
Log.w("AddScreen", "Fuck MviEventListener(viewModel.singleEvent) processNext")
processNext()
Expand Down
Loading

0 comments on commit c34a837

Please sign in to comment.