Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ fun AiGenerationResult.mapDomainToEntity(): GenerationResultEntity = with(this)
subSeed = subSeed,
subSeedStrength = subSeedStrength,
denoisingStrength = denoisingStrength,
hidden = hidden,
)
}
//endregion
Expand Down Expand Up @@ -53,6 +54,7 @@ fun GenerationResultEntity.mapEntityToDomain(): AiGenerationResult = with(this)
subSeed = subSeed,
subSeedStrength = subSeedStrength,
denoisingStrength = denoisingStrength,
hidden = hidden,
)
}
//endregion
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ fun Pair<ImageToImagePayload, SdGenerationResponse>.mapToAiGenResult(): AiGenera
subSeed = if (payload.subSeed.trim().isNotEmpty()) payload.subSeed
else mapSubSeedFromRemote(response.info),
subSeedStrength = payload.subSeedStrength,
hidden = false,
)
}

Expand All @@ -165,6 +166,7 @@ fun Pair<ImageToImagePayload, String>.mapCloudToAiGenResult(): AiGenerationResul
seed = payload.seed,
subSeed = payload.subSeed,
subSeedStrength = payload.subSeedStrength,
hidden = false,
)
}
//endregion
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ fun Pair<TextToImagePayload, SdGenerationResponse>.mapToAiGenResult(): AiGenerat
subSeed = if (payload.subSeed.trim().isNotEmpty()) payload.subSeed
else mapSubSeedFromRemote(response.info),
subSeedStrength = payload.subSeedStrength,
hidden = false,
)
}

Expand All @@ -166,6 +167,7 @@ fun Pair<TextToImagePayload, String>.mapCloudToAiGenResult(): AiGenerationResult
seed = payload.seed,
subSeed = payload.subSeed,
subSeedStrength = payload.subSeedStrength,
hidden = false,
)
}

Expand All @@ -189,6 +191,7 @@ fun Pair<TextToImagePayload, String>.mapLocalDiffusionToAiGenResult(): AiGenerat
seed = payload.seed,
subSeed = payload.subSeed,
subSeedStrength = payload.subSeedStrength,
hidden = false,
)
}
//endregion
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class PreferenceManagerImpl(

override var formPromptTaggedInput: Boolean by preferences.delegates.boolean(
key = KEY_FORM_PROMPT_TAGGED_INPUT,
default = true,
default = false,
onChanged = ::onPreferencesChanged,
)

Expand Down Expand Up @@ -274,7 +274,7 @@ class PreferenceManagerImpl(
const val KEY_AI_AUTO_SAVE = "key_ai_auto_save"
const val KEY_SAVE_TO_MEDIA_STORE = "key_save_to_media_store"
const val KEY_FORM_ALWAYS_SHOW_ADVANCED_OPTIONS = "key_always_show_advanced_options"
const val KEY_FORM_PROMPT_TAGGED_INPUT = "key_prompt_tagged_input"
const val KEY_FORM_PROMPT_TAGGED_INPUT = "key_prompt_tagged_input_kb"
const val KEY_SERVER_SOURCE = "key_server_source"
const val KEY_SD_MODEL = "key_sd_model"
const val KEY_HORDE_API_KEY = "key_horde_api_key"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,11 @@ internal class GenerationResultRepositoryImpl(
override fun deleteByIdList(idList: List<Long>) = localDataSource.deleteByIdList(idList)

override fun deleteAll() = localDataSource.deleteAll()

override fun toggleVisibility(id: Long): Single<Boolean> = localDataSource
.queryById(id)
.map { it.copy(hidden = !it.hidden) }
.flatMap(localDataSource::insert)
.flatMap { localDataSource.queryById(id) }
.map(AiGenerationResult::hidden)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ val mockAiGenerationResult = AiGenerationResult(
subSeed = "1504",
subSeedStrength = 5598f,
denoisingStrength = 1504f,
hidden = false,
)

val mockAiGenerationResults = listOf(mockAiGenerationResult)
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ val mockGenerationResultEntity = GenerationResultEntity(
subSeed = "1504",
subSeedStrength = 5598f,
denoisingStrength = 1504f,
hidden = false,
)

val mockGenerationResultEntities = listOf(mockGenerationResultEntity)
Original file line number Diff line number Diff line change
Expand Up @@ -299,4 +299,40 @@ class GenerationResultRepositoryImplTest {
.await()
.assertNotComplete()
}

@Test
fun `given attempt to toggle image visibility, process succeeds, expected boolean value`() {
every {
stubLocalDataSource.queryById(any())
} returns Single.just(mockAiGenerationResult)

every {
stubLocalDataSource.insert(any())
} returns Single.just(5598L)

repository
.toggleVisibility(5598L)
.test()
.await()
.assertComplete()
}

@Test
fun `given attempt to toggle image visibility, error occurs, expected boolean value`() {
every {
stubLocalDataSource.queryById(any())
} returns Single.just(mockAiGenerationResult)

every {
stubLocalDataSource.insert(any())
} returns Single.error(stubException)

repository
.toggleVisibility(5598L)
.test()
.assertError(stubException)
.assertNoValues()
.await()
.assertNotComplete()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ internal class ImageToImageDemoImpl(
subSeed = timeProvider.currentTimeMillis().toString(),
subSeedStrength = 0f,
denoisingStrength = 0f,
hidden = false,
)

override fun getDemoBase64(payload: ImageToImagePayload) = execute(payload)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ internal class TextToImageDemoImpl(
subSeed = timeProvider.currentTimeMillis().toString(),
subSeedStrength = 0f,
denoisingStrength = 0f,
hidden = false,
)

override fun getDemoBase64(payload: TextToImagePayload) = execute(payload)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ import com.shifthackz.aisdv1.domain.usecase.gallery.GetGalleryItemsUseCase
import com.shifthackz.aisdv1.domain.usecase.gallery.GetGalleryItemsUseCaseImpl
import com.shifthackz.aisdv1.domain.usecase.gallery.GetMediaStoreInfoUseCase
import com.shifthackz.aisdv1.domain.usecase.gallery.GetMediaStoreInfoUseCaseImpl
import com.shifthackz.aisdv1.domain.usecase.gallery.ToggleImageVisibilityUseCase
import com.shifthackz.aisdv1.domain.usecase.gallery.ToggleImageVisibilityUseCaseImpl
import com.shifthackz.aisdv1.domain.usecase.generation.GetGenerationResultPagedUseCase
import com.shifthackz.aisdv1.domain.usecase.generation.GetGenerationResultPagedUseCaseImpl
import com.shifthackz.aisdv1.domain.usecase.generation.GetGenerationResultUseCase
Expand Down Expand Up @@ -157,6 +159,7 @@ internal val useCasesModule = module {
factoryOf(::ObserveSeverConnectivityUseCaseImpl) bind ObserveSeverConnectivityUseCase::class
factoryOf(::ObserveHordeProcessStatusUseCaseImpl) bind ObserveHordeProcessStatusUseCase::class
factoryOf(::GetMediaStoreInfoUseCaseImpl) bind GetMediaStoreInfoUseCase::class
factoryOf(::ToggleImageVisibilityUseCaseImpl) bind ToggleImageVisibilityUseCase::class
factoryOf(::GetRandomImageUseCaseImpl) bind GetRandomImageUseCase::class
factoryOf(::SaveLastResultToCacheUseCaseImpl) bind SaveLastResultToCacheUseCase::class
factoryOf(::GetLastResultFromCacheUseCaseImpl) bind GetLastResultFromCacheUseCase::class
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ data class AiGenerationResult(
val subSeed: String,
val subSeedStrength: Float,
val denoisingStrength: Float,
val hidden: Boolean,
) {
enum class Type(val key: String) {
TEXT_TO_IMAGE("txt2img"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ interface GenerationResultRepository {
fun deleteByIdList(idList: List<Long>): Completable

fun deleteAll(): Completable

fun toggleVisibility(id: Long): Single<Boolean>
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class DebugInsertBadBase64UseCaseImpl(
subSeed = "",
subSeedStrength = 0f,
denoisingStrength = 0f,
hidden = false,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.shifthackz.aisdv1.domain.usecase.gallery

import io.reactivex.rxjava3.core.Single

interface ToggleImageVisibilityUseCase {
operator fun invoke(id: Long): Single<Boolean>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.shifthackz.aisdv1.domain.usecase.gallery

import com.shifthackz.aisdv1.domain.repository.GenerationResultRepository

internal class ToggleImageVisibilityUseCaseImpl(
private val repository: GenerationResultRepository,
) : ToggleImageVisibilityUseCase {

override fun invoke(id: Long) = repository.toggleVisibility(id)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ val mockAiGenerationResult = AiGenerationResult(
subSeed = "1504",
subSeedStrength = 5598f,
denoisingStrength = 1504f,
hidden = false,
)

val mockAiGenerationResults = listOf(mockAiGenerationResult)
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.shifthackz.aisdv1.domain.usecase.gallery

import com.nhaarman.mockitokotlin2.any
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.whenever
import com.shifthackz.aisdv1.domain.repository.GenerationResultRepository
import io.reactivex.rxjava3.core.Single
import org.junit.Test

class ToggleImageVisibilityUseCaseImplTest {

private val stubRepository = mock<GenerationResultRepository>()

private val useCase = ToggleImageVisibilityUseCaseImpl(stubRepository)

@Test
fun `given repository returned value, expected valid boolean value`() {
whenever(stubRepository.toggleVisibility(any()))
.thenReturn(Single.just(true))

useCase(5598L)
.test()
.await()
.assertValue(true)
.assertComplete()
}

@Test
fun `given repository thrown exception, expected error value`() {
val stubException = Throwable("Error communicating with MediaStore.")

whenever(stubRepository.toggleVisibility(any()))
.thenReturn(Single.error(stubException))

useCase(5598L)
.test()
.await()
.assertError(stubException)
.assertNoValues()
.assertNotComplete()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ val viewModelModule = module {
getGenerationResultUseCase = get(),
getLastResultFromCacheUseCase = get(),
deleteGalleryItemUseCase = get(),
toggleImageVisibilityUseCase = get(),
galleryDetailBitmapExporter = get(),
base64ToBitmapConverter = get(),
schedulersProvider = get(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ sealed interface GalleryDetailIntent : MviIntent {
Request, Confirm
}

data object ToggleVisibility : GalleryDetailIntent

data object Report : GalleryDetailIntent

data object DismissDialog : GalleryDetailIntent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ val mockGalleryDetailTxt2Img = GalleryDetailState.Content(
subSeed = "0001".asUiText(),
subSeedStrength = "".asUiText(),
denoisingStrength = "".asUiText(),
hidden = false,
)
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import androidx.compose.material.icons.filled.ContentCopy
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Report
import androidx.compose.material.icons.filled.Share
import androidx.compose.material.icons.filled.Visibility
import androidx.compose.material.icons.filled.VisibilityOff
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
Expand Down Expand Up @@ -235,6 +237,18 @@ private fun GalleryDetailNavigationBar(
tint = LocalContentColor.current,
)
}
IconButton(
onClick = { processIntent(GalleryDetailIntent.ToggleVisibility) },
) {
Icon(
imageVector = if (state.hidden) {
Icons.Default.VisibilityOff
} else {
Icons.Default.Visibility
},
contentDescription = "Toggle visibility",
)
}
IconButton(
onClick = { processIntent(GalleryDetailIntent.Export.Params) },
) {
Expand Down Expand Up @@ -297,6 +311,7 @@ private fun GalleryDetailContentState(
GalleryDetailState.Tab.IMAGE -> ZoomableImage(
modifier = Modifier.fillMaxSize(),
source = ZoomableImageSource.Bmp(state.bitmap),
hideImage = state.hidden,
)

GalleryDetailState.Tab.ORIGINAL -> state.inputBitmap?.let { bmp ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ sealed interface GalleryDetailState : MviState {
val subSeed: UiText,
val subSeedStrength: UiText,
val denoisingStrength: UiText,
val hidden: Boolean,
) : GalleryDetailState

fun withTab(tab: Tab): GalleryDetailState = when (this) {
Expand All @@ -60,6 +61,11 @@ sealed interface GalleryDetailState : MviState {
is Loading -> copy(screenModal = dialog)
}

fun withHiddenState(value: Boolean) = when (this) {
is Content -> copy(hidden = value)
is Loading -> this
}

enum class Tab(
@StringRes val label: Int,
@DrawableRes val iconRes: Int,
Expand Down Expand Up @@ -101,5 +107,6 @@ fun Triple<AiGenerationResult, Base64ToBitmapConverter.Output, Base64ToBitmapCon
subSeed = ai.subSeed.asUiText(),
subSeedStrength = ai.subSeedStrength.toString().asUiText(),
denoisingStrength = ai.denoisingStrength.toString().asUiText(),
hidden = ai.hidden,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.shifthackz.aisdv1.core.viewmodel.MviRxViewModel
import com.shifthackz.aisdv1.domain.entity.AiGenerationResult
import com.shifthackz.aisdv1.domain.usecase.caching.GetLastResultFromCacheUseCase
import com.shifthackz.aisdv1.domain.usecase.gallery.DeleteGalleryItemUseCase
import com.shifthackz.aisdv1.domain.usecase.gallery.ToggleImageVisibilityUseCase
import com.shifthackz.aisdv1.domain.usecase.generation.GetGenerationResultUseCase
import com.shifthackz.aisdv1.presentation.core.GenerationFormUpdateEvent
import com.shifthackz.aisdv1.presentation.model.Modal
Expand All @@ -23,6 +24,7 @@ class GalleryDetailViewModel(
private val getGenerationResultUseCase: GetGenerationResultUseCase,
private val getLastResultFromCacheUseCase: GetLastResultFromCacheUseCase,
private val deleteGalleryItemUseCase: DeleteGalleryItemUseCase,
private val toggleImageVisibilityUseCase: ToggleImageVisibilityUseCase,
private val galleryDetailBitmapExporter: GalleryDetailBitmapExporter,
private val base64ToBitmapConverter: Base64ToBitmapConverter,
private val schedulersProvider: SchedulersProvider,
Expand Down Expand Up @@ -85,6 +87,8 @@ class GalleryDetailViewModel(
GalleryDetailIntent.Report -> (currentState as? GalleryDetailState.Content)
?.id
?.let(mainRouter::navigateToReportImage)

GalleryDetailIntent.ToggleVisibility -> toggleVisibility()
}
}

Expand Down Expand Up @@ -146,6 +150,12 @@ class GalleryDetailViewModel(

}

private fun toggleVisibility() = !toggleImageVisibilityUseCase(itemId)
.subscribeOnMainThread(schedulersProvider)
.subscribeBy(::errorLog) { hidden ->
updateState { it.withHiddenState(hidden) }
}

private fun getGenerationResult(id: Long): Single<AiGenerationResult> {
if (id <= 0) return getLastResultFromCacheUseCase()
return getGenerationResultUseCase(id)
Expand Down
Loading