Skip to content

Commit 54945de

Browse files
committed
WIP: Backup screen flow UI, data layer
1 parent 2444712 commit 54945de

File tree

23 files changed

+801
-53
lines changed

23 files changed

+801
-53
lines changed

core/localization/src/main/res/values/strings.xml

+10
Original file line numberDiff line numberDiff line change
@@ -402,4 +402,14 @@
402402
<string name="report_reason_intellectual">Intellectual property infringement</string>
403403
<string name="report_reason_adult">Adult content</string>
404404
<string name="report_reason_other">Other</string>
405+
406+
<string name="backup_step_operation">Select operation</string>
407+
<string name="backup_step_process">Proceed</string>
408+
<string name="backup_action_restore">Restore</string>
409+
<string name="backup_action_create">Create</string>
410+
<string name="backup_operation_create">Create a new backup</string>
411+
<string name="backup_operation_restore">Restore from the backup</string>
412+
<string name="backup_entry_config">Generation provider configuration</string>
413+
<string name="backup_entry_prefs">Appication settings</string>
414+
<string name="backup_entry_gallery">Gallery</string>
405415
</resources>

data/src/main/java/com/shifthackz/aisdv1/data/di/RepositoryModule.kt

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.shifthackz.aisdv1.data.di
22

33
import android.content.Context
44
import android.os.PowerManager
5+
import com.shifthackz.aisdv1.data.repository.BackupRepositoryImpl
56
import com.shifthackz.aisdv1.data.repository.DownloadableModelRepositoryImpl
67
import com.shifthackz.aisdv1.data.repository.EmbeddingsRepositoryImpl
78
import com.shifthackz.aisdv1.data.repository.GenerationResultRepositoryImpl
@@ -27,6 +28,7 @@ import com.shifthackz.aisdv1.data.repository.SwarmUiGenerationRepositoryImpl
2728
import com.shifthackz.aisdv1.data.repository.SwarmUiModelsRepositoryImpl
2829
import com.shifthackz.aisdv1.data.repository.TemporaryGenerationResultRepositoryImpl
2930
import com.shifthackz.aisdv1.data.repository.WakeLockRepositoryImpl
31+
import com.shifthackz.aisdv1.domain.repository.BackupRepository
3032
import com.shifthackz.aisdv1.domain.repository.DownloadableModelRepository
3133
import com.shifthackz.aisdv1.domain.repository.EmbeddingsRepository
3234
import com.shifthackz.aisdv1.domain.repository.GenerationResultRepository
@@ -66,6 +68,7 @@ val repositoryModule = module {
6668
}
6769

6870
singleOf(::TemporaryGenerationResultRepositoryImpl) bind TemporaryGenerationResultRepository::class
71+
factoryOf(::BackupRepositoryImpl) bind BackupRepository::class
6972
factoryOf(::LocalDiffusionGenerationRepositoryImpl) bind LocalDiffusionGenerationRepository::class
7073
factoryOf(::MediaPipeGenerationRepositoryImpl) bind MediaPipeGenerationRepository::class
7174
factoryOf(::HordeGenerationRepositoryImpl) bind HordeGenerationRepository::class

data/src/main/java/com/shifthackz/aisdv1/data/local/GenerationResultLocalDataSource.kt

+5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.shifthackz.aisdv1.domain.datasource.GenerationResultDataSource
66
import com.shifthackz.aisdv1.domain.entity.AiGenerationResult
77
import com.shifthackz.aisdv1.storage.db.persistent.dao.GenerationResultDao
88
import com.shifthackz.aisdv1.storage.db.persistent.entity.GenerationResultEntity
9+
import io.reactivex.rxjava3.core.Completable
910
import io.reactivex.rxjava3.core.Single
1011

1112
internal class GenerationResultLocalDataSource(
@@ -16,6 +17,10 @@ internal class GenerationResultLocalDataSource(
1617
.mapDomainToEntity()
1718
.let(dao::insert)
1819

20+
override fun insert(results: List<AiGenerationResult>) = results
21+
.mapDomainToEntity()
22+
.let(dao::insert)
23+
1924
override fun queryAll(): Single<List<AiGenerationResult>> = dao
2025
.query()
2126
.map(List<GenerationResultEntity>::mapEntityToDomain)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
package com.shifthackz.aisdv1.data.repository
2+
3+
import com.google.gson.Gson
4+
import com.google.gson.reflect.TypeToken
5+
import com.shifthackz.aisdv1.core.common.appbuild.BuildInfoProvider
6+
import com.shifthackz.aisdv1.core.common.schedulers.SchedulersToken
7+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_AI_AUTO_SAVE
8+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_ALLOW_LOCAL_DIFFUSION_CANCEL
9+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_BACKGROUND_GENERATION
10+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_DEMO_MODE
11+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_DESIGN_COLOR_TOKEN
12+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_DESIGN_DARK_THEME
13+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_DESIGN_DARK_TOKEN
14+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_DESIGN_DYNAMIC_COLORS
15+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_DESIGN_SYSTEM_DARK_THEME
16+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_DEVELOPER_MODE
17+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_FORCE_SETUP_AFTER_UPDATE
18+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_FORM_ALWAYS_SHOW_ADVANCED_OPTIONS
19+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_FORM_PROMPT_TAGGED_INPUT
20+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_GALLERY_GRID
21+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_HORDE_API_KEY
22+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_HUGGING_FACE_API_KEY
23+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_HUGGING_FACE_MODEL_KEY
24+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_LOCAL_DIFFUSION_CUSTOM_MODEL_PATH
25+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_LOCAL_DIFFUSION_SCHEDULER_THREAD
26+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_LOCAL_MODEL_ID
27+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_LOCAL_NN_API
28+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_MONITOR_CONNECTIVITY
29+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_ON_BOARDING_COMPLETE
30+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_OPEN_AI_API_KEY
31+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_SAVE_TO_MEDIA_STORE
32+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_SD_MODEL
33+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_SERVER_SOURCE
34+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_SERVER_URL
35+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_STABILITY_AI_API_KEY
36+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_STABILITY_AI_ENGINE_ID_KEY
37+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_SWARM_MODEL
38+
import com.shifthackz.aisdv1.data.preference.PreferenceManagerImpl.Companion.KEY_SWARM_SERVER_URL
39+
import com.shifthackz.aisdv1.domain.datasource.GenerationResultDataSource
40+
import com.shifthackz.aisdv1.domain.entity.Backup
41+
import com.shifthackz.aisdv1.domain.entity.BackupEntryToken
42+
import com.shifthackz.aisdv1.domain.entity.Grid
43+
import com.shifthackz.aisdv1.domain.entity.ServerSource
44+
import com.shifthackz.aisdv1.domain.preference.PreferenceManager
45+
import com.shifthackz.aisdv1.domain.repository.BackupRepository
46+
import io.reactivex.rxjava3.core.Completable
47+
import io.reactivex.rxjava3.core.Single
48+
import java.util.Date
49+
50+
internal class BackupRepositoryImpl(
51+
private val gson: Gson,
52+
private val generationLds: GenerationResultDataSource.Local,
53+
private val preferenceManager: PreferenceManager,
54+
private val buildInfoProvider: BuildInfoProvider,
55+
) : BackupRepository {
56+
57+
override fun create(tokens: List<Pair<BackupEntryToken, Boolean>>): Single<ByteArray> {
58+
val chainGallery = if (tokens.contains(BackupEntryToken.Gallery to true)) {
59+
generationLds.queryAll()
60+
} else {
61+
Single.just(emptyList())
62+
}
63+
val chainAppConfig = if (tokens.contains(BackupEntryToken.AppConfiguration to true)) {
64+
val map = with(preferenceManager) {
65+
mapOf(
66+
KEY_SERVER_URL to automatic1111ServerUrl,
67+
KEY_SWARM_SERVER_URL to swarmUiServerUrl,
68+
KEY_SWARM_MODEL to swarmUiModel,
69+
KEY_DEMO_MODE to demoMode,
70+
KEY_DEVELOPER_MODE to developerMode,
71+
KEY_LOCAL_DIFFUSION_CUSTOM_MODEL_PATH to localDiffusionCustomModelPath,
72+
KEY_ALLOW_LOCAL_DIFFUSION_CANCEL to localDiffusionAllowCancel,
73+
KEY_LOCAL_DIFFUSION_SCHEDULER_THREAD to localDiffusionSchedulerThread,
74+
KEY_MONITOR_CONNECTIVITY to monitorConnectivity,
75+
KEY_AI_AUTO_SAVE to autoSaveAiResults,
76+
KEY_SAVE_TO_MEDIA_STORE to saveToMediaStore,
77+
KEY_FORM_ALWAYS_SHOW_ADVANCED_OPTIONS to formAdvancedOptionsAlwaysShow,
78+
KEY_FORM_PROMPT_TAGGED_INPUT to formPromptTaggedInput,
79+
KEY_SERVER_SOURCE to source,
80+
KEY_SD_MODEL to sdModel,
81+
KEY_HORDE_API_KEY to hordeApiKey,
82+
KEY_OPEN_AI_API_KEY to openAiApiKey,
83+
KEY_HUGGING_FACE_API_KEY to huggingFaceApiKey,
84+
KEY_HUGGING_FACE_MODEL_KEY to huggingFaceModel,
85+
KEY_STABILITY_AI_API_KEY to stabilityAiApiKey,
86+
KEY_STABILITY_AI_ENGINE_ID_KEY to stabilityAiEngineId,
87+
KEY_ON_BOARDING_COMPLETE to onBoardingComplete,
88+
KEY_FORCE_SETUP_AFTER_UPDATE to forceSetupAfterUpdate,
89+
KEY_LOCAL_MODEL_ID to localModelId,
90+
KEY_LOCAL_NN_API to localUseNNAPI,
91+
KEY_DESIGN_DYNAMIC_COLORS to designUseSystemColorPalette,
92+
KEY_DESIGN_SYSTEM_DARK_THEME to designUseSystemDarkTheme,
93+
KEY_DESIGN_DARK_THEME to designDarkTheme,
94+
KEY_DESIGN_COLOR_TOKEN to designColorToken,
95+
KEY_DESIGN_DARK_TOKEN to designDarkThemeToken,
96+
KEY_BACKGROUND_GENERATION to backgroundGeneration,
97+
KEY_GALLERY_GRID to galleryGrid,
98+
)
99+
}
100+
Single.just(map)
101+
} else {
102+
Single.just(emptyMap<String, Any>())
103+
}
104+
return Single
105+
.zip(chainGallery, chainAppConfig, ::Pair)
106+
.map { (gallery, config) ->
107+
Backup(
108+
generatedAt = Date(),
109+
appVersion = buildInfoProvider.toString(),
110+
appConfiguration = config,
111+
gallery = gallery,
112+
)
113+
}
114+
.map { backup -> gson.toJson(backup).encodeToByteArray() }
115+
}
116+
117+
override fun restore(bytes: ByteArray): Completable = Single
118+
.just(bytes)
119+
.map { it.decodeToString() }
120+
.map { gson.fromJson<Backup>(it, object : TypeToken<Backup>() {}.type) }
121+
.flatMapCompletable { backup ->
122+
Completable.mergeArray(
123+
Completable.fromAction {
124+
backup.appConfiguration.entries.forEach { (key, value) ->
125+
when (key) {
126+
KEY_SERVER_URL -> {
127+
preferenceManager.automatic1111ServerUrl = value as String
128+
}
129+
KEY_SWARM_SERVER_URL -> {
130+
preferenceManager.swarmUiServerUrl = value as String
131+
}
132+
KEY_SWARM_MODEL -> {
133+
preferenceManager.swarmUiModel = value as String
134+
}
135+
KEY_DEMO_MODE -> {
136+
preferenceManager.demoMode = value as Boolean
137+
}
138+
KEY_DEVELOPER_MODE -> {
139+
preferenceManager.developerMode = value as Boolean
140+
}
141+
KEY_LOCAL_DIFFUSION_CUSTOM_MODEL_PATH -> {
142+
preferenceManager.localDiffusionCustomModelPath = value as String
143+
}
144+
KEY_ALLOW_LOCAL_DIFFUSION_CANCEL -> {
145+
preferenceManager.localDiffusionAllowCancel = value as Boolean
146+
}
147+
KEY_LOCAL_DIFFUSION_SCHEDULER_THREAD -> {
148+
preferenceManager.localDiffusionSchedulerThread = value as SchedulersToken
149+
}
150+
KEY_MONITOR_CONNECTIVITY -> {
151+
preferenceManager.monitorConnectivity = value as Boolean
152+
}
153+
KEY_AI_AUTO_SAVE -> {
154+
preferenceManager.autoSaveAiResults = value as Boolean
155+
}
156+
KEY_SAVE_TO_MEDIA_STORE -> {
157+
preferenceManager.saveToMediaStore = value as Boolean
158+
}
159+
KEY_FORM_ALWAYS_SHOW_ADVANCED_OPTIONS -> {
160+
preferenceManager.formAdvancedOptionsAlwaysShow = value as Boolean
161+
}
162+
KEY_FORM_PROMPT_TAGGED_INPUT -> {
163+
preferenceManager.formPromptTaggedInput = value as Boolean
164+
}
165+
KEY_SERVER_SOURCE -> {
166+
preferenceManager.source = value as ServerSource
167+
}
168+
KEY_SD_MODEL -> {
169+
preferenceManager.sdModel = value as String
170+
}
171+
KEY_HORDE_API_KEY -> {
172+
preferenceManager.hordeApiKey = value as String
173+
}
174+
KEY_OPEN_AI_API_KEY -> {
175+
preferenceManager.openAiApiKey = value as String
176+
}
177+
KEY_HUGGING_FACE_API_KEY -> {
178+
preferenceManager.huggingFaceApiKey = value as String
179+
}
180+
KEY_HUGGING_FACE_MODEL_KEY -> {
181+
preferenceManager.huggingFaceModel = value as String
182+
}
183+
KEY_STABILITY_AI_API_KEY -> {
184+
preferenceManager.stabilityAiApiKey = value as String
185+
}
186+
KEY_STABILITY_AI_ENGINE_ID_KEY -> {
187+
preferenceManager.stabilityAiEngineId = value as String
188+
}
189+
KEY_ON_BOARDING_COMPLETE -> {
190+
preferenceManager.onBoardingComplete = value as Boolean
191+
}
192+
KEY_FORCE_SETUP_AFTER_UPDATE -> {
193+
preferenceManager.forceSetupAfterUpdate = value as Boolean
194+
}
195+
KEY_LOCAL_MODEL_ID -> {
196+
preferenceManager.localModelId = value as String
197+
}
198+
KEY_LOCAL_NN_API -> {
199+
preferenceManager.localUseNNAPI = value as Boolean
200+
}
201+
KEY_DESIGN_DYNAMIC_COLORS -> {
202+
preferenceManager.designUseSystemColorPalette = value as Boolean
203+
}
204+
KEY_DESIGN_SYSTEM_DARK_THEME -> {
205+
preferenceManager.designUseSystemDarkTheme = value as Boolean
206+
}
207+
KEY_DESIGN_DARK_THEME -> {
208+
preferenceManager.designDarkTheme = value as Boolean
209+
}
210+
KEY_DESIGN_COLOR_TOKEN -> {
211+
preferenceManager.designColorToken = value as String
212+
}
213+
KEY_DESIGN_DARK_TOKEN -> {
214+
preferenceManager.designDarkThemeToken = value as String
215+
}
216+
KEY_BACKGROUND_GENERATION -> {
217+
preferenceManager.backgroundGeneration = value as Boolean
218+
}
219+
KEY_GALLERY_GRID -> {
220+
preferenceManager.galleryGrid = value as Grid
221+
}
222+
}
223+
}
224+
},
225+
generationLds.insert(backup.gallery),
226+
)
227+
}
228+
}

domain/src/main/java/com/shifthackz/aisdv1/domain/datasource/GenerationResultDataSource.kt

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ sealed interface GenerationResultDataSource {
88

99
interface Local : GenerationResultDataSource {
1010
fun insert(result: AiGenerationResult): Single<Long>
11+
fun insert(results: List<AiGenerationResult>): Completable
1112
fun queryAll(): Single<List<AiGenerationResult>>
1213
fun queryPage(limit: Int, offset: Int): Single<List<AiGenerationResult>>
1314
fun queryById(id: Long): Single<AiGenerationResult>

domain/src/main/java/com/shifthackz/aisdv1/domain/di/DomainModule.kt

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import com.shifthackz.aisdv1.domain.interactor.settings.SetupConnectionInterActo
44
import com.shifthackz.aisdv1.domain.interactor.settings.SetupConnectionInterActorImpl
55
import com.shifthackz.aisdv1.domain.interactor.wakelock.WakeLockInterActor
66
import com.shifthackz.aisdv1.domain.interactor.wakelock.WakeLockInterActorImpl
7+
import com.shifthackz.aisdv1.domain.usecase.backup.CreateBackupUseCase
8+
import com.shifthackz.aisdv1.domain.usecase.backup.CreateBackupUseCaseImpl
79
import com.shifthackz.aisdv1.domain.usecase.caching.ClearAppCacheUseCase
810
import com.shifthackz.aisdv1.domain.usecase.caching.ClearAppCacheUseCaseImpl
911
import com.shifthackz.aisdv1.domain.usecase.caching.DataPreLoaderUseCase
@@ -127,6 +129,7 @@ import org.koin.dsl.bind
127129
import org.koin.dsl.module
128130

129131
internal val useCasesModule = module {
132+
factoryOf(::CreateBackupUseCaseImpl) bind CreateBackupUseCase::class
130133
factoryOf(::TextToImageUseCaseImpl) bind TextToImageUseCase::class
131134
factoryOf(::ImageToImageUseCaseImpl) bind ImageToImageUseCase::class
132135
factoryOf(::PingStableDiffusionServiceUseCaseImpl) bind PingStableDiffusionServiceUseCase::class
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.shifthackz.aisdv1.domain.entity
2+
3+
import java.util.Date
4+
5+
data class Backup(
6+
val generatedAt: Date = Date(),
7+
val appVersion: String = "",
8+
val appConfiguration: Map<String, Any> = mapOf(),
9+
val gallery: List<AiGenerationResult> = emptyList(),
10+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.shifthackz.aisdv1.domain.entity
2+
3+
enum class BackupEntryToken {
4+
AppConfiguration,
5+
// AppPreferences,
6+
Gallery;
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.shifthackz.aisdv1.domain.repository
2+
3+
import com.shifthackz.aisdv1.domain.entity.BackupEntryToken
4+
import io.reactivex.rxjava3.core.Completable
5+
import io.reactivex.rxjava3.core.Single
6+
7+
interface BackupRepository {
8+
fun create(tokens: List<Pair<BackupEntryToken, Boolean>>): Single<ByteArray>
9+
fun restore(bytes: ByteArray): Completable
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.shifthackz.aisdv1.domain.usecase.backup
2+
3+
import com.shifthackz.aisdv1.domain.entity.BackupEntryToken
4+
import io.reactivex.rxjava3.core.Single
5+
6+
interface CreateBackupUseCase {
7+
operator fun invoke(tokens: List<Pair<BackupEntryToken, Boolean>>): Single<ByteArray>
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.shifthackz.aisdv1.domain.usecase.backup
2+
3+
import com.shifthackz.aisdv1.domain.entity.BackupEntryToken
4+
import com.shifthackz.aisdv1.domain.repository.BackupRepository
5+
6+
internal class CreateBackupUseCaseImpl(
7+
private val backupRepository: BackupRepository,
8+
) : CreateBackupUseCase {
9+
10+
override fun invoke(tokens: List<Pair<BackupEntryToken, Boolean>>) = backupRepository
11+
.create(tokens)
12+
}

0 commit comments

Comments
 (0)