Skip to content

Backup/restore configuration #249

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
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
11 changes: 11 additions & 0 deletions core/localization/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@
<string name="gallery_tab_original">Original</string>
<string name="gallery_tab_info">Info</string>

<string name="title_backup">Backup</string>
<string name="title_text_to_image">Text to Image</string>
<string name="title_image_to_image">Image to Image</string>
<string name="title_gallery">Gallery</string>
Expand Down Expand Up @@ -401,4 +402,14 @@
<string name="report_reason_intellectual">Intellectual property infringement</string>
<string name="report_reason_adult">Adult content</string>
<string name="report_reason_other">Other</string>

<string name="backup_step_operation">Select operation</string>
<string name="backup_step_process">Proceed</string>
<string name="backup_action_restore">Restore</string>
<string name="backup_action_create">Create</string>
<string name="backup_operation_create">Create a new backup</string>
<string name="backup_operation_restore">Restore from the backup</string>
<string name="backup_entry_config">Generation provider configuration</string>
<string name="backup_entry_prefs">Appication settings</string>
<string name="backup_entry_gallery">Gallery</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.shifthackz.aisdv1.data.di

import android.content.Context
import android.os.PowerManager
import com.shifthackz.aisdv1.data.repository.BackupRepositoryImpl
import com.shifthackz.aisdv1.data.repository.DownloadableModelRepositoryImpl
import com.shifthackz.aisdv1.data.repository.EmbeddingsRepositoryImpl
import com.shifthackz.aisdv1.data.repository.GenerationResultRepositoryImpl
Expand All @@ -27,6 +28,7 @@ import com.shifthackz.aisdv1.data.repository.SwarmUiGenerationRepositoryImpl
import com.shifthackz.aisdv1.data.repository.SwarmUiModelsRepositoryImpl
import com.shifthackz.aisdv1.data.repository.TemporaryGenerationResultRepositoryImpl
import com.shifthackz.aisdv1.data.repository.WakeLockRepositoryImpl
import com.shifthackz.aisdv1.domain.repository.BackupRepository
import com.shifthackz.aisdv1.domain.repository.DownloadableModelRepository
import com.shifthackz.aisdv1.domain.repository.EmbeddingsRepository
import com.shifthackz.aisdv1.domain.repository.GenerationResultRepository
Expand Down Expand Up @@ -66,6 +68,7 @@ val repositoryModule = module {
}

singleOf(::TemporaryGenerationResultRepositoryImpl) bind TemporaryGenerationResultRepository::class
factoryOf(::BackupRepositoryImpl) bind BackupRepository::class
factoryOf(::LocalDiffusionGenerationRepositoryImpl) bind LocalDiffusionGenerationRepository::class
factoryOf(::MediaPipeGenerationRepositoryImpl) bind MediaPipeGenerationRepository::class
factoryOf(::HordeGenerationRepositoryImpl) bind HordeGenerationRepository::class
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.shifthackz.aisdv1.domain.datasource.GenerationResultDataSource
import com.shifthackz.aisdv1.domain.entity.AiGenerationResult
import com.shifthackz.aisdv1.storage.db.persistent.dao.GenerationResultDao
import com.shifthackz.aisdv1.storage.db.persistent.entity.GenerationResultEntity
import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.core.Single

internal class GenerationResultLocalDataSource(
Expand All @@ -16,6 +17,10 @@ internal class GenerationResultLocalDataSource(
.mapDomainToEntity()
.let(dao::insert)

override fun insert(results: List<AiGenerationResult>) = results
.mapDomainToEntity()
.let(dao::insert)

override fun queryAll(): Single<List<AiGenerationResult>> = dao
.query()
.map(List<GenerationResultEntity>::mapEntityToDomain)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
package com.shifthackz.aisdv1.data.repository

import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.shifthackz.aisdv1.core.common.appbuild.BuildInfoProvider
import com.shifthackz.aisdv1.core.common.schedulers.SchedulersToken
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_AI_AUTO_SAVE
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_ALLOW_LOCAL_DIFFUSION_CANCEL
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_BACKGROUND_GENERATION
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_DEMO_MODE
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_DESIGN_COLOR_TOKEN
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_DESIGN_DARK_THEME
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_DESIGN_DARK_TOKEN
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_DESIGN_DYNAMIC_COLORS
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_DESIGN_SYSTEM_DARK_THEME
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_DEVELOPER_MODE
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_FORCE_SETUP_AFTER_UPDATE
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_FORM_ALWAYS_SHOW_ADVANCED_OPTIONS
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_FORM_PROMPT_TAGGED_INPUT
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_GALLERY_GRID
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_HORDE_API_KEY
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_HUGGING_FACE_API_KEY
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_HUGGING_FACE_MODEL_KEY
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_LOCAL_DIFFUSION_CUSTOM_MODEL_PATH
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_LOCAL_DIFFUSION_SCHEDULER_THREAD
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_LOCAL_MODEL_ID
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_LOCAL_NN_API
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_MONITOR_CONNECTIVITY
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_ON_BOARDING_COMPLETE
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_OPEN_AI_API_KEY
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_SAVE_TO_MEDIA_STORE
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_SD_MODEL
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_SERVER_SOURCE
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_SERVER_URL
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_STABILITY_AI_API_KEY
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_STABILITY_AI_ENGINE_ID_KEY
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_SWARM_MODEL
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_SWARM_SERVER_URL
import com.shifthackz.aisdv1.domain.datasource.GenerationResultDataSource
import com.shifthackz.aisdv1.domain.entity.Backup
import com.shifthackz.aisdv1.domain.entity.BackupEntryToken
import com.shifthackz.aisdv1.domain.entity.Grid
import com.shifthackz.aisdv1.domain.entity.ServerSource
import com.shifthackz.aisdv1.domain.preference.PreferenceManager
import com.shifthackz.aisdv1.domain.repository.BackupRepository
import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.core.Single
import java.util.Date

internal class BackupRepositoryImpl(
private val gson: Gson,
private val generationLds: GenerationResultDataSource.Local,
private val preferenceManager: PreferenceManager,
private val buildInfoProvider: BuildInfoProvider,
) : BackupRepository {

override fun create(tokens: List<Pair<BackupEntryToken, Boolean>>): Single<ByteArray> {
val chainGallery = if (tokens.contains(BackupEntryToken.Gallery to true)) {
generationLds.queryAll()
} else {
Single.just(emptyList())
}
val chainAppConfig = if (tokens.contains(BackupEntryToken.AppConfiguration to true)) {
val map = with(preferenceManager) {
mapOf(
KEY_SERVER_URL to automatic1111ServerUrl,
KEY_SWARM_SERVER_URL to swarmUiServerUrl,
KEY_SWARM_MODEL to swarmUiModel,
KEY_DEMO_MODE to demoMode,
KEY_DEVELOPER_MODE to developerMode,
KEY_LOCAL_DIFFUSION_CUSTOM_MODEL_PATH to localOnnxCustomModelPath,
KEY_ALLOW_LOCAL_DIFFUSION_CANCEL to localOnnxAllowCancel,
KEY_LOCAL_DIFFUSION_SCHEDULER_THREAD to localOnnxSchedulerThread,
KEY_MONITOR_CONNECTIVITY to monitorConnectivity,
KEY_AI_AUTO_SAVE to autoSaveAiResults,
KEY_SAVE_TO_MEDIA_STORE to saveToMediaStore,
KEY_FORM_ALWAYS_SHOW_ADVANCED_OPTIONS to formAdvancedOptionsAlwaysShow,
KEY_FORM_PROMPT_TAGGED_INPUT to formPromptTaggedInput,
KEY_SERVER_SOURCE to source,
KEY_SD_MODEL to sdModel,
KEY_HORDE_API_KEY to hordeApiKey,
KEY_OPEN_AI_API_KEY to openAiApiKey,
KEY_HUGGING_FACE_API_KEY to huggingFaceApiKey,
KEY_HUGGING_FACE_MODEL_KEY to huggingFaceModel,
KEY_STABILITY_AI_API_KEY to stabilityAiApiKey,
KEY_STABILITY_AI_ENGINE_ID_KEY to stabilityAiEngineId,
KEY_ON_BOARDING_COMPLETE to onBoardingComplete,
KEY_FORCE_SETUP_AFTER_UPDATE to forceSetupAfterUpdate,
KEY_LOCAL_MODEL_ID to localOnnxModelId,
KEY_LOCAL_NN_API to localOnnxUseNNAPI,
KEY_DESIGN_DYNAMIC_COLORS to designUseSystemColorPalette,
KEY_DESIGN_SYSTEM_DARK_THEME to designUseSystemDarkTheme,
KEY_DESIGN_DARK_THEME to designDarkTheme,
KEY_DESIGN_COLOR_TOKEN to designColorToken,
KEY_DESIGN_DARK_TOKEN to designDarkThemeToken,
KEY_BACKGROUND_GENERATION to backgroundGeneration,
KEY_GALLERY_GRID to galleryGrid,
)
}
Single.just(map)
} else {
Single.just(emptyMap<String, Any>())
}
return Single
.zip(chainGallery, chainAppConfig, ::Pair)
.map { (gallery, config) ->
Backup(
generatedAt = Date(),
appVersion = buildInfoProvider.toString(),
appConfiguration = config,
gallery = gallery,
)
}
.map { backup -> gson.toJson(backup).encodeToByteArray() }
}

override fun restore(bytes: ByteArray): Completable = Single
.just(bytes)
.map { it.decodeToString() }
.map { gson.fromJson<Backup>(it, object : TypeToken<Backup>() {}.type) }
.flatMapCompletable { backup ->
Completable.mergeArray(
Completable.fromAction {
backup.appConfiguration.entries.forEach { (key, value) ->
when (key) {
KEY_SERVER_URL -> {
preferenceManager.automatic1111ServerUrl = value as String
}
KEY_SWARM_SERVER_URL -> {
preferenceManager.swarmUiServerUrl = value as String
}
KEY_SWARM_MODEL -> {
preferenceManager.swarmUiModel = value as String
}
KEY_DEMO_MODE -> {
preferenceManager.demoMode = value as Boolean
}
KEY_DEVELOPER_MODE -> {
preferenceManager.developerMode = value as Boolean
}
KEY_LOCAL_DIFFUSION_CUSTOM_MODEL_PATH -> {
preferenceManager.localOnnxCustomModelPath = value as String
}
KEY_ALLOW_LOCAL_DIFFUSION_CANCEL -> {
preferenceManager.localOnnxAllowCancel = value as Boolean
}
KEY_LOCAL_DIFFUSION_SCHEDULER_THREAD -> {
preferenceManager.localOnnxSchedulerThread = SchedulersToken.valueOf(value as String)
}
KEY_MONITOR_CONNECTIVITY -> {
preferenceManager.monitorConnectivity = value as Boolean
}
KEY_AI_AUTO_SAVE -> {
preferenceManager.autoSaveAiResults = value as Boolean
}
KEY_SAVE_TO_MEDIA_STORE -> {
preferenceManager.saveToMediaStore = value as Boolean
}
KEY_FORM_ALWAYS_SHOW_ADVANCED_OPTIONS -> {
preferenceManager.formAdvancedOptionsAlwaysShow = value as Boolean
}
KEY_FORM_PROMPT_TAGGED_INPUT -> {
preferenceManager.formPromptTaggedInput = value as Boolean
}
KEY_SERVER_SOURCE -> {
preferenceManager.source = ServerSource.valueOf(value as String)
}
KEY_SD_MODEL -> {
preferenceManager.sdModel = value as String
}
KEY_HORDE_API_KEY -> {
preferenceManager.hordeApiKey = value as String
}
KEY_OPEN_AI_API_KEY -> {
preferenceManager.openAiApiKey = value as String
}
KEY_HUGGING_FACE_API_KEY -> {
preferenceManager.huggingFaceApiKey = value as String
}
KEY_HUGGING_FACE_MODEL_KEY -> {
preferenceManager.huggingFaceModel = value as String
}
KEY_STABILITY_AI_API_KEY -> {
preferenceManager.stabilityAiApiKey = value as String
}
KEY_STABILITY_AI_ENGINE_ID_KEY -> {
preferenceManager.stabilityAiEngineId = value as String
}
KEY_ON_BOARDING_COMPLETE -> {
preferenceManager.onBoardingComplete = value as Boolean
}
KEY_FORCE_SETUP_AFTER_UPDATE -> {
preferenceManager.forceSetupAfterUpdate = value as Boolean
}
KEY_LOCAL_MODEL_ID -> {
preferenceManager.localOnnxModelId = value as String
}
KEY_LOCAL_NN_API -> {
preferenceManager.localOnnxUseNNAPI = value as Boolean
}
KEY_DESIGN_DYNAMIC_COLORS -> {
preferenceManager.designUseSystemColorPalette = value as Boolean
}
KEY_DESIGN_SYSTEM_DARK_THEME -> {
preferenceManager.designUseSystemDarkTheme = value as Boolean
}
KEY_DESIGN_DARK_THEME -> {
preferenceManager.designDarkTheme = value as Boolean
}
KEY_DESIGN_COLOR_TOKEN -> {
preferenceManager.designColorToken = value as String
}
KEY_DESIGN_DARK_TOKEN -> {
preferenceManager.designDarkThemeToken = value as String
}
KEY_BACKGROUND_GENERATION -> {
preferenceManager.backgroundGeneration = value as Boolean
}
KEY_GALLERY_GRID -> {
preferenceManager.galleryGrid = Grid.valueOf(value as String)
}
}
}
},
generationLds.insert(backup.gallery),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ sealed interface GenerationResultDataSource {

interface Local : GenerationResultDataSource {
fun insert(result: AiGenerationResult): Single<Long>
fun insert(results: List<AiGenerationResult>): Completable
fun queryAll(): Single<List<AiGenerationResult>>
fun queryPage(limit: Int, offset: Int): Single<List<AiGenerationResult>>
fun queryById(id: Long): Single<AiGenerationResult>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import com.shifthackz.aisdv1.domain.interactor.settings.SetupConnectionInterActo
import com.shifthackz.aisdv1.domain.interactor.settings.SetupConnectionInterActorImpl
import com.shifthackz.aisdv1.domain.interactor.wakelock.WakeLockInterActor
import com.shifthackz.aisdv1.domain.interactor.wakelock.WakeLockInterActorImpl
import com.shifthackz.aisdv1.domain.usecase.backup.CreateBackupUseCase
import com.shifthackz.aisdv1.domain.usecase.backup.CreateBackupUseCaseImpl
import com.shifthackz.aisdv1.domain.usecase.backup.RestoreBackupUseCase
import com.shifthackz.aisdv1.domain.usecase.backup.RestoreBackupUseCaseImpl
import com.shifthackz.aisdv1.domain.usecase.caching.ClearAppCacheUseCase
import com.shifthackz.aisdv1.domain.usecase.caching.ClearAppCacheUseCaseImpl
import com.shifthackz.aisdv1.domain.usecase.caching.DataPreLoaderUseCase
Expand Down Expand Up @@ -127,6 +131,8 @@ import org.koin.dsl.bind
import org.koin.dsl.module

internal val useCasesModule = module {
factoryOf(::CreateBackupUseCaseImpl) bind CreateBackupUseCase::class
factoryOf(::RestoreBackupUseCaseImpl) bind RestoreBackupUseCase::class
factoryOf(::TextToImageUseCaseImpl) bind TextToImageUseCase::class
factoryOf(::ImageToImageUseCaseImpl) bind ImageToImageUseCase::class
factoryOf(::PingStableDiffusionServiceUseCaseImpl) bind PingStableDiffusionServiceUseCase::class
Expand Down
10 changes: 10 additions & 0 deletions domain/src/main/java/com/shifthackz/aisdv1/domain/entity/Backup.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.shifthackz.aisdv1.domain.entity

import java.util.Date

data class Backup(
val generatedAt: Date = Date(),
val appVersion: String = "",
val appConfiguration: Map<String, Any> = mapOf(),
val gallery: List<AiGenerationResult> = emptyList(),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.shifthackz.aisdv1.domain.entity

enum class BackupEntryToken {
AppConfiguration,
// AppPreferences,
Gallery;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.shifthackz.aisdv1.domain.repository

import com.shifthackz.aisdv1.domain.entity.BackupEntryToken
import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.core.Single

interface BackupRepository {
fun create(tokens: List<Pair<BackupEntryToken, Boolean>>): Single<ByteArray>
fun restore(bytes: ByteArray): Completable
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.shifthackz.aisdv1.domain.usecase.backup

import com.shifthackz.aisdv1.domain.entity.BackupEntryToken
import io.reactivex.rxjava3.core.Single

interface CreateBackupUseCase {
operator fun invoke(tokens: List<Pair<BackupEntryToken, Boolean>>): Single<ByteArray>
}
Loading