diff --git a/core/localization/src/main/res/values-ru/strings.xml b/core/localization/src/main/res/values-ru/strings.xml
index a9dd642b..acbaa8e7 100644
--- a/core/localization/src/main/res/values-ru/strings.xml
+++ b/core/localization/src/main/res/values-ru/strings.xml
@@ -218,6 +218,7 @@
Политика конфиденциальности
Как настроить сервер
Поддержать проект
+ Просмотреть руководство
Исходный код
Подождите, коммуницируем с сервером…
@@ -353,4 +354,9 @@
I/O Поток
Вычислительный
Однопоточность
+
+ Расширенные функции\n[Stable Diffusion].
+ [Офлайн] генерация\nLocal Diffusion.
+ Настройте приложение,\nсделайте его [своим]!
+ [Свобода] выбора\nпровайедра генерации.
diff --git a/core/localization/src/main/res/values-tr/strings.xml b/core/localization/src/main/res/values-tr/strings.xml
index 815b72d9..eed6dea1 100644
--- a/core/localization/src/main/res/values-tr/strings.xml
+++ b/core/localization/src/main/res/values-tr/strings.xml
@@ -218,6 +218,7 @@
Gizlilik ve Hukuksal Politikalar
Sunucu kurulum talimatları
Bağış yapmak
+ Eğitimi görüntüle
Kaynak kodunu alın
Lütfen bekleyin, sunucu ile iletişime geçiliyor…
@@ -353,4 +354,9 @@
G/Ç İş Parçacığı
Hesaplama
Tek İş Parçacığı
+
+ Gelişmiş Özellikler\n[Kararlı Dağıtım].
+ [Çevrimdışı] nesil\nYerel Dağıtım.
+ Uygulamayı özelleştirin,\n[kendinizin] yapın!
+ Nesil sağlayıcıyı\nseçme [Özgürlüğü].
diff --git a/core/localization/src/main/res/values-uk/strings.xml b/core/localization/src/main/res/values-uk/strings.xml
index 1ff9adf6..da32118e 100644
--- a/core/localization/src/main/res/values-uk/strings.xml
+++ b/core/localization/src/main/res/values-uk/strings.xml
@@ -218,6 +218,7 @@
Політика конфіденційності
Як налаштувати сервер
Підтримати проект
+ Переглянути туторіал
Вихідний код
Зачекайте, йде коммунікація із сервером…
@@ -353,4 +354,9 @@
I/O Потік
Обчислення
Один потік
+
+ Розширені можливості\n[Stable Diffusion].
+ [Офлайн] генерація\nLocal Diffusion.
+ Налаштуйте додаток,\nзробіть його [своїм]!
+ [Свобода] вибору\nпостачальника генерації.
diff --git a/core/localization/src/main/res/values-zh/strings.xml b/core/localization/src/main/res/values-zh/strings.xml
index 2199fbcd..c3483d2e 100644
--- a/core/localization/src/main/res/values-zh/strings.xml
+++ b/core/localization/src/main/res/values-zh/strings.xml
@@ -264,6 +264,7 @@
隐私和法律政策
服务器设置说明
捐赠
+ 查看教程
获取源代码
@@ -419,4 +420,9 @@
I/O 线程
计算
单线程
+
+ 高级功能\n[稳定扩散]。
+ [离线]生成\n本地扩散。
+ 自定义应用程序,\n让它成为[您的]!
+ [自由]选择\n代提供商。
diff --git a/core/localization/src/main/res/values/strings.xml b/core/localization/src/main/res/values/strings.xml
index f455448f..cba23819 100755
--- a/core/localization/src/main/res/values/strings.xml
+++ b/core/localization/src/main/res/values/strings.xml
@@ -238,6 +238,7 @@
Privacy and legal policy
Server setup instructions
Donate
+ View tutorial
Get source code
Hang tight, communicating with server…
@@ -377,4 +378,9 @@
I/O Thread
Computation
Single Thread
+
+ Advanced [Stable Diffusion]\nAI generation features.
+ [Offline] Local Diffusion\nAI generation.
+ Configure, customize,\nmake it [yours]!
+ [Freedom] to choose your\nAI generation provider.
diff --git a/core/ui/src/main/java/com/shifthackz/aisdv1/core/extensions/GestureExtensions.kt b/core/ui/src/main/java/com/shifthackz/aisdv1/core/extensions/GestureExtensions.kt
new file mode 100644
index 00000000..277a1cff
--- /dev/null
+++ b/core/ui/src/main/java/com/shifthackz/aisdv1/core/extensions/GestureExtensions.kt
@@ -0,0 +1,22 @@
+package com.shifthackz.aisdv1.core.extensions
+
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.pointer.PointerEventPass
+import androidx.compose.ui.input.pointer.PointerInputChange
+import androidx.compose.ui.input.pointer.pointerInput
+
+fun Modifier.gesturesDisabled(disabled: Boolean = true) =
+ if (disabled) {
+ pointerInput(Unit) {
+ awaitPointerEventScope {
+ // we should wait for all new pointer events
+ while (true) {
+ awaitPointerEvent(pass = PointerEventPass.Initial)
+ .changes
+ .forEach(PointerInputChange::consume)
+ }
+ }
+ }
+ } else {
+ this
+ }
diff --git a/data/src/main/java/com/shifthackz/aisdv1/data/preference/PreferenceManagerImpl.kt b/data/src/main/java/com/shifthackz/aisdv1/data/preference/PreferenceManagerImpl.kt
index 1fffb4d4..e88fcf47 100644
--- a/data/src/main/java/com/shifthackz/aisdv1/data/preference/PreferenceManagerImpl.kt
+++ b/data/src/main/java/com/shifthackz/aisdv1/data/preference/PreferenceManagerImpl.kt
@@ -183,6 +183,12 @@ class PreferenceManagerImpl(
.apply()
.also { onPreferencesChanged() }
+ override var onBoardingComplete: Boolean
+ get() = preferences.getBoolean(KEY_ON_BOARDING_COMPLETE, false)
+ set(value) = preferences.edit()
+ .putBoolean(KEY_ON_BOARDING_COMPLETE, value)
+ .apply()
+
override var forceSetupAfterUpdate: Boolean
get() = preferences.getBoolean(KEY_FORCE_SETUP_AFTER_UPDATE, true)
set(value) = preferences.edit()
@@ -311,6 +317,7 @@ class PreferenceManagerImpl(
const val KEY_HUGGING_FACE_MODEL_KEY = "key_hugging_face_model_key"
const val KEY_STABILITY_AI_API_KEY = "key_stability_ai_api_key"
const val KEY_STABILITY_AI_ENGINE_ID_KEY = "key_stability_ai_engine_id_key"
+ const val KEY_ON_BOARDING_COMPLETE = "key_on_boarding_complete"
const val KEY_FORCE_SETUP_AFTER_UPDATE = "force_upd_setup_v0.x.x-v0.6.2"
const val KEY_LOCAL_MODEL_ID = "key_local_model_id"
const val KEY_LOCAL_NN_API = "key_local_nn_api"
diff --git a/domain/src/main/java/com/shifthackz/aisdv1/domain/preference/PreferenceManager.kt b/domain/src/main/java/com/shifthackz/aisdv1/domain/preference/PreferenceManager.kt
index 50e0cda5..1ee8950b 100644
--- a/domain/src/main/java/com/shifthackz/aisdv1/domain/preference/PreferenceManager.kt
+++ b/domain/src/main/java/com/shifthackz/aisdv1/domain/preference/PreferenceManager.kt
@@ -28,6 +28,7 @@ interface PreferenceManager {
var huggingFaceModel: String
var stabilityAiApiKey: String
var stabilityAiEngineId: String
+ var onBoardingComplete: Boolean
var forceSetupAfterUpdate: Boolean
var localModelId: String
var localUseNNAPI: Boolean
diff --git a/domain/src/main/java/com/shifthackz/aisdv1/domain/usecase/splash/SplashNavigationUseCaseImpl.kt b/domain/src/main/java/com/shifthackz/aisdv1/domain/usecase/splash/SplashNavigationUseCaseImpl.kt
index 2dbb2831..338f7a97 100644
--- a/domain/src/main/java/com/shifthackz/aisdv1/domain/usecase/splash/SplashNavigationUseCaseImpl.kt
+++ b/domain/src/main/java/com/shifthackz/aisdv1/domain/usecase/splash/SplashNavigationUseCaseImpl.kt
@@ -11,6 +11,10 @@ internal class SplashNavigationUseCaseImpl(
override fun invoke(): Single = Single.create { emitter ->
val action = when {
+ !preferenceManager.onBoardingComplete -> {
+ Action.LAUNCH_ONBOARDING
+ }
+
preferenceManager.forceSetupAfterUpdate -> {
Action.LAUNCH_SERVER_SETUP
}
diff --git a/domain/src/test/java/com/shifthackz/aisdv1/domain/usecase/splash/SplashNavigationUseCaseImplTest.kt b/domain/src/test/java/com/shifthackz/aisdv1/domain/usecase/splash/SplashNavigationUseCaseImplTest.kt
index cb76cb84..1c2b3a0d 100644
--- a/domain/src/test/java/com/shifthackz/aisdv1/domain/usecase/splash/SplashNavigationUseCaseImplTest.kt
+++ b/domain/src/test/java/com/shifthackz/aisdv1/domain/usecase/splash/SplashNavigationUseCaseImplTest.kt
@@ -12,8 +12,22 @@ class SplashNavigationUseCaseImplTest {
private val useCase = SplashNavigationUseCaseImpl(stubPreferenceManager)
+ @Test
+ fun `given onBoardingComplete is false, expected LAUNCH_ONBOARDING`() {
+ whenever(stubPreferenceManager.onBoardingComplete)
+ .thenReturn(false)
+
+ useCase()
+ .test()
+ .assertNoErrors()
+ .assertValue(SplashNavigationUseCase.Action.LAUNCH_ONBOARDING)
+ }
+
@Test
fun `given forceSetupAfterUpdate is true, expected LAUNCH_SERVER_SETUP`() {
+ whenever(stubPreferenceManager.onBoardingComplete)
+ .thenReturn(true)
+
whenever(stubPreferenceManager.forceSetupAfterUpdate)
.thenReturn(true)
@@ -25,6 +39,9 @@ class SplashNavigationUseCaseImplTest {
@Test
fun `given source is AUTOMATIC1111 and server url empty, expected LAUNCH_SERVER_SETUP`() {
+ whenever(stubPreferenceManager.onBoardingComplete)
+ .thenReturn(true)
+
whenever(stubPreferenceManager.forceSetupAfterUpdate)
.thenReturn(false)
@@ -42,6 +59,9 @@ class SplashNavigationUseCaseImplTest {
@Test
fun `given source is AUTOMATIC1111 and server url not empty, expected LAUNCH_HOME`() {
+ whenever(stubPreferenceManager.onBoardingComplete)
+ .thenReturn(true)
+
whenever(stubPreferenceManager.forceSetupAfterUpdate)
.thenReturn(false)
@@ -59,6 +79,9 @@ class SplashNavigationUseCaseImplTest {
@Test
fun `given source is LOCAL, and server url is empty, expected LAUNCH_HOME`() {
+ whenever(stubPreferenceManager.onBoardingComplete)
+ .thenReturn(true)
+
whenever(stubPreferenceManager.forceSetupAfterUpdate)
.thenReturn(false)
@@ -76,6 +99,9 @@ class SplashNavigationUseCaseImplTest {
@Test
fun `given source is LOCAL, and server url is not empty, expected LAUNCH_HOME`() {
+ whenever(stubPreferenceManager.onBoardingComplete)
+ .thenReturn(true)
+
whenever(stubPreferenceManager.forceSetupAfterUpdate)
.thenReturn(false)
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/core/GenerationMviState.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/core/GenerationMviState.kt
index e1fbb7d5..7e8f7130 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/core/GenerationMviState.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/core/GenerationMviState.kt
@@ -12,6 +12,7 @@ import com.shifthackz.aisdv1.presentation.model.Modal
import com.shifthackz.android.core.mvi.MviState
abstract class GenerationMviState : MviState {
+ abstract val onBoardingDemo: Boolean
abstract val screenModal: Modal
abstract val mode: ServerSource
abstract val advancedToggleButtonVisible: Boolean
@@ -55,6 +56,7 @@ abstract class GenerationMviState : MviState {
get() = widthValidationError != null || heightValidationError != null
open fun copyState(
+ onBoardingDemo: Boolean = this.onBoardingDemo,
screenModal: Modal = this.screenModal,
mode: ServerSource = this.mode,
advancedToggleButtonVisible: Boolean = this.advancedToggleButtonVisible,
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/core/GenerationMviViewModel.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/core/GenerationMviViewModel.kt
index cea05b90..714f0ef9 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/core/GenerationMviViewModel.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/core/GenerationMviViewModel.kt
@@ -22,11 +22,11 @@ import com.shifthackz.aisdv1.domain.usecase.generation.ObserveHordeProcessStatus
import com.shifthackz.aisdv1.domain.usecase.generation.ObserveLocalDiffusionProcessStatusUseCase
import com.shifthackz.aisdv1.domain.usecase.generation.SaveGenerationResultUseCase
import com.shifthackz.aisdv1.domain.usecase.sdsampler.GetStableDiffusionSamplersUseCase
+import com.shifthackz.aisdv1.presentation.model.LaunchSource
import com.shifthackz.aisdv1.presentation.model.Modal
import com.shifthackz.aisdv1.presentation.navigation.router.drawer.DrawerRouter
import com.shifthackz.aisdv1.presentation.navigation.router.main.MainRouter
import com.shifthackz.aisdv1.presentation.screen.drawer.DrawerIntent
-import com.shifthackz.aisdv1.presentation.screen.setup.ServerSetupLaunchSource
import com.shifthackz.aisdv1.presentation.screen.txt2img.mapToUi
import com.shifthackz.android.core.mvi.MviEffect
import io.reactivex.rxjava3.core.Observable
@@ -262,7 +262,7 @@ abstract class GenerationMviViewModel mainRouter.navigateToServerSetup(
- ServerSetupLaunchSource.SETTINGS,
+ LaunchSource.SETTINGS,
)
is GenerationMviIntent.UpdateFromGeneration -> {
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/di/ViewModelModule.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/di/ViewModelModule.kt
index a22190ec..23e5a154 100755
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/di/ViewModelModule.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/di/ViewModelModule.kt
@@ -5,6 +5,7 @@ import com.shifthackz.aisdv1.presentation.modal.embedding.EmbeddingViewModel
import com.shifthackz.aisdv1.presentation.modal.extras.ExtrasViewModel
import com.shifthackz.aisdv1.presentation.modal.history.InputHistoryViewModel
import com.shifthackz.aisdv1.presentation.modal.tag.EditTagViewModel
+import com.shifthackz.aisdv1.presentation.model.LaunchSource
import com.shifthackz.aisdv1.presentation.screen.debug.DebugMenuViewModel
import com.shifthackz.aisdv1.presentation.screen.donate.DonateViewModel
import com.shifthackz.aisdv1.presentation.screen.drawer.DrawerViewModel
@@ -15,8 +16,8 @@ import com.shifthackz.aisdv1.presentation.screen.img2img.ImageToImageViewModel
import com.shifthackz.aisdv1.presentation.screen.inpaint.InPaintViewModel
import com.shifthackz.aisdv1.presentation.screen.loader.ConfigurationLoaderViewModel
import com.shifthackz.aisdv1.presentation.screen.logger.LoggerViewModel
+import com.shifthackz.aisdv1.presentation.screen.onboarding.OnBoardingViewModel
import com.shifthackz.aisdv1.presentation.screen.settings.SettingsViewModel
-import com.shifthackz.aisdv1.presentation.screen.setup.ServerSetupLaunchSource
import com.shifthackz.aisdv1.presentation.screen.setup.ServerSetupViewModel
import com.shifthackz.aisdv1.presentation.screen.splash.SplashViewModel
import com.shifthackz.aisdv1.presentation.screen.txt2img.TextToImageViewModel
@@ -54,7 +55,17 @@ val viewModelModule = module {
viewModelOf(::LoggerViewModel)
viewModel { parameters ->
- val launchSource = ServerSetupLaunchSource.fromKey(parameters.get())
+ OnBoardingViewModel(
+ launchSource = LaunchSource.fromKey(parameters.get()),
+ mainRouter = get(),
+ splashNavigationUseCase = get(),
+ preferenceManager = get(),
+ schedulersProvider = get(),
+ )
+ }
+
+ viewModel { parameters ->
+ val launchSource = LaunchSource.fromKey(parameters.get())
ServerSetupViewModel(
launchSource = launchSource,
getConfigurationUseCase = get(),
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/model/LaunchSource.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/model/LaunchSource.kt
new file mode 100644
index 00000000..14fb1545
--- /dev/null
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/model/LaunchSource.kt
@@ -0,0 +1,10 @@
+package com.shifthackz.aisdv1.presentation.model
+
+enum class LaunchSource {
+ SPLASH,
+ SETTINGS;
+
+ companion object {
+ fun fromKey(key: Int) = entries.firstOrNull { it.ordinal == key } ?: SPLASH
+ }
+}
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/navigation/graph/DrawerNavGraph.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/navigation/graph/DrawerNavGraph.kt
index b5f0bfbe..5146f51d 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/navigation/graph/DrawerNavGraph.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/navigation/graph/DrawerNavGraph.kt
@@ -9,8 +9,8 @@ import com.shifthackz.aisdv1.core.model.asUiText
import com.shifthackz.aisdv1.domain.entity.FeatureTag
import com.shifthackz.aisdv1.domain.entity.ServerSource
import com.shifthackz.aisdv1.domain.entity.Settings
+import com.shifthackz.aisdv1.presentation.model.LaunchSource
import com.shifthackz.aisdv1.presentation.model.NavItem
-import com.shifthackz.aisdv1.presentation.screen.setup.ServerSetupLaunchSource
import com.shifthackz.aisdv1.presentation.utils.Constants
import com.shifthackz.aisdv1.presentation.widget.source.getNameUiText
import com.shifthackz.aisdv1.core.localization.R as LocalizationR
@@ -44,7 +44,7 @@ private fun webUi(source: ServerSource) = NavItem(
private fun configuration() = NavItem(
name = LocalizationR.string.settings_item_config.asUiText(),
- route = "${Constants.ROUTE_SERVER_SETUP}/${ServerSetupLaunchSource.SETTINGS.ordinal}",
+ route = "${Constants.ROUTE_SERVER_SETUP}/${LaunchSource.SETTINGS.ordinal}",
icon = NavItem.Icon.Vector(
vector = Icons.Default.SettingsEthernet,
),
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/navigation/graph/MainNavGraph.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/navigation/graph/MainNavGraph.kt
index ad5a352d..1c04b2a3 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/navigation/graph/MainNavGraph.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/navigation/graph/MainNavGraph.kt
@@ -5,13 +5,15 @@ import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavType
import androidx.navigation.compose.ComposeNavigator
import androidx.navigation.get
+import com.shifthackz.aisdv1.presentation.model.LaunchSource
import com.shifthackz.aisdv1.presentation.screen.debug.DebugMenuScreen
import com.shifthackz.aisdv1.presentation.screen.donate.DonateScreen
import com.shifthackz.aisdv1.presentation.screen.gallery.detail.GalleryDetailScreen
import com.shifthackz.aisdv1.presentation.screen.inpaint.InPaintScreen
import com.shifthackz.aisdv1.presentation.screen.loader.ConfigurationLoaderScreen
import com.shifthackz.aisdv1.presentation.screen.logger.LoggerScreen
-import com.shifthackz.aisdv1.presentation.screen.setup.ServerSetupLaunchSource
+import com.shifthackz.aisdv1.presentation.screen.onboarding.OnBoardingScreen
+import com.shifthackz.aisdv1.presentation.screen.onboarding.OnBoardingViewModel
import com.shifthackz.aisdv1.presentation.screen.setup.ServerSetupScreen
import com.shifthackz.aisdv1.presentation.screen.setup.ServerSetupViewModel
import com.shifthackz.aisdv1.presentation.screen.splash.SplashScreen
@@ -33,7 +35,7 @@ fun NavGraphBuilder.mainNavGraph() {
ComposeNavigator.Destination(provider[ComposeNavigator::class]) { entry ->
val sourceKey = entry.arguments
?.getInt(Constants.PARAM_SOURCE)
- ?: ServerSetupLaunchSource.SPLASH.ordinal
+ ?: LaunchSource.SPLASH.ordinal
ServerSetupScreen(
viewModel = getViewModel(
parameters = { parametersOf(sourceKey) }
@@ -103,4 +105,22 @@ fun NavGraphBuilder.mainNavGraph() {
route = Constants.ROUTE_DONATE
}
)
+ addDestination(
+ ComposeNavigator.Destination(provider[ComposeNavigator::class]) { entry ->
+ val sourceKey = entry.arguments
+ ?.getInt(Constants.PARAM_SOURCE)
+ ?: LaunchSource.SPLASH.ordinal
+ OnBoardingScreen(
+ viewModel = getViewModel(
+ parameters = { parametersOf(sourceKey) }
+ ),
+ )
+ }.apply {
+ route = Constants.ROUTE_ONBOARDING_FULL
+ addArgument(
+ Constants.PARAM_SOURCE,
+ NavArgument.Builder().setType(NavType.IntType).build(),
+ )
+ }
+ )
}
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/navigation/router/main/MainRouter.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/navigation/router/main/MainRouter.kt
index 7f64a566..b45a025c 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/navigation/router/main/MainRouter.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/navigation/router/main/MainRouter.kt
@@ -1,18 +1,20 @@
package com.shifthackz.aisdv1.presentation.navigation.router.main
+import com.shifthackz.aisdv1.presentation.model.LaunchSource
import com.shifthackz.aisdv1.presentation.navigation.NavigationEffect
import com.shifthackz.aisdv1.presentation.navigation.router.Router
-import com.shifthackz.aisdv1.presentation.screen.setup.ServerSetupLaunchSource
interface MainRouter : Router {
fun navigateBack()
+ fun navigateToOnBoarding(source: LaunchSource)
+
fun navigateToPostSplashConfigLoader()
fun navigateToHomeScreen()
- fun navigateToServerSetup(source: ServerSetupLaunchSource)
+ fun navigateToServerSetup(source: LaunchSource)
fun navigateToGalleryDetails(itemId: Long)
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/navigation/router/main/MainRouterExtensions.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/navigation/router/main/MainRouterExtensions.kt
new file mode 100644
index 00000000..ed0df2b9
--- /dev/null
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/navigation/router/main/MainRouterExtensions.kt
@@ -0,0 +1,18 @@
+package com.shifthackz.aisdv1.presentation.navigation.router.main
+
+import com.shifthackz.aisdv1.domain.usecase.splash.SplashNavigationUseCase
+import com.shifthackz.aisdv1.presentation.model.LaunchSource
+
+fun MainRouter.postSplashNavigation(
+ action: SplashNavigationUseCase.Action,
+) {
+ when (action) {
+ SplashNavigationUseCase.Action.LAUNCH_ONBOARDING -> navigateToOnBoarding(
+ source = LaunchSource.SPLASH,
+ )
+ SplashNavigationUseCase.Action.LAUNCH_SERVER_SETUP -> navigateToServerSetup(
+ source = LaunchSource.SPLASH,
+ )
+ SplashNavigationUseCase.Action.LAUNCH_HOME -> navigateToPostSplashConfigLoader()
+ }
+}
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/navigation/router/main/MainRouterImpl.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/navigation/router/main/MainRouterImpl.kt
index 24a8c52c..df0b16af 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/navigation/router/main/MainRouterImpl.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/navigation/router/main/MainRouterImpl.kt
@@ -1,15 +1,12 @@
package com.shifthackz.aisdv1.presentation.navigation.router.main
+import com.shifthackz.aisdv1.presentation.model.LaunchSource
import com.shifthackz.aisdv1.presentation.navigation.NavigationEffect
-import com.shifthackz.aisdv1.presentation.screen.debug.DebugMenuAccessor
-import com.shifthackz.aisdv1.presentation.screen.setup.ServerSetupLaunchSource
import com.shifthackz.aisdv1.presentation.utils.Constants
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.subjects.PublishSubject
-internal class MainRouterImpl(
- private val debugMenuAccessor: DebugMenuAccessor,
-) : MainRouter {
+internal class MainRouterImpl : MainRouter {
private val effectSubject: PublishSubject = PublishSubject.create()
@@ -21,6 +18,16 @@ internal class MainRouterImpl(
effectSubject.onNext(NavigationEffect.Back)
}
+ override fun navigateToOnBoarding(source: LaunchSource) {
+ effectSubject.onNext(NavigationEffect.Navigate.RouteBuilder("${Constants.ROUTE_ONBOARDING}/${source.ordinal}") {
+ if (source == LaunchSource.SPLASH) {
+ popUpTo(Constants.ROUTE_SPLASH) {
+ inclusive = true
+ }
+ }
+ })
+ }
+
override fun navigateToPostSplashConfigLoader() {
effectSubject.onNext(NavigationEffect.Navigate.RouteBuilder(Constants.ROUTE_CONFIG_LOADER) {
popUpTo(Constants.ROUTE_SPLASH) {
@@ -30,13 +37,17 @@ internal class MainRouterImpl(
}
override fun navigateToHomeScreen() {
- effectSubject.onNext(NavigationEffect.Navigate.RoutePopUp(Constants.ROUTE_HOME))
+ effectSubject.onNext(NavigationEffect.Navigate.RouteBuilder(Constants.ROUTE_HOME) {
+ popUpTo(0) {
+ inclusive = true
+ }
+ })
}
- override fun navigateToServerSetup(source: ServerSetupLaunchSource) {
+ override fun navigateToServerSetup(source: LaunchSource) {
effectSubject.onNext(NavigationEffect.Navigate.RouteBuilder("${Constants.ROUTE_SERVER_SETUP}/${source.ordinal}") {
- if (source == ServerSetupLaunchSource.SPLASH) {
- popUpTo(Constants.ROUTE_SPLASH) {
+ if (source == LaunchSource.SPLASH) {
+ popUpTo(Constants.ROUTE_ONBOARDING) {
inclusive = true
}
}
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/gallery/list/GalleryScreen.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/gallery/list/GalleryScreen.kt
index 8d36fb3d..a6052000 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/gallery/list/GalleryScreen.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/gallery/list/GalleryScreen.kt
@@ -131,7 +131,7 @@ fun GalleryScreen() {
BackHandler(state.selectionMode) {
intentHandler(GalleryIntent.ChangeSelectionMode(false))
}
- ScreenContent(
+ GalleryScreenContent(
state = state,
lazyGalleryItems = lazyGalleryItems,
processIntent = intentHandler,
@@ -140,7 +140,7 @@ fun GalleryScreen() {
}
@Composable
-private fun ScreenContent(
+fun GalleryScreenContent(
modifier: Modifier = Modifier,
state: GalleryState,
lazyGalleryItems: LazyPagingItems,
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/img2img/ImageToImageState.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/img2img/ImageToImageState.kt
index 4732517e..533b7b9b 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/img2img/ImageToImageState.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/img2img/ImageToImageState.kt
@@ -21,6 +21,7 @@ data class ImageToImageState(
val imageBase64: String = "",
val denoisingStrength: Float = 0.75f,
val inPaintModel: InPaintModel = InPaintModel(),
+ override val onBoardingDemo: Boolean = false,
override val screenModal: Modal = Modal.None,
override val mode: ServerSource = ServerSource.AUTOMATIC1111,
override val advancedToggleButtonVisible: Boolean = true,
@@ -61,6 +62,7 @@ data class ImageToImageState(
}
override fun copyState(
+ onBoardingDemo: Boolean,
screenModal: Modal,
mode: ServerSource,
advancedToggleButtonVisible: Boolean,
@@ -90,6 +92,7 @@ data class ImageToImageState(
batchCount: Int,
generateButtonEnabled: Boolean
): GenerationMviState = copy(
+ onBoardingDemo = onBoardingDemo,
screenModal = screenModal,
mode = mode,
advancedToggleButtonVisible = advancedToggleButtonVisible,
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingDensity.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingDensity.kt
new file mode 100644
index 00000000..9ee89f1e
--- /dev/null
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingDensity.kt
@@ -0,0 +1,10 @@
+package com.shifthackz.aisdv1.presentation.screen.onboarding
+
+import androidx.compose.animation.core.FastOutSlowInEasing
+import androidx.compose.animation.core.tween
+import androidx.compose.ui.unit.Density
+
+val onBoardingDensity = Density(2f, 1f)
+val onBoardingPhoneWidthFraction = 0.76f
+val onBoardingPhoneAspectRatio = 9.5f / 16f
+val onBoardingPageAnimation = tween(1200, easing = FastOutSlowInEasing)
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingIntent.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingIntent.kt
new file mode 100644
index 00000000..f91f592c
--- /dev/null
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingIntent.kt
@@ -0,0 +1,7 @@
+package com.shifthackz.aisdv1.presentation.screen.onboarding
+
+import com.shifthackz.android.core.mvi.MviIntent
+
+sealed interface OnBoardingIntent : MviIntent {
+ data object Navigate : OnBoardingIntent
+}
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingPage.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingPage.kt
new file mode 100644
index 00000000..560da13e
--- /dev/null
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingPage.kt
@@ -0,0 +1,9 @@
+package com.shifthackz.aisdv1.presentation.screen.onboarding
+
+
+enum class OnBoardingPage {
+ Providers,
+ Form,
+ LocalDiffusion,
+ LookAndFeel,
+}
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingScreen.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingScreen.kt
new file mode 100644
index 00000000..708a7bbc
--- /dev/null
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingScreen.kt
@@ -0,0 +1,210 @@
+@file:OptIn(ExperimentalFoundationApi::class)
+
+package com.shifthackz.aisdv1.presentation.screen.onboarding
+
+import androidx.activity.compose.BackHandler
+import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+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.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.pager.HorizontalPager
+import androidx.compose.foundation.pager.rememberPagerState
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Check
+import androidx.compose.material.icons.filled.DoubleArrow
+import androidx.compose.material3.Button
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.OutlinedButton
+import androidx.compose.material3.Scaffold
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.draw.rotate
+import androidx.compose.ui.unit.dp
+import com.shifthackz.aisdv1.core.ui.MviComponent
+import com.shifthackz.aisdv1.presentation.model.LaunchSource
+import com.shifthackz.aisdv1.presentation.screen.onboarding.page.FormPageContent
+import com.shifthackz.aisdv1.presentation.screen.onboarding.page.LocalDiffusionPageContent
+import com.shifthackz.aisdv1.presentation.screen.onboarding.page.LookAndFeelPageContent
+import com.shifthackz.aisdv1.presentation.screen.onboarding.page.ProviderPageContent
+import kotlinx.coroutines.launch
+
+@Composable
+fun OnBoardingScreen(
+ viewModel: OnBoardingViewModel,
+) {
+ MviComponent(
+ viewModel = viewModel,
+ navigationBarColor = MaterialTheme.colorScheme.surface,
+ applySystemUiColors = true,
+ ) { state, processIntent ->
+ OnBoardingScreenContent(
+ launchSource = viewModel.launchSource,
+ state = state,
+ processIntent = processIntent,
+ )
+ }
+}
+
+@Composable
+private fun OnBoardingScreenContent(
+ launchSource: LaunchSource,
+ state: OnBoardingState,
+ processIntent: (OnBoardingIntent) -> Unit = {},
+) {
+ val scope = rememberCoroutineScope()
+ val pagerState = rememberPagerState(
+ initialPage = OnBoardingPage.entries.first().ordinal,
+ pageCount = { OnBoardingPage.entries.size },
+ )
+ BackHandler(pagerState.currentPage > 0) {
+ scope.launch {
+ pagerState.animateScrollToPage(
+ page = pagerState.currentPage - 1,
+ animationSpec = onBoardingPageAnimation,
+ )
+ }
+ }
+ Scaffold(
+ modifier = Modifier.fillMaxSize(),
+ bottomBar = {
+ val shape = RoundedCornerShape(
+ topStart = 24.dp,
+ topEnd = 24.dp,
+ )
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .clip(shape),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth(onBoardingPhoneWidthFraction)
+ .padding(bottom = 32.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ val backAlpha by animateFloatAsState(
+ targetValue = if (pagerState.currentPage > 0 || launchSource == LaunchSource.SETTINGS) {
+ 1f
+ } else {
+ 0f
+ },
+ label = "back_button_animation",
+ )
+ OutlinedButton(
+ modifier = Modifier
+ .alpha(backAlpha)
+ .size(56.dp),
+ shape = RoundedCornerShape(12.dp),
+ contentPadding = PaddingValues(0.dp),
+ onClick = {
+ if (pagerState.currentPage > 0) {
+ scope.launch {
+ pagerState.animateScrollToPage(
+ page = pagerState.currentPage - 1,
+ animationSpec = onBoardingPageAnimation,
+ )
+ }
+ } else if (pagerState.currentPage == 0 && launchSource == LaunchSource.SETTINGS) {
+ processIntent(OnBoardingIntent.Navigate)
+ }
+ },
+ ) {
+ Icon(
+ modifier = Modifier.rotate(180f),
+ imageVector = Icons.Default.DoubleArrow,
+ contentDescription = "Next",
+ )
+ }
+ Spacer(modifier = Modifier.weight(1f))
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(4.dp)
+ ) {
+ repeat(OnBoardingPage.entries.size) { index ->
+ val color = if (index == pagerState.currentPage) {
+ MaterialTheme.colorScheme.primary
+ } else {
+ MaterialTheme.colorScheme.primary.copy(alpha = 0.25f)
+ }
+ Box(
+ modifier = Modifier
+ .size(8.dp)
+ .background(color, CircleShape)
+ )
+ }
+ }
+ Spacer(modifier = Modifier.weight(1f))
+ Button(
+ modifier = Modifier.size(56.dp),
+ shape = RoundedCornerShape(12.dp),
+ contentPadding = PaddingValues(0.dp),
+ onClick = {
+ if (pagerState.currentPage == OnBoardingPage.entries.size - 1) {
+ processIntent(OnBoardingIntent.Navigate)
+ } else {
+ scope.launch {
+ pagerState.animateScrollToPage(
+ page = pagerState.currentPage + 1,
+ animationSpec = onBoardingPageAnimation,
+ )
+ }
+ }
+ },
+ ) {
+ val icon =
+ if (pagerState.currentPage == OnBoardingPage.entries.last().ordinal) {
+ Icons.Default.Check
+ } else {
+ Icons.Default.DoubleArrow
+ }
+ Icon(
+ imageVector = icon,
+ contentDescription = "Next",
+ )
+ }
+ }
+ }
+ },
+ containerColor = MaterialTheme.colorScheme.surface,
+ ) { paddingValues ->
+ Column(
+ modifier = Modifier
+ .padding(paddingValues)
+ .fillMaxSize(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ HorizontalPager(
+ modifier = Modifier.fillMaxSize(),
+ state = pagerState,
+ beyondBoundsPageCount = OnBoardingPage.entries.size,
+ userScrollEnabled = false,
+ ) { index ->
+ when (OnBoardingPage.entries[index]) {
+ OnBoardingPage.Form -> FormPageContent()
+ OnBoardingPage.Providers -> ProviderPageContent()
+ OnBoardingPage.LocalDiffusion -> LocalDiffusionPageContent()
+ OnBoardingPage.LookAndFeel -> LookAndFeelPageContent(
+ darkThemeToken = state.darkThemeToken,
+ )
+ }
+ }
+ }
+ }
+}
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingState.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingState.kt
new file mode 100644
index 00000000..812a4082
--- /dev/null
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingState.kt
@@ -0,0 +1,8 @@
+package com.shifthackz.aisdv1.presentation.screen.onboarding
+
+import com.shifthackz.aisdv1.domain.entity.DarkThemeToken
+import com.shifthackz.android.core.mvi.MviState
+
+data class OnBoardingState(
+ val darkThemeToken: DarkThemeToken = DarkThemeToken.FRAPPE,
+) : MviState
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingText.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingText.kt
new file mode 100644
index 00000000..a40aed1e
--- /dev/null
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingText.kt
@@ -0,0 +1,47 @@
+package com.shifthackz.aisdv1.presentation.screen.onboarding
+
+import androidx.annotation.StringRes
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.SpanStyle
+import androidx.compose.ui.text.buildAnnotatedString
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.withStyle
+
+private const val CHAR_BOLD_START = '['
+private const val CHAR_BOLD_END = ']'
+
+@Composable
+fun buildOnBoardingText(@StringRes resId: Int): AnnotatedString = buildAnnotatedString {
+ val list = mutableListOf>()
+ val fullString = stringResource(id = resId)
+ var currentSequence = ""
+ var currentFontWeight = FontWeight.Light
+ for (index in fullString.indices) {
+ val char = fullString[index]
+ fun add() {
+ list.add(currentSequence to currentFontWeight)
+ currentSequence = ""
+ }
+ if (char == CHAR_BOLD_START) {
+ add()
+ currentFontWeight = FontWeight.Bold
+ } else if (char == CHAR_BOLD_END) {
+ add()
+ currentFontWeight = FontWeight.Light
+ } else if (index == fullString.length - 1) {
+ currentSequence += char
+ add()
+ }
+ if (char == CHAR_BOLD_START || char == CHAR_BOLD_END) {
+ continue
+ }
+ currentSequence += char
+ }
+ list.forEach {
+ withStyle(style = SpanStyle(fontWeight = it.second)) {
+ append(it.first)
+ }
+ }
+}
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingViewModel.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingViewModel.kt
new file mode 100644
index 00000000..8a2f057e
--- /dev/null
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingViewModel.kt
@@ -0,0 +1,49 @@
+package com.shifthackz.aisdv1.presentation.screen.onboarding
+
+import com.shifthackz.aisdv1.core.common.log.errorLog
+import com.shifthackz.aisdv1.core.common.schedulers.SchedulersProvider
+import com.shifthackz.aisdv1.core.common.schedulers.subscribeOnMainThread
+import com.shifthackz.aisdv1.core.viewmodel.MviRxViewModel
+import com.shifthackz.aisdv1.domain.entity.DarkThemeToken
+import com.shifthackz.aisdv1.domain.preference.PreferenceManager
+import com.shifthackz.aisdv1.domain.usecase.splash.SplashNavigationUseCase
+import com.shifthackz.aisdv1.presentation.model.LaunchSource
+import com.shifthackz.aisdv1.presentation.navigation.router.main.MainRouter
+import com.shifthackz.aisdv1.presentation.navigation.router.main.postSplashNavigation
+import com.shifthackz.android.core.mvi.EmptyEffect
+import io.reactivex.rxjava3.kotlin.subscribeBy
+
+class OnBoardingViewModel(
+ val launchSource: LaunchSource,
+ private val mainRouter: MainRouter,
+ private val splashNavigationUseCase: SplashNavigationUseCase,
+ private val preferenceManager: PreferenceManager,
+ private val schedulersProvider: SchedulersProvider,
+) : MviRxViewModel() {
+
+ override val initialState = OnBoardingState()
+
+ init {
+ updateState {
+ val token = DarkThemeToken.parse(preferenceManager.designDarkThemeToken)
+ it.copy(darkThemeToken = token)
+ }
+ }
+
+ override fun processIntent(intent: OnBoardingIntent) {
+ when (intent) {
+ OnBoardingIntent.Navigate -> {
+ preferenceManager.onBoardingComplete = true
+ when (launchSource) {
+ LaunchSource.SPLASH -> !splashNavigationUseCase()
+ .subscribeOnMainThread(schedulersProvider)
+ .subscribeBy(::errorLog) { action ->
+ mainRouter.postSplashNavigation(action)
+ }
+
+ LaunchSource.SETTINGS -> mainRouter.navigateBack()
+ }
+ }
+ }
+ }
+}
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/page/FormPageContent.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/page/FormPageContent.kt
new file mode 100644
index 00000000..a24cfebd
--- /dev/null
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/page/FormPageContent.kt
@@ -0,0 +1,65 @@
+package com.shifthackz.aisdv1.presentation.screen.onboarding.page
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.aspectRatio
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.sp
+import com.shifthackz.aisdv1.core.extensions.gesturesDisabled
+import com.shifthackz.aisdv1.presentation.screen.onboarding.buildOnBoardingText
+import com.shifthackz.aisdv1.presentation.screen.onboarding.onBoardingDensity
+import com.shifthackz.aisdv1.presentation.screen.onboarding.onBoardingPhoneAspectRatio
+import com.shifthackz.aisdv1.presentation.screen.onboarding.onBoardingPhoneWidthFraction
+import com.shifthackz.aisdv1.presentation.screen.txt2img.TextToImageScreenContent
+import com.shifthackz.aisdv1.presentation.screen.txt2img.TextToImageState
+import com.shifthackz.aisdv1.presentation.widget.frame.PhoneFrame
+import com.shifthackz.aisdv1.core.localization.R as LocalizationR
+
+@Composable
+fun FormPageContent(
+ modifier: Modifier = Modifier,
+) = Column(
+ modifier = modifier.fillMaxSize(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+) {
+ Spacer(modifier = Modifier.weight(1f))
+ Text(
+ text = buildOnBoardingText(LocalizationR.string.on_boarding_page_form_title),
+ fontSize = 24.sp,
+ textAlign = TextAlign.Center,
+ )
+ Spacer(modifier = Modifier.weight(1f))
+ PhoneFrame(
+ modifier = Modifier.fillMaxWidth(onBoardingPhoneWidthFraction),
+ ) {
+ CompositionLocalProvider(LocalDensity provides onBoardingDensity) {
+ TextToImageScreenContent(
+ modifier = Modifier
+ .gesturesDisabled()
+ .aspectRatio(onBoardingPhoneAspectRatio),
+ state = TextToImageState(
+ onBoardingDemo = true,
+ advancedToggleButtonVisible = false,
+ advancedOptionsVisible = true,
+ formPromptTaggedInput = true,
+ prompt = "man, photorealistic, black hair, aviator glasses, handsome, beautiful, nature background, , ",
+ negativePrompt = "bad anatomy, bad fingers, distorted, jpeg artifacts",
+ selectedSampler = "DPM++ 2M",
+ availableSamplers = listOf("DPM++ 2M"),
+ seed = "050598",
+ subSeed = "151297",
+ subSeedStrength = 0.69f,
+ ),
+ )
+ }
+ }
+ Spacer(modifier = Modifier.weight(1f))
+}
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/page/LocalDiffusionPageContent.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/page/LocalDiffusionPageContent.kt
new file mode 100644
index 00000000..9893fe8f
--- /dev/null
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/page/LocalDiffusionPageContent.kt
@@ -0,0 +1,90 @@
+package com.shifthackz.aisdv1.presentation.screen.onboarding.page
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.aspectRatio
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.sp
+import com.shifthackz.aisdv1.core.extensions.gesturesDisabled
+import com.shifthackz.aisdv1.domain.entity.ServerSource
+import com.shifthackz.aisdv1.presentation.screen.onboarding.buildOnBoardingText
+import com.shifthackz.aisdv1.presentation.screen.onboarding.onBoardingDensity
+import com.shifthackz.aisdv1.presentation.screen.onboarding.onBoardingPhoneAspectRatio
+import com.shifthackz.aisdv1.presentation.screen.onboarding.onBoardingPhoneWidthFraction
+import com.shifthackz.aisdv1.presentation.screen.txt2img.TextToImageScreenContent
+import com.shifthackz.aisdv1.presentation.screen.txt2img.TextToImageState
+import com.shifthackz.aisdv1.presentation.widget.dialog.GeneratingProgressDialogContent
+import com.shifthackz.aisdv1.presentation.widget.frame.PhoneFrame
+import com.shifthackz.aisdv1.core.localization.R as LocalizationR
+
+@Composable
+fun LocalDiffusionPageContent(
+ modifier: Modifier = Modifier,
+) = Column(
+ modifier = modifier.fillMaxSize(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+) {
+ Spacer(modifier = Modifier.weight(1f))
+ Text(
+ text = buildOnBoardingText(LocalizationR.string.on_boarding_page_local_title),
+ fontSize = 24.sp,
+ textAlign = TextAlign.Center,
+ fontWeight = FontWeight(450),
+ )
+ Spacer(modifier = Modifier.weight(1f))
+ PhoneFrame(
+ modifier = Modifier.fillMaxWidth(onBoardingPhoneWidthFraction),
+ ) {
+ CompositionLocalProvider(LocalDensity provides onBoardingDensity) {
+ val localModifier = Modifier
+ .gesturesDisabled()
+ .aspectRatio(onBoardingPhoneAspectRatio)
+ Box(
+ contentAlignment = Alignment.Center,
+ ) {
+ TextToImageScreenContent(
+ modifier = localModifier,
+ state = TextToImageState(
+ onBoardingDemo = true,
+ mode = ServerSource.LOCAL,
+ advancedToggleButtonVisible = false,
+ advancedOptionsVisible = true,
+ formPromptTaggedInput = true,
+ prompt = "man, photorealistic, black hair, aviator glasses, handsome, beautiful, nature background, , ",
+ negativePrompt = "bad anatomy, bad fingers, distorted, jpeg artifacts",
+ seed = "050598",
+ ),
+ )
+ Box(
+ modifier = localModifier
+ .fillMaxWidth()
+ .background(Color.Black.copy(alpha = 0.7f)),
+ contentAlignment = Alignment.Center,
+ ) {
+ Box(
+ modifier = Modifier.fillMaxWidth(0.85f),
+ contentAlignment = Alignment.Center,
+ ) {
+ GeneratingProgressDialogContent(
+ titleResId = LocalizationR.string.communicating_local_title,
+ step = 3 to 20,
+ )
+ }
+ }
+ }
+ }
+ }
+ Spacer(modifier = Modifier.weight(1f))
+}
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/page/LookAndFeelPageContent.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/page/LookAndFeelPageContent.kt
new file mode 100644
index 00000000..c7f570e1
--- /dev/null
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/page/LookAndFeelPageContent.kt
@@ -0,0 +1,102 @@
+package com.shifthackz.aisdv1.presentation.screen.onboarding.page
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.aspectRatio
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.sp
+import com.shifthackz.aisdv1.core.extensions.gesturesDisabled
+import com.shifthackz.aisdv1.domain.entity.ColorToken
+import com.shifthackz.aisdv1.domain.entity.DarkThemeToken
+import com.shifthackz.aisdv1.presentation.screen.onboarding.buildOnBoardingText
+import com.shifthackz.aisdv1.presentation.screen.onboarding.onBoardingDensity
+import com.shifthackz.aisdv1.presentation.screen.onboarding.onBoardingPhoneAspectRatio
+import com.shifthackz.aisdv1.presentation.screen.onboarding.onBoardingPhoneWidthFraction
+import com.shifthackz.aisdv1.presentation.screen.settings.SettingsScreenContent
+import com.shifthackz.aisdv1.presentation.screen.settings.SettingsState
+import com.shifthackz.aisdv1.presentation.theme.global.AiSdAppTheme
+import com.shifthackz.aisdv1.presentation.theme.global.AiSdAppThemeState
+import com.shifthackz.aisdv1.presentation.theme.isSdAppInDarkTheme
+import com.shifthackz.aisdv1.presentation.widget.frame.PhoneFrame
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import com.shifthackz.aisdv1.core.localization.R as LocalizationR
+
+@Composable
+fun LookAndFeelPageContent(
+ modifier: Modifier = Modifier,
+ darkThemeToken: DarkThemeToken,
+) = Column(
+ modifier = modifier.fillMaxSize(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+) {
+ val scope = rememberCoroutineScope()
+ val darkTheme = isSdAppInDarkTheme()
+ var themeState by remember {
+ mutableStateOf(
+ AiSdAppThemeState(
+ systemColorPalette = false,
+ systemDarkTheme = false,
+ darkTheme = darkTheme,
+ darkThemeToken = darkThemeToken,
+ ),
+ )
+ }
+ Spacer(modifier = Modifier.weight(1f))
+ Text(
+ text = buildOnBoardingText(LocalizationR.string.on_boarding_page_ui_title),
+ fontSize = 24.sp,
+ textAlign = TextAlign.Center,
+ fontWeight = FontWeight(450),
+ )
+ Spacer(modifier = Modifier.weight(1f))
+ PhoneFrame(
+ modifier = Modifier.fillMaxWidth(onBoardingPhoneWidthFraction),
+ ) {
+ CompositionLocalProvider(LocalDensity provides onBoardingDensity) {
+ AiSdAppTheme(themeState) {
+ SettingsScreenContent(
+ modifier = Modifier
+ .gesturesDisabled()
+ .aspectRatio(onBoardingPhoneAspectRatio),
+ state = SettingsState(
+ loading = false,
+ onBoardingDemo = true,
+ colorToken = themeState.colorToken,
+ darkThemeToken = darkThemeToken,
+ darkTheme = darkTheme,
+ ),
+ )
+ }
+ }
+ }
+ DisposableEffect(Unit) {
+ val job = scope.launch {
+ while (true) {
+ delay(700)
+ themeState = themeState.copy(
+ colorToken = ColorToken.entries.random(),
+ )
+ }
+ }
+ onDispose {
+ job.cancel()
+ }
+ }
+ Spacer(modifier = Modifier.weight(1f))
+}
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/page/ProvidersPageContent.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/page/ProvidersPageContent.kt
new file mode 100644
index 00000000..362ccfbd
--- /dev/null
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/page/ProvidersPageContent.kt
@@ -0,0 +1,85 @@
+package com.shifthackz.aisdv1.presentation.screen.onboarding.page
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.aspectRatio
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.sp
+import com.shifthackz.aisdv1.core.extensions.gesturesDisabled
+import com.shifthackz.aisdv1.domain.entity.ServerSource
+import com.shifthackz.aisdv1.presentation.screen.onboarding.buildOnBoardingText
+import com.shifthackz.aisdv1.presentation.screen.onboarding.onBoardingDensity
+import com.shifthackz.aisdv1.presentation.screen.onboarding.onBoardingPhoneAspectRatio
+import com.shifthackz.aisdv1.presentation.screen.onboarding.onBoardingPhoneWidthFraction
+import com.shifthackz.aisdv1.presentation.screen.setup.ServerSetupScreenContent
+import com.shifthackz.aisdv1.presentation.screen.setup.ServerSetupState
+import com.shifthackz.aisdv1.presentation.widget.frame.PhoneFrame
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+import com.shifthackz.aisdv1.core.localization.R as LocalizationR
+
+@Composable
+fun ProviderPageContent(
+ modifier: Modifier = Modifier,
+) = Column(
+ modifier = modifier.fillMaxSize(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+) {
+ val scope = rememberCoroutineScope()
+ var serverState by remember {
+ mutableStateOf(
+ ServerSetupState(
+ showBackNavArrow = false,
+ )
+ )
+ }
+ Spacer(modifier = Modifier.weight(1f))
+ Text(
+ text = buildOnBoardingText(LocalizationR.string.on_boarding_page_provider_title),
+ fontSize = 24.sp,
+ textAlign = TextAlign.Center,
+ fontWeight = FontWeight(450),
+ )
+ Spacer(modifier = Modifier.weight(1f))
+ PhoneFrame(
+ modifier = Modifier.fillMaxWidth(onBoardingPhoneWidthFraction),
+ ) {
+ CompositionLocalProvider(LocalDensity provides onBoardingDensity) {
+ ServerSetupScreenContent(
+ modifier = Modifier
+ .gesturesDisabled()
+ .aspectRatio(onBoardingPhoneAspectRatio),
+ state = serverState,
+ )
+ }
+ }
+ Spacer(modifier = Modifier.weight(1f))
+ DisposableEffect(Unit) {
+ val job = scope.launch {
+ while (true) {
+ delay(1200)
+ serverState = serverState.copy(
+ mode = ServerSource.entries.random(),
+ )
+ }
+ }
+ onDispose {
+ job.cancel()
+ }
+ }
+}
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsIntent.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsIntent.kt
index be85a4fb..41f68563 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsIntent.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsIntent.kt
@@ -40,6 +40,8 @@ sealed interface SettingsIntent : MviIntent {
}
data object Donate : Action
+
+ data object OnBoarding : Action
}
sealed class LaunchUrl : SettingsIntent, KoinComponent {
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsScreen.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsScreen.kt
index f4757741..0c13e5d4 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsScreen.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsScreen.kt
@@ -20,6 +20,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountTree
+import androidx.compose.material.icons.filled.AllInclusive
import androidx.compose.material.icons.filled.AutoFixNormal
import androidx.compose.material.icons.filled.Circle
import androidx.compose.material.icons.filled.Code
@@ -124,7 +125,7 @@ fun SettingsScreen() {
},
applySystemUiColors = false,
) { state, intentHandler ->
- ScreenContent(
+ SettingsScreenContent(
state = state,
processIntent = intentHandler,
)
@@ -132,10 +133,10 @@ fun SettingsScreen() {
}
@Composable
-private fun ScreenContent(
+fun SettingsScreenContent(
modifier: Modifier = Modifier,
state: SettingsState,
- processIntent: (SettingsIntent) -> Unit,
+ processIntent: (SettingsIntent) -> Unit = {},
) {
Box(modifier) {
Scaffold(
@@ -202,8 +203,9 @@ private fun ContentSettingsState(
) {
systemUiController.setNavigationBarColor(navBarColor)
}
+ val scrollState = rememberScrollState()
Column(
- modifier = modifier.verticalScroll(rememberScrollState()),
+ modifier = modifier.verticalScroll(scrollState),
) {
val headerModifier = Modifier.padding(top = 28.dp, bottom = 8.dp)
@@ -215,220 +217,228 @@ private fun ContentSettingsState(
.fillMaxWidth()
.padding(top = 4.dp, start = 4.dp)
- //region MAIN SETTINGS
- SettingsHeader(
- modifier = headerModifier,
- loading = state.loading,
- text = LocalizationR.string.settings_header_server.asUiText(),
- )
- SettingsItem(
- modifier = itemModifier,
- loading = state.loading,
- startIcon = Icons.Default.SettingsEthernet,
- text = LocalizationR.string.settings_item_config.asUiText(),
- endValueText = when (state.serverSource) {
- ServerSource.AUTOMATIC1111 -> LocalizationR.string.srv_type_own_short
- ServerSource.HORDE -> LocalizationR.string.srv_type_horde_short
- ServerSource.HUGGING_FACE -> LocalizationR.string.srv_type_hugging_face_short
- ServerSource.OPEN_AI -> LocalizationR.string.srv_type_open_ai
- ServerSource.STABILITY_AI -> LocalizationR.string.srv_type_stability_ai
- ServerSource.LOCAL -> LocalizationR.string.srv_type_local_short
- ServerSource.SWARM_UI -> LocalizationR.string.srv_type_swarm_ui
- }.asUiText(),
- onClick = { processIntent(SettingsIntent.NavigateConfiguration) },
- )
- if (state.showStabilityAiCredits) SettingsItem(
- modifier = itemModifier,
- loading = state.loading,
- enabled = false,
- startIcon = Icons.Default.Circle,
- text = LocalizationR.string.settings_item_stability_ai_credits.asUiText(),
- endValueText = state.stabilityAiCredits.roundTo(4).toString().asUiText(),
- )
- if (state.showSdModelSelector) SettingsItem(
- modifier = itemModifier,
- loading = state.loading,
- startIcon = Icons.Default.AutoFixNormal,
- text = LocalizationR.string.settings_item_sd_model.asUiText(),
- endValueText = state.sdModelSelected.asUiText(),
- onClick = { processIntent(SettingsIntent.SdModel.OpenChooser) },
- )
- if (state.showLocalUseNNAPI) {
+ if (!state.onBoardingDemo) {
+ //region MAIN SETTINGS
+ SettingsHeader(
+ modifier = headerModifier,
+ loading = state.loading,
+ text = LocalizationR.string.settings_header_server.asUiText(),
+ )
SettingsItem(
modifier = itemModifier,
loading = state.loading,
- startIcon = Icons.Default.AccountTree,
- text = LocalizationR.string.settings_item_local_nnapi.asUiText(),
+ startIcon = Icons.Default.SettingsEthernet,
+ text = LocalizationR.string.settings_item_config.asUiText(),
+ endValueText = when (state.serverSource) {
+ ServerSource.AUTOMATIC1111 -> LocalizationR.string.srv_type_own_short
+ ServerSource.HORDE -> LocalizationR.string.srv_type_horde_short
+ ServerSource.HUGGING_FACE -> LocalizationR.string.srv_type_hugging_face_short
+ ServerSource.OPEN_AI -> LocalizationR.string.srv_type_open_ai
+ ServerSource.STABILITY_AI -> LocalizationR.string.srv_type_stability_ai
+ ServerSource.LOCAL -> LocalizationR.string.srv_type_local_short
+ ServerSource.SWARM_UI -> LocalizationR.string.srv_type_swarm_ui
+ }.asUiText(),
+ onClick = { processIntent(SettingsIntent.NavigateConfiguration) },
+ )
+ if (state.showStabilityAiCredits) SettingsItem(
+ modifier = itemModifier,
+ loading = state.loading,
+ enabled = false,
+ startIcon = Icons.Default.Circle,
+ text = LocalizationR.string.settings_item_stability_ai_credits.asUiText(),
+ endValueText = state.stabilityAiCredits.roundTo(4).toString().asUiText(),
+ )
+ if (state.showSdModelSelector) SettingsItem(
+ modifier = itemModifier,
+ loading = state.loading,
+ startIcon = Icons.Default.AutoFixNormal,
+ text = LocalizationR.string.settings_item_sd_model.asUiText(),
endValueText = state.sdModelSelected.asUiText(),
- onClick = { processIntent(SettingsIntent.UpdateFlag.NNAPI(!state.localUseNNAPI)) },
+ onClick = { processIntent(SettingsIntent.SdModel.OpenChooser) },
+ )
+ if (state.showLocalUseNNAPI) {
+ SettingsItem(
+ modifier = itemModifier,
+ loading = state.loading,
+ startIcon = Icons.Default.AccountTree,
+ text = LocalizationR.string.settings_item_local_nnapi.asUiText(),
+ endValueText = state.sdModelSelected.asUiText(),
+ onClick = { processIntent(SettingsIntent.UpdateFlag.NNAPI(!state.localUseNNAPI)) },
+ endValueContent = {
+ Switch(
+ modifier = Modifier.padding(horizontal = 8.dp),
+ checked = state.localUseNNAPI,
+ onCheckedChange = { processIntent(SettingsIntent.UpdateFlag.NNAPI(it)) },
+ )
+ }
+ )
+ AnimatedVisibility(visible = !state.loading) {
+ Text(
+ modifier = warningModifier,
+ text = stringResource(id = LocalizationR.string.settings_item_local_nnapi_warning),
+ style = MaterialTheme.typography.labelMedium,
+ )
+ }
+ }
+ SettingsItem(
+ modifier = itemModifier,
+ loading = state.loading,
+ startIcon = Icons.Default.MiscellaneousServices,
+ text = LocalizationR.string.settings_item_background_generation.asUiText(),
+ onClick = {
+ processIntent(SettingsIntent.UpdateFlag.BackgroundGeneration(!state.backgroundGeneration))
+ },
endValueContent = {
Switch(
modifier = Modifier.padding(horizontal = 8.dp),
- checked = state.localUseNNAPI,
- onCheckedChange = { processIntent(SettingsIntent.UpdateFlag.NNAPI(it)) },
+ checked = state.backgroundGeneration,
+ onCheckedChange = {
+ processIntent(SettingsIntent.UpdateFlag.BackgroundGeneration(it))
+ },
)
- }
+ },
)
AnimatedVisibility(visible = !state.loading) {
Text(
modifier = warningModifier,
- text = stringResource(id = LocalizationR.string.settings_item_local_nnapi_warning),
+ text = stringResource(id = LocalizationR.string.settings_item_background_generation_warning),
style = MaterialTheme.typography.labelMedium,
)
}
- }
- SettingsItem(
- modifier = itemModifier,
- loading = state.loading,
- startIcon = Icons.Default.MiscellaneousServices,
- text = LocalizationR.string.settings_item_background_generation.asUiText(),
- onClick = {
- processIntent(SettingsIntent.UpdateFlag.BackgroundGeneration(!state.backgroundGeneration))
- },
- endValueContent = {
- Switch(
- modifier = Modifier.padding(horizontal = 8.dp),
- checked = state.backgroundGeneration,
- onCheckedChange = {
- processIntent(SettingsIntent.UpdateFlag.BackgroundGeneration(it))
- },
+ AnimatedVisibility(visible = !state.loading && state.developerMode) {
+ SettingsItem(
+ modifier = itemModifier,
+ loading = state.loading,
+ startIcon = Icons.Default.DeveloperMode,
+ text = LocalizationR.string.title_debug_menu.asUiText(),
+ onClick = { processIntent(SettingsIntent.NavigateDeveloperMode) },
)
- },
- )
- AnimatedVisibility(visible = !state.loading) {
- Text(
- modifier = warningModifier,
- text = stringResource(id = LocalizationR.string.settings_item_background_generation_warning),
- style = MaterialTheme.typography.labelMedium,
+ }
+ //endregion
+
+ //region APP SETTINGS
+ SettingsHeader(
+ modifier = headerModifier,
+ loading = state.loading,
+ text = LocalizationR.string.settings_header_app.asUiText(),
+ )
+ if (state.showMonitorConnectionOption) SettingsItem(
+ modifier = itemModifier,
+ loading = state.loading,
+ startIcon = Icons.Default.Refresh,
+ text = LocalizationR.string.settings_item_monitor_connection.asUiText(),
+ onClick = {
+ processIntent(SettingsIntent.UpdateFlag.MonitorConnection(!state.monitorConnectivity))
+ },
+ endValueContent = {
+ Switch(
+ modifier = Modifier.padding(horizontal = 8.dp),
+ checked = state.monitorConnectivity,
+ onCheckedChange = {
+ processIntent(
+ SettingsIntent.UpdateFlag.MonitorConnection(
+ it
+ )
+ )
+ },
+ )
+ },
)
- }
- AnimatedVisibility(visible = !state.loading && state.developerMode) {
SettingsItem(
modifier = itemModifier,
loading = state.loading,
- startIcon = Icons.Default.DeveloperMode,
- text = LocalizationR.string.title_debug_menu.asUiText(),
- onClick = { processIntent(SettingsIntent.NavigateDeveloperMode) },
+ startIcon = Icons.Default.Save,
+ text = UiText.Concat(
+ LocalizationR.string.settings_item_auto_save.asUiText(),
+ if (state.backgroundGeneration) "*" else "",
+ ),
+ onClick = {
+ processIntent(SettingsIntent.UpdateFlag.AutoSaveResult(!state.autoSaveAiResults))
+ },
+ endValueContent = {
+ Switch(
+ modifier = Modifier.padding(horizontal = 8.dp),
+ checked = state.autoSaveAiResults,
+ onCheckedChange = {
+ processIntent(SettingsIntent.UpdateFlag.AutoSaveResult(it))
+ },
+ )
+ },
)
- }
- //endregion
-
- //region APP SETTINGS
- SettingsHeader(
- modifier = headerModifier,
- loading = state.loading,
- text = LocalizationR.string.settings_header_app.asUiText(),
- )
- if (state.showMonitorConnectionOption) SettingsItem(
- modifier = itemModifier,
- loading = state.loading,
- startIcon = Icons.Default.Refresh,
- text = LocalizationR.string.settings_item_monitor_connection.asUiText(),
- onClick = {
- processIntent(SettingsIntent.UpdateFlag.MonitorConnection(!state.monitorConnectivity))
- },
- endValueContent = {
- Switch(
- modifier = Modifier.padding(horizontal = 8.dp),
- checked = state.monitorConnectivity,
- onCheckedChange = { processIntent(SettingsIntent.UpdateFlag.MonitorConnection(it)) },
- )
- },
- )
- SettingsItem(
- modifier = itemModifier,
- loading = state.loading,
- startIcon = Icons.Default.Save,
- text = UiText.Concat(
- LocalizationR.string.settings_item_auto_save.asUiText(),
- if (state.backgroundGeneration) "*" else "",
- ),
- onClick = {
- processIntent(SettingsIntent.UpdateFlag.AutoSaveResult(!state.autoSaveAiResults))
- },
- endValueContent = {
- Switch(
- modifier = Modifier.padding(horizontal = 8.dp),
- checked = state.autoSaveAiResults,
- onCheckedChange = {
- processIntent(SettingsIntent.UpdateFlag.AutoSaveResult(it))
- },
+ AnimatedVisibility(
+ visible = !state.loading && state.backgroundGeneration,
+ ) {
+ Text(
+ modifier = warningModifier,
+ text = stringResource(id = LocalizationR.string.settings_item_auto_save_warning),
+ style = MaterialTheme.typography.labelMedium,
)
- },
- )
- AnimatedVisibility(
- visible = !state.loading && state.backgroundGeneration,
- ) {
- Text(
- modifier = warningModifier,
- text = stringResource(id = LocalizationR.string.settings_item_auto_save_warning),
- style = MaterialTheme.typography.labelMedium,
+ }
+ SettingsItem(
+ modifier = itemModifier,
+ loading = state.loading,
+ startIcon = Icons.Default.Folder,
+ text = LocalizationR.string.settings_item_auto_save_media_store.asUiText(),
+ onClick = {
+ processIntent(SettingsIntent.UpdateFlag.SaveToMediaStore(!state.saveToMediaStore))
+ },
+ endValueContent = {
+ Switch(
+ modifier = Modifier.padding(horizontal = 8.dp),
+ checked = state.saveToMediaStore,
+ onCheckedChange = {
+ processIntent(SettingsIntent.UpdateFlag.SaveToMediaStore(it))
+ },
+ )
+ },
)
- }
- SettingsItem(
- modifier = itemModifier,
- loading = state.loading,
- startIcon = Icons.Default.Folder,
- text = LocalizationR.string.settings_item_auto_save_media_store.asUiText(),
- onClick = {
- processIntent(SettingsIntent.UpdateFlag.SaveToMediaStore(!state.saveToMediaStore))
- },
- endValueContent = {
- Switch(
- modifier = Modifier.padding(horizontal = 8.dp),
- checked = state.saveToMediaStore,
- onCheckedChange = {
- processIntent(SettingsIntent.UpdateFlag.SaveToMediaStore(it))
- },
- )
- },
- )
- SettingsItem(
- modifier = itemModifier,
- loading = state.loading,
- startIcon = Icons.Default.Tag,
- text = LocalizationR.string.settings_item_tagged_input.asUiText(),
- onClick = {
- processIntent(SettingsIntent.UpdateFlag.TaggedInput(!state.formPromptTaggedInput))
- },
- endValueContent = {
- Switch(
- modifier = Modifier.padding(horizontal = 8.dp),
- checked = state.formPromptTaggedInput,
- onCheckedChange = {
- processIntent(SettingsIntent.UpdateFlag.TaggedInput(it))
- },
- )
- },
- )
- if (state.showFormAdvancedOption) {
SettingsItem(
modifier = itemModifier,
loading = state.loading,
- startIcon = Icons.Default.DynamicForm,
- text = LocalizationR.string.settings_item_advanced_form_default.asUiText(),
+ startIcon = Icons.Default.Tag,
+ text = LocalizationR.string.settings_item_tagged_input.asUiText(),
onClick = {
- processIntent(SettingsIntent.UpdateFlag.AdvancedFormVisibility(!state.formAdvancedOptionsAlwaysShow))
+ processIntent(SettingsIntent.UpdateFlag.TaggedInput(!state.formPromptTaggedInput))
},
endValueContent = {
Switch(
modifier = Modifier.padding(horizontal = 8.dp),
- checked = state.formAdvancedOptionsAlwaysShow,
+ checked = state.formPromptTaggedInput,
onCheckedChange = {
- processIntent(SettingsIntent.UpdateFlag.AdvancedFormVisibility(it))
+ processIntent(SettingsIntent.UpdateFlag.TaggedInput(it))
},
)
},
)
+ if (state.showFormAdvancedOption) {
+ SettingsItem(
+ modifier = itemModifier,
+ loading = state.loading,
+ startIcon = Icons.Default.DynamicForm,
+ text = LocalizationR.string.settings_item_advanced_form_default.asUiText(),
+ onClick = {
+ processIntent(SettingsIntent.UpdateFlag.AdvancedFormVisibility(!state.formAdvancedOptionsAlwaysShow))
+ },
+ endValueContent = {
+ Switch(
+ modifier = Modifier.padding(horizontal = 8.dp),
+ checked = state.formAdvancedOptionsAlwaysShow,
+ onCheckedChange = {
+ processIntent(SettingsIntent.UpdateFlag.AdvancedFormVisibility(it))
+ },
+ )
+ },
+ )
+ }
+ SettingsItem(
+ modifier = itemModifier,
+ loading = state.loading,
+ startIcon = Icons.Default.DeleteForever,
+ text = LocalizationR.string.settings_item_clear_cache.asUiText(),
+ onClick = { processIntent(SettingsIntent.Action.ClearAppCache.Request) },
+ )
+ //endregion
}
- SettingsItem(
- modifier = itemModifier,
- loading = state.loading,
- startIcon = Icons.Default.DeleteForever,
- text = LocalizationR.string.settings_item_clear_cache.asUiText(),
- onClick = { processIntent(SettingsIntent.Action.ClearAppCache.Request)},
- )
- //endregion
//region LOOK AND FEEL
SettingsHeader(
@@ -580,6 +590,13 @@ private fun ContentSettingsState(
text = LocalizationR.string.settings_item_donate.asUiText(),
onClick = { processIntent(SettingsIntent.Action.Donate) },
)
+ SettingsItem(
+ modifier = itemModifier,
+ loading = state.loading,
+ startIcon = Icons.Default.AllInclusive,
+ text = LocalizationR.string.settings_item_on_boarding.asUiText(),
+ onClick = { processIntent(SettingsIntent.Action.OnBoarding) },
+ )
SettingsItem(
modifier = itemModifier,
loading = state.loading,
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsState.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsState.kt
index 432ec831..aff0ad43 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsState.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsState.kt
@@ -11,6 +11,7 @@ import com.shifthackz.android.core.mvi.MviState
@Immutable
data class SettingsState(
val loading: Boolean = true,
+ val onBoardingDemo: Boolean = false,
val screenModal: Modal = Modal.None,
val serverSource: ServerSource = ServerSource.AUTOMATIC1111,
val sdModels: List = emptyList(),
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsViewModel.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsViewModel.kt
index ff9c9cd7..a300bde8 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsViewModel.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsViewModel.kt
@@ -16,12 +16,12 @@ import com.shifthackz.aisdv1.domain.usecase.caching.ClearAppCacheUseCase
import com.shifthackz.aisdv1.domain.usecase.sdmodel.GetStableDiffusionModelsUseCase
import com.shifthackz.aisdv1.domain.usecase.sdmodel.SelectStableDiffusionModelUseCase
import com.shifthackz.aisdv1.domain.usecase.stabilityai.ObserveStabilityAiCreditsUseCase
+import com.shifthackz.aisdv1.presentation.model.LaunchSource
import com.shifthackz.aisdv1.presentation.model.Modal
import com.shifthackz.aisdv1.presentation.navigation.router.drawer.DrawerRouter
import com.shifthackz.aisdv1.presentation.navigation.router.main.MainRouter
import com.shifthackz.aisdv1.presentation.screen.debug.DebugMenuAccessor
import com.shifthackz.aisdv1.presentation.screen.drawer.DrawerIntent
-import com.shifthackz.aisdv1.presentation.screen.setup.ServerSetupLaunchSource
import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.kotlin.subscribeBy
import com.shifthackz.aisdv1.core.localization.R as LocalizationR
@@ -109,7 +109,7 @@ class SettingsViewModel(
}
SettingsIntent.NavigateConfiguration -> mainRouter.navigateToServerSetup(
- ServerSetupLaunchSource.SETTINGS
+ LaunchSource.SETTINGS
)
SettingsIntent.NavigateDeveloperMode -> mainRouter.navigateToDebugMenu()
@@ -210,6 +210,10 @@ class SettingsViewModel(
SettingsIntent.Action.Donate -> mainRouter.navigateToDonate()
+ SettingsIntent.Action.OnBoarding -> mainRouter.navigateToOnBoarding(
+ source = LaunchSource.SETTINGS,
+ )
+
is SettingsIntent.UpdateFlag.BackgroundGeneration -> {
if (intent.flag) {
emitEffect(SettingsEffect.RequestPermission.Notifications)
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/setup/ServerSetupScreen.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/setup/ServerSetupScreen.kt
index ddba12fe..a83405f0 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/setup/ServerSetupScreen.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/setup/ServerSetupScreen.kt
@@ -86,7 +86,7 @@ fun ServerSetupScreen(
}
},
) { state, intentHandler ->
- ScreenContent(
+ ServerSetupScreenContent(
modifier = modifier.fillMaxSize(),
state = state,
buildInfoProvider = buildInfoProvider,
@@ -96,7 +96,7 @@ fun ServerSetupScreen(
}
@Composable
-private fun ScreenContent(
+fun ServerSetupScreenContent(
modifier: Modifier = Modifier,
state: ServerSetupState,
buildInfoProvider: BuildInfoProvider = BuildInfoProvider.stub,
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/setup/ServerSetupState.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/setup/ServerSetupState.kt
index 7e91bbf6..553e7bde 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/setup/ServerSetupState.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/setup/ServerSetupState.kt
@@ -87,15 +87,6 @@ data class ServerSetupState(
)
}
-enum class ServerSetupLaunchSource {
- SPLASH,
- SETTINGS;
-
- companion object {
- fun fromKey(key: Int) = entries.firstOrNull { it.ordinal == key } ?: SPLASH
- }
-}
-
val Configuration.authType: ServerSetupState.AuthType
get() {
val noCredentials = ServerSetupState.AuthType.ANONYMOUS
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/setup/ServerSetupViewModel.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/setup/ServerSetupViewModel.kt
index d02f1287..d963e80f 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/setup/ServerSetupViewModel.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/setup/ServerSetupViewModel.kt
@@ -21,6 +21,7 @@ import com.shifthackz.aisdv1.domain.usecase.downloadable.DownloadModelUseCase
import com.shifthackz.aisdv1.domain.usecase.downloadable.GetLocalAiModelsUseCase
import com.shifthackz.aisdv1.domain.usecase.huggingface.FetchAndGetHuggingFaceModelsUseCase
import com.shifthackz.aisdv1.domain.usecase.settings.GetConfigurationUseCase
+import com.shifthackz.aisdv1.presentation.model.LaunchSource
import com.shifthackz.aisdv1.presentation.model.Modal
import com.shifthackz.aisdv1.presentation.navigation.router.main.MainRouter
import com.shifthackz.aisdv1.presentation.screen.setup.mappers.mapLocalCustomModelSwitchState
@@ -32,7 +33,7 @@ import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.kotlin.subscribeBy
class ServerSetupViewModel(
- launchSource: ServerSetupLaunchSource,
+ launchSource: LaunchSource,
getConfigurationUseCase: GetConfigurationUseCase,
getLocalAiModelsUseCase: GetLocalAiModelsUseCase,
fetchAndGetHuggingFaceModelsUseCase: FetchAndGetHuggingFaceModelsUseCase,
@@ -49,7 +50,7 @@ class ServerSetupViewModel(
) : MviRxViewModel() {
override val initialState = ServerSetupState(
- showBackNavArrow = launchSource == ServerSetupLaunchSource.SETTINGS,
+ showBackNavArrow = launchSource == LaunchSource.SETTINGS,
)
private val credentials: AuthorizationCredentials
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/splash/SplashViewModel.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/splash/SplashViewModel.kt
index a2aa431d..ee148e3f 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/splash/SplashViewModel.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/splash/SplashViewModel.kt
@@ -6,7 +6,7 @@ import com.shifthackz.aisdv1.core.common.schedulers.subscribeOnMainThread
import com.shifthackz.aisdv1.core.viewmodel.MviRxViewModel
import com.shifthackz.aisdv1.domain.usecase.splash.SplashNavigationUseCase
import com.shifthackz.aisdv1.presentation.navigation.router.main.MainRouter
-import com.shifthackz.aisdv1.presentation.screen.setup.ServerSetupLaunchSource
+import com.shifthackz.aisdv1.presentation.navigation.router.main.postSplashNavigation
import com.shifthackz.android.core.mvi.EmptyEffect
import com.shifthackz.android.core.mvi.EmptyIntent
import com.shifthackz.android.core.mvi.EmptyState
@@ -23,14 +23,6 @@ class SplashViewModel(
init {
!splashNavigationUseCase()
.subscribeOnMainThread(schedulersProvider)
- .subscribeBy(::errorLog) { action ->
- when (action) {
- SplashNavigationUseCase.Action.LAUNCH_ONBOARDING -> {}
- SplashNavigationUseCase.Action.LAUNCH_SERVER_SETUP -> mainRouter.navigateToServerSetup(
- source = ServerSetupLaunchSource.SPLASH
- )
- SplashNavigationUseCase.Action.LAUNCH_HOME -> mainRouter.navigateToPostSplashConfigLoader()
- }
- }
+ .subscribeBy(::errorLog) { action -> mainRouter.postSplashNavigation(action) }
}
}
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/txt2img/TextToImageScreen.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/txt2img/TextToImageScreen.kt
index c3563be3..af121398 100755
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/txt2img/TextToImageScreen.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/txt2img/TextToImageScreen.kt
@@ -52,7 +52,7 @@ fun TextToImageScreen() {
viewModel = koinViewModel(),
applySystemUiColors = false,
) { state, intentHandler ->
- ScreenContent(
+ TextToImageScreenContent(
modifier = Modifier.fillMaxSize(),
state = state,
processIntent = intentHandler,
@@ -61,7 +61,7 @@ fun TextToImageScreen() {
}
@Composable
-private fun ScreenContent(
+fun TextToImageScreenContent(
modifier: Modifier = Modifier,
state: TextToImageState,
processIntent: (GenerationMviIntent) -> Unit = {},
@@ -185,7 +185,7 @@ private fun ScreenContent(
@Composable
@Preview(showSystemUi = true, showBackground = true)
fun PreviewStateContent() {
- ScreenContent(
+ TextToImageScreenContent(
modifier = Modifier.fillMaxSize(),
state = TextToImageState(
prompt = "Opel Astra H OPC",
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/txt2img/TextToImageState.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/txt2img/TextToImageState.kt
index 13b4b996..2dad0725 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/txt2img/TextToImageState.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/txt2img/TextToImageState.kt
@@ -19,6 +19,7 @@ import com.shifthackz.aisdv1.core.localization.R as LocalizationR
@Immutable
data class TextToImageState(
+ override val onBoardingDemo: Boolean = false,
override val screenModal: Modal = Modal.None,
override val mode: ServerSource = ServerSource.AUTOMATIC1111,
override val advancedToggleButtonVisible: Boolean = true,
@@ -50,6 +51,7 @@ data class TextToImageState(
) : GenerationMviState() {
override fun copyState(
+ onBoardingDemo: Boolean,
screenModal: Modal,
mode: ServerSource,
advancedToggleButtonVisible: Boolean,
@@ -79,6 +81,7 @@ data class TextToImageState(
batchCount: Int,
generateButtonEnabled: Boolean
): GenerationMviState = copy(
+ onBoardingDemo = onBoardingDemo,
screenModal = screenModal,
mode = mode,
advancedToggleButtonVisible = advancedToggleButtonVisible,
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/theme/global/AiSdAppTheme.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/theme/global/AiSdAppTheme.kt
index efa903c2..cb0eee09 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/theme/global/AiSdAppTheme.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/theme/global/AiSdAppTheme.kt
@@ -20,30 +20,38 @@ fun AiSdAppTheme(
viewModel = koinViewModel(),
applySystemUiColors = false,
) { state, _ ->
- val context = LocalContext.current
- val isDark = if (state.systemDarkTheme) {
- isSystemInDarkTheme()
- } else {
- state.darkTheme
- }
- if (state.systemColorPalette && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- MaterialTheme(
- colorScheme = if (isDark) {
- dynamicDarkColorScheme(context)
- } else {
- dynamicLightColorScheme(context)
- },
- content = content,
- )
- } else {
- CatppuccinTheme.Palette(
- palette = colorTokenPalette(
- token = state.colorToken,
- darkThemeToken = state.darkThemeToken,
- isDark = isDark
- ),
- content = content,
- )
- }
+ AiSdAppTheme(state, content)
+ }
+}
+
+@Composable
+fun AiSdAppTheme(
+ state: AiSdAppThemeState,
+ content: @Composable () -> Unit,
+) {
+ val context = LocalContext.current
+ val isDark = if (state.systemDarkTheme) {
+ isSystemInDarkTheme()
+ } else {
+ state.darkTheme
+ }
+ if (state.systemColorPalette && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ MaterialTheme(
+ colorScheme = if (isDark) {
+ dynamicDarkColorScheme(context)
+ } else {
+ dynamicLightColorScheme(context)
+ },
+ content = content,
+ )
+ } else {
+ CatppuccinTheme.Palette(
+ palette = colorTokenPalette(
+ token = state.colorToken,
+ darkThemeToken = state.darkThemeToken,
+ isDark = isDark,
+ ),
+ content = content,
+ )
}
}
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/utils/Constants.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/utils/Constants.kt
index d83360a1..6562ec2f 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/utils/Constants.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/utils/Constants.kt
@@ -23,6 +23,8 @@ object Constants {
const val ROUTE_LOGGER = "logger"
const val ROUTE_IN_PAINT = "in_paint"
const val ROUTE_DONATE = "donate"
+ const val ROUTE_ONBOARDING = "onboarding"
+ const val ROUTE_ONBOARDING_FULL = "$ROUTE_ONBOARDING/{$PARAM_SOURCE}"
const val SUB_SEED_STRENGTH_MIN = 0f
const val SUB_SEED_STRENGTH_MAX = 1f
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/widget/dialog/ProgressDialog.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/widget/dialog/ProgressDialog.kt
index 31c1787e..1820409a 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/widget/dialog/ProgressDialog.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/widget/dialog/ProgressDialog.kt
@@ -44,37 +44,14 @@ fun ProgressDialog(
dismissOnBackPress = canDismiss,
),
) {
- Surface(
- shape = RoundedCornerShape(16.dp),
- color = AlertDialogDefaults.containerColor,
- ) {
- Column(modifier = Modifier.padding(horizontal = 16.dp, vertical = 16.dp)) {
- Text(
- text = stringResource(id = titleResId),
- style = TextStyle(fontSize = 16.sp),
- fontWeight = FontWeight.Bold,
- color = AlertDialogDefaults.titleContentColor,
- )
- Text(
- modifier = Modifier.padding(top = 14.dp),
- text = stringResource(id = subTitleResId),
- style = TextStyle(fontSize = 14.sp),
- color = AlertDialogDefaults.textContentColor,
- )
- ProgressDialogStatus(
- waitTimeSeconds = waitTimeSeconds,
- positionInQueue = positionInQueue,
- step = step,
- )
- LinearProgressIndicator(
- modifier = Modifier
- .fillMaxWidth()
- .padding(top = 8.dp),
- color = AlertDialogDefaults.iconContentColor,
- )
- content?.invoke()
- }
- }
+ GeneratingProgressDialogContent(
+ titleResId = titleResId,
+ subTitleResId = subTitleResId,
+ waitTimeSeconds = waitTimeSeconds,
+ positionInQueue = positionInQueue,
+ step = step,
+ content = content,
+ )
}
}
@@ -128,6 +105,48 @@ fun ProgressDialogCancelButton(onClick: () -> Unit) {
}
}
+@Composable
+fun GeneratingProgressDialogContent(
+ @StringRes titleResId: Int = LocalizationR.string.communicating_progress_title,
+ @StringRes subTitleResId: Int = LocalizationR.string.communicating_progress_sub_title,
+ waitTimeSeconds: Int? = null,
+ positionInQueue: Int? = null,
+ step: Pair? = null,
+ content: (@Composable () -> Unit)? = null,
+) {
+ Surface(
+ shape = RoundedCornerShape(16.dp),
+ color = AlertDialogDefaults.containerColor,
+ ) {
+ Column(modifier = Modifier.padding(horizontal = 16.dp, vertical = 16.dp)) {
+ Text(
+ text = stringResource(id = titleResId),
+ style = TextStyle(fontSize = 16.sp),
+ fontWeight = FontWeight.Bold,
+ color = AlertDialogDefaults.titleContentColor,
+ )
+ Text(
+ modifier = Modifier.padding(top = 14.dp),
+ text = stringResource(id = subTitleResId),
+ style = TextStyle(fontSize = 14.sp),
+ color = AlertDialogDefaults.textContentColor,
+ )
+ ProgressDialogStatus(
+ waitTimeSeconds = waitTimeSeconds,
+ positionInQueue = positionInQueue,
+ step = step,
+ )
+ LinearProgressIndicator(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 8.dp),
+ color = AlertDialogDefaults.iconContentColor,
+ )
+ content?.invoke()
+ }
+ }
+}
+
@Composable
@Preview(showBackground = true)
private fun CommunicationProgressDialogPreview() {
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/widget/frame/PhoneFrame.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/widget/frame/PhoneFrame.kt
new file mode 100644
index 00000000..b30b8117
--- /dev/null
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/widget/frame/PhoneFrame.kt
@@ -0,0 +1,99 @@
+package com.shifthackz.aisdv1.presentation.widget.frame
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.dp
+import com.shifthackz.aisdv1.presentation.R
+
+@Composable
+fun PhoneFrame(
+ modifier: Modifier = Modifier,
+ content: @Composable () -> Unit = {},
+) {
+ Column(
+ modifier = modifier
+ .background(Color.Black, RoundedCornerShape(24.dp))
+ .border(
+ border = BorderStroke(6.dp, Color.Black),
+ shape = RoundedCornerShape(24.dp)
+ )
+ .clip(RoundedCornerShape(24.dp)),
+ ) {
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(18.dp)
+ .background(
+ color = Color.Black,
+ shape = RoundedCornerShape(
+ topStart = 24.dp,
+ topEnd = 24.dp,
+ ),
+ ),
+ contentAlignment = Alignment.Center,
+ ) {
+ Box(
+ modifier = Modifier
+ .alpha(0.5f)
+ .padding(top = 8.dp)
+ .width(54.dp)
+ .height(8.dp)
+ .clip(RoundedCornerShape(12.dp)),
+ contentAlignment = Alignment.Center,
+ ) {
+ Image(
+ modifier = Modifier.fillMaxSize(),
+ painter = painterResource(id = R.drawable.ic_speaker_texture),
+ contentDescription = null,
+ contentScale = ContentScale.Crop,
+ )
+ }
+ }
+ Box(
+ modifier = Modifier,
+ contentAlignment = Alignment.Center,
+ ) {
+ Box(
+ modifier = Modifier
+ .border(
+ border = BorderStroke(6.dp, Color.Black),
+ shape = RoundedCornerShape(12.dp)
+ )
+ .padding(6.dp),
+ ) {
+ content()
+ }
+ }
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(12.dp)
+ .background(
+ color = Color.Black,
+ shape = RoundedCornerShape(
+ bottomStart = 24.dp,
+ bottomEnd = 24.dp,
+ ),
+ ),
+ )
+ }
+
+}
diff --git a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/widget/input/GenerationInputForm.kt b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/widget/input/GenerationInputForm.kt
index 5e74957b..1a8583d5 100644
--- a/presentation/src/main/java/com/shifthackz/aisdv1/presentation/widget/input/GenerationInputForm.kt
+++ b/presentation/src/main/java/com/shifthackz/aisdv1/presentation/widget/input/GenerationInputForm.kt
@@ -142,24 +142,28 @@ fun GenerationInputForm(
}
Column(modifier = modifier) {
- when (state.mode) {
- ServerSource.AUTOMATIC1111,
- ServerSource.SWARM_UI,
- ServerSource.STABILITY_AI,
- ServerSource.HUGGING_FACE,
- ServerSource.LOCAL -> EngineSelectionComponent(
- modifier = Modifier
- .fillMaxWidth()
- .padding(top = 8.dp),
- )
- ServerSource.OPEN_AI -> DropdownTextField(
- modifier = Modifier.padding(top = 8.dp),
- label = LocalizationR.string.hint_model_open_ai.asUiText(),
- value = state.openAiModel,
- items = OpenAiModel.entries,
- onItemSelected = { processIntent(GenerationMviIntent.Update.OpenAi.Model(it)) },
- )
- else -> Unit
+ if (!state.onBoardingDemo) {
+ when (state.mode) {
+ ServerSource.AUTOMATIC1111,
+ ServerSource.SWARM_UI,
+ ServerSource.STABILITY_AI,
+ ServerSource.HUGGING_FACE,
+ ServerSource.LOCAL -> EngineSelectionComponent(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 8.dp),
+ )
+
+ ServerSource.OPEN_AI -> DropdownTextField(
+ modifier = Modifier.padding(top = 8.dp),
+ label = LocalizationR.string.hint_model_open_ai.asUiText(),
+ value = state.openAiModel,
+ items = OpenAiModel.entries,
+ onItemSelected = { processIntent(GenerationMviIntent.Update.OpenAi.Model(it)) },
+ )
+
+ else -> Unit
+ }
}
if (state.formPromptTaggedInput) {
ChipTextFieldWithItem(
diff --git a/presentation/src/main/res/drawable/ic_speaker_texture.jpg b/presentation/src/main/res/drawable/ic_speaker_texture.jpg
new file mode 100644
index 00000000..8628231e
Binary files /dev/null and b/presentation/src/main/res/drawable/ic_speaker_texture.jpg differ
diff --git a/presentation/src/test/java/com/shifthackz/aisdv1/presentation/navigation/router/main/MainRouterImplTest.kt b/presentation/src/test/java/com/shifthackz/aisdv1/presentation/navigation/router/main/MainRouterImplTest.kt
index ecec9c5c..bbc45def 100644
--- a/presentation/src/test/java/com/shifthackz/aisdv1/presentation/navigation/router/main/MainRouterImplTest.kt
+++ b/presentation/src/test/java/com/shifthackz/aisdv1/presentation/navigation/router/main/MainRouterImplTest.kt
@@ -1,25 +1,13 @@
package com.shifthackz.aisdv1.presentation.navigation.router.main
-import com.shifthackz.aisdv1.domain.preference.PreferenceManager
+import com.shifthackz.aisdv1.presentation.model.LaunchSource
import com.shifthackz.aisdv1.presentation.navigation.NavigationEffect
-import com.shifthackz.aisdv1.presentation.screen.debug.DebugMenuAccessor
-import com.shifthackz.aisdv1.presentation.screen.setup.ServerSetupLaunchSource
import com.shifthackz.aisdv1.presentation.utils.Constants
-import io.mockk.mockk
-import org.junit.Before
import org.junit.Test
class MainRouterImplTest {
- private val stubPreferenceManager = mockk()
- private val stubDebugMenuAccessor = DebugMenuAccessor(stubPreferenceManager)
-
- private val router = MainRouterImpl(stubDebugMenuAccessor)
-
- @Before
- fun initialize() {
-
- }
+ private val router = MainRouterImpl()
@Test
fun `given user navigates back, expected router emits Back event`() {
@@ -51,7 +39,11 @@ class MainRouterImplTest {
.test()
.also { router.navigateToHomeScreen() }
.assertNoErrors()
- .assertValueAt(0, NavigationEffect.Navigate.RoutePopUp(Constants.ROUTE_HOME))
+ .assertValueAt(0) { actual ->
+ val expectedRoute = Constants.ROUTE_HOME
+ actual is NavigationEffect.Navigate.RouteBuilder
+ && actual.route == expectedRoute
+ }
}
@Test
@@ -59,11 +51,11 @@ class MainRouterImplTest {
router
.observe()
.test()
- .also { router.navigateToServerSetup(ServerSetupLaunchSource.SPLASH) }
+ .also { router.navigateToServerSetup(LaunchSource.SPLASH) }
.assertNoErrors()
.assertValueAt(0) { actual ->
val expectedRoute =
- "${Constants.ROUTE_SERVER_SETUP}/${ServerSetupLaunchSource.SPLASH.ordinal}"
+ "${Constants.ROUTE_SERVER_SETUP}/${LaunchSource.SPLASH.ordinal}"
actual is NavigationEffect.Navigate.RouteBuilder
&& actual.route == expectedRoute
}
@@ -74,11 +66,11 @@ class MainRouterImplTest {
router
.observe()
.test()
- .also { router.navigateToServerSetup(ServerSetupLaunchSource.SETTINGS) }
+ .also { router.navigateToServerSetup(LaunchSource.SETTINGS) }
.assertNoErrors()
.assertValueAt(0) { actual ->
val expectedRoute =
- "${Constants.ROUTE_SERVER_SETUP}/${ServerSetupLaunchSource.SETTINGS.ordinal}"
+ "${Constants.ROUTE_SERVER_SETUP}/${LaunchSource.SETTINGS.ordinal}"
actual is NavigationEffect.Navigate.RouteBuilder
&& actual.route == expectedRoute
}
diff --git a/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/gallery/detail/GalleryDetailViewModelTest.kt b/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/gallery/detail/GalleryDetailViewModelTest.kt
index e3431228..3d0efcb6 100644
--- a/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/gallery/detail/GalleryDetailViewModelTest.kt
+++ b/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/gallery/detail/GalleryDetailViewModelTest.kt
@@ -81,30 +81,28 @@ class GalleryDetailViewModelTest : CoreViewModelTest() {
@Test
fun `initialized, loaded ai generation result, expected UI state is Content`() {
- runTest {
- val expected = GalleryDetailState.Content(
- tabs = GalleryDetailState.Tab.consume(mockAiGenerationResult.type),
- generationType = mockAiGenerationResult.type,
- id = mockAiGenerationResult.id,
- bitmap = stubBitmap,
- inputBitmap = stubBitmap,
- createdAt = mockAiGenerationResult.createdAt.toString().asUiText(),
- type = mockAiGenerationResult.type.key.asUiText(),
- prompt = mockAiGenerationResult.prompt.asUiText(),
- negativePrompt = mockAiGenerationResult.negativePrompt.asUiText(),
- size = "512 X 512".asUiText(),
- samplingSteps = mockAiGenerationResult.samplingSteps.toString().asUiText(),
- cfgScale = mockAiGenerationResult.cfgScale.toString().asUiText(),
- restoreFaces = mockAiGenerationResult.restoreFaces.mapToUi(),
- sampler = mockAiGenerationResult.sampler.asUiText(),
- seed = mockAiGenerationResult.seed.asUiText(),
- subSeed = mockAiGenerationResult.subSeed.asUiText(),
- subSeedStrength = mockAiGenerationResult.subSeedStrength.toString().asUiText(),
- denoisingStrength = mockAiGenerationResult.denoisingStrength.toString().asUiText(),
- )
- val actual = viewModel.state.value
- Assert.assertEquals(expected, actual)
- }
+ val expected = GalleryDetailState.Content(
+ tabs = GalleryDetailState.Tab.consume(mockAiGenerationResult.type),
+ generationType = mockAiGenerationResult.type,
+ id = mockAiGenerationResult.id,
+ bitmap = stubBitmap,
+ inputBitmap = stubBitmap,
+ createdAt = mockAiGenerationResult.createdAt.toString().asUiText(),
+ type = mockAiGenerationResult.type.key.asUiText(),
+ prompt = mockAiGenerationResult.prompt.asUiText(),
+ negativePrompt = mockAiGenerationResult.negativePrompt.asUiText(),
+ size = "512 X 512".asUiText(),
+ samplingSteps = mockAiGenerationResult.samplingSteps.toString().asUiText(),
+ cfgScale = mockAiGenerationResult.cfgScale.toString().asUiText(),
+ restoreFaces = mockAiGenerationResult.restoreFaces.mapToUi(),
+ sampler = mockAiGenerationResult.sampler.asUiText(),
+ seed = mockAiGenerationResult.seed.asUiText(),
+ subSeed = mockAiGenerationResult.subSeed.asUiText(),
+ subSeedStrength = mockAiGenerationResult.subSeedStrength.toString().asUiText(),
+ denoisingStrength = mockAiGenerationResult.denoisingStrength.toString().asUiText(),
+ )
+ val actual = viewModel.state.value
+ Assert.assertEquals(expected, actual)
}
@Test
diff --git a/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/img2img/ImageToImageViewModelTest.kt b/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/img2img/ImageToImageViewModelTest.kt
index 50e45fbd..e2982572 100644
--- a/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/img2img/ImageToImageViewModelTest.kt
+++ b/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/img2img/ImageToImageViewModelTest.kt
@@ -19,10 +19,10 @@ import com.shifthackz.aisdv1.presentation.core.GenerationFormUpdateEvent
import com.shifthackz.aisdv1.presentation.core.GenerationMviIntent
import com.shifthackz.aisdv1.presentation.mocks.mockAiGenerationResult
import com.shifthackz.aisdv1.presentation.model.InPaintModel
+import com.shifthackz.aisdv1.presentation.model.LaunchSource
import com.shifthackz.aisdv1.presentation.model.Modal
import com.shifthackz.aisdv1.presentation.screen.drawer.DrawerIntent
import com.shifthackz.aisdv1.presentation.screen.inpaint.InPaintStateProducer
-import com.shifthackz.aisdv1.presentation.screen.setup.ServerSetupLaunchSource
import io.mockk.every
import io.mockk.mockk
import io.mockk.unmockkAll
@@ -446,7 +446,7 @@ class ImageToImageViewModelTest : CoreGenerationMviViewModelTest() {
+
+ private var source = LaunchSource.SPLASH
+
+ private val stubMainRouter = mockk()
+ private val stubSplashNavigationUseCase = mockk()
+ private val stubPreferenceManager = mockk()
+
+ override val testViewModelStrategy = CoreViewModelInitializeStrategy.InitializeEveryTime
+
+ override fun initializeViewModel() = OnBoardingViewModel(
+ source,
+ stubMainRouter,
+ stubSplashNavigationUseCase,
+ stubPreferenceManager,
+ stubSchedulersProvider,
+ )
+
+ @Before
+ override fun initialize() {
+ super.initialize()
+
+ every {
+ stubPreferenceManager::designDarkThemeToken.get()
+ } returns DarkThemeToken.FRAPPE.toString()
+
+ every {
+ stubPreferenceManager::onBoardingComplete.set(any())
+ } returns Unit
+
+ every {
+ stubPreferenceManager::onBoardingComplete.get()
+ } returns true
+ }
+
+ @Test
+ fun `given received Navigate intent, expected onBoardingComplete updated in preference, navigation processed`() {
+ source = LaunchSource.SPLASH
+
+ every {
+ stubSplashNavigationUseCase()
+ } returns Single.just(SplashNavigationUseCase.Action.LAUNCH_HOME)
+
+ viewModel.processIntent(OnBoardingIntent.Navigate)
+
+ verify {
+ stubMainRouter.navigateToPostSplashConfigLoader()
+ }
+ }
+
+ @Test
+ fun `given received Navigate intent, expected onBoardingComplete updated in preference, navigateBack processed`() {
+ source = LaunchSource.SETTINGS
+
+ every {
+ stubMainRouter.navigateBack()
+ } returns Unit
+
+ viewModel.processIntent(OnBoardingIntent.Navigate)
+
+ verify {
+ stubMainRouter.navigateBack()
+ }
+ }
+}
diff --git a/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsViewModelTest.kt b/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsViewModelTest.kt
index 5aa56c54..00f18879 100644
--- a/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsViewModelTest.kt
+++ b/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/settings/SettingsViewModelTest.kt
@@ -13,11 +13,11 @@ import com.shifthackz.aisdv1.domain.usecase.sdmodel.SelectStableDiffusionModelUs
import com.shifthackz.aisdv1.domain.usecase.stabilityai.ObserveStabilityAiCreditsUseCase
import com.shifthackz.aisdv1.presentation.core.CoreViewModelTest
import com.shifthackz.aisdv1.presentation.mocks.mockStableDiffusionModels
+import com.shifthackz.aisdv1.presentation.model.LaunchSource
import com.shifthackz.aisdv1.presentation.model.Modal
import com.shifthackz.aisdv1.presentation.navigation.router.drawer.DrawerRouter
import com.shifthackz.aisdv1.presentation.navigation.router.main.MainRouter
import com.shifthackz.aisdv1.presentation.screen.debug.DebugMenuAccessor
-import com.shifthackz.aisdv1.presentation.screen.setup.ServerSetupLaunchSource
import com.shifthackz.aisdv1.presentation.stub.stubSchedulersProvider
import io.mockk.every
import io.mockk.mockk
@@ -161,7 +161,7 @@ class SettingsViewModelTest : CoreViewModelTest() {
viewModel.processIntent(SettingsIntent.NavigateConfiguration)
verify {
- stubMainRouter.navigateToServerSetup(ServerSetupLaunchSource.SETTINGS)
+ stubMainRouter.navigateToServerSetup(LaunchSource.SETTINGS)
}
}
diff --git a/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/setup/ServerSetupViewModelTest.kt b/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/setup/ServerSetupViewModelTest.kt
index 178d0c6a..5c23b4e6 100644
--- a/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/setup/ServerSetupViewModelTest.kt
+++ b/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/setup/ServerSetupViewModelTest.kt
@@ -18,6 +18,7 @@ import com.shifthackz.aisdv1.presentation.core.CoreViewModelTest
import com.shifthackz.aisdv1.presentation.mocks.mockHuggingFaceModels
import com.shifthackz.aisdv1.presentation.mocks.mockLocalAiModels
import com.shifthackz.aisdv1.presentation.mocks.mockServerSetupStateLocalModel
+import com.shifthackz.aisdv1.presentation.model.LaunchSource
import com.shifthackz.aisdv1.presentation.model.Modal
import com.shifthackz.aisdv1.presentation.navigation.router.main.MainRouter
import com.shifthackz.aisdv1.presentation.stub.stubSchedulersProvider
@@ -48,7 +49,7 @@ class ServerSetupViewModelTest : CoreViewModelTest() {
private val stubMainRouter = mockk()
override fun initializeViewModel() = ServerSetupViewModel(
- launchSource = ServerSetupLaunchSource.SETTINGS,
+ launchSource = LaunchSource.SETTINGS,
getConfigurationUseCase = stubGetConfigurationUseCase,
getLocalAiModelsUseCase = stubGetLocalAiModelsUseCase,
fetchAndGetHuggingFaceModelsUseCase = stubFetchAndGetHuggingFaceModelsUseCase,
diff --git a/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/splash/SplashViewModelTest.kt b/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/splash/SplashViewModelTest.kt
index a115c47b..6678f581 100644
--- a/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/splash/SplashViewModelTest.kt
+++ b/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/splash/SplashViewModelTest.kt
@@ -3,8 +3,8 @@ package com.shifthackz.aisdv1.presentation.screen.splash
import com.shifthackz.aisdv1.domain.usecase.splash.SplashNavigationUseCase
import com.shifthackz.aisdv1.presentation.core.CoreViewModelInitializeStrategy
import com.shifthackz.aisdv1.presentation.core.CoreViewModelTest
+import com.shifthackz.aisdv1.presentation.model.LaunchSource
import com.shifthackz.aisdv1.presentation.navigation.router.main.MainRouter
-import com.shifthackz.aisdv1.presentation.screen.setup.ServerSetupLaunchSource
import com.shifthackz.aisdv1.presentation.stub.stubSchedulersProvider
import io.mockk.every
import io.mockk.mockk
@@ -34,7 +34,7 @@ class SplashViewModelTest : CoreViewModelTest() {
viewModel.hashCode()
verify(inverse = true) {
- stubMainRouter.navigateToServerSetup(ServerSetupLaunchSource.SPLASH)
+ stubMainRouter.navigateToServerSetup(LaunchSource.SPLASH)
}
verify(inverse = true) {
stubMainRouter.navigateToPostSplashConfigLoader()
@@ -55,7 +55,7 @@ class SplashViewModelTest : CoreViewModelTest() {
verify {
stubMainRouter.navigateToServerSetup(
- ServerSetupLaunchSource.SPLASH
+ LaunchSource.SPLASH
)
}
}
diff --git a/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/txt2img/TextToImageViewModelTest.kt b/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/txt2img/TextToImageViewModelTest.kt
index 25807412..7846c3a5 100644
--- a/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/txt2img/TextToImageViewModelTest.kt
+++ b/presentation/src/test/java/com/shifthackz/aisdv1/presentation/screen/txt2img/TextToImageViewModelTest.kt
@@ -14,9 +14,9 @@ import com.shifthackz.aisdv1.presentation.core.CoreGenerationMviViewModelTest
import com.shifthackz.aisdv1.presentation.core.GenerationFormUpdateEvent
import com.shifthackz.aisdv1.presentation.core.GenerationMviIntent
import com.shifthackz.aisdv1.presentation.mocks.mockAiGenerationResult
+import com.shifthackz.aisdv1.presentation.model.LaunchSource
import com.shifthackz.aisdv1.presentation.model.Modal
import com.shifthackz.aisdv1.presentation.screen.drawer.DrawerIntent
-import com.shifthackz.aisdv1.presentation.screen.setup.ServerSetupLaunchSource
import io.mockk.every
import io.mockk.mockk
import io.mockk.unmockkAll
@@ -455,7 +455,7 @@ class TextToImageViewModelTest : CoreGenerationMviViewModelTest