Skip to content

Commit a8a8d8f

Browse files
authored
Onboarding UI update (#250)
* Added onboarding form page animation & made other pages animations run only when page is visible for the user * ServerSetupViewModelTest updated * UI update: - Updated splash screen with system colors - Added scroll for onboarding pager - Made Form page animation slightly faster - Updated LookAndFeelPage animation & UI - Updated configuration loader screen with system colors * Updated OnBoardingViewModelSplashSourceTest * Resolved PR comments
1 parent 6d51895 commit a8a8d8f

File tree

15 files changed

+205
-76
lines changed

15 files changed

+205
-76
lines changed

core/ui/src/main/java/com/shifthackz/aisdv1/core/extensions/GestureExtensions.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package com.shifthackz.aisdv1.core.extensions
22

3+
import android.annotation.SuppressLint
34
import androidx.compose.ui.Modifier
45
import androidx.compose.ui.input.pointer.PointerEventPass
56
import androidx.compose.ui.input.pointer.PointerInputChange
67
import androidx.compose.ui.input.pointer.pointerInput
78

9+
@SuppressLint("ReturnFromAwaitPointerEventScope")
810
fun Modifier.gesturesDisabled(disabled: Boolean = true) =
911
if (disabled) {
1012
pointerInput(Unit) {

presentation/src/main/java/com/shifthackz/aisdv1/presentation/di/ViewModelModule.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ val viewModelModule = module {
6161
splashNavigationUseCase = get(),
6262
preferenceManager = get(),
6363
schedulersProvider = get(),
64+
buildInfoProvider = get(),
6465
)
6566
}
6667

presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/loader/ConfigurationLoaderScreen.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import org.koin.androidx.compose.koinViewModel
2626
fun ConfigurationLoaderScreen() {
2727
MviComponent(
2828
viewModel = koinViewModel<ConfigurationLoaderViewModel>(),
29+
navigationBarColor = MaterialTheme.colorScheme.surface,
30+
applySystemUiColors = true,
2931
) { state, _ ->
3032
ScreenContent(
3133
modifier = Modifier.fillMaxSize(),
@@ -40,7 +42,7 @@ private fun ScreenContent(
4042
state: ConfigurationLoaderState,
4143
) {
4244
Box(
43-
modifier = modifier.background(MaterialTheme.colorScheme.background),
45+
modifier = modifier.background(MaterialTheme.colorScheme.surface),
4446
) {
4547
Column(
4648
modifier = Modifier.fillMaxSize(),

presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingScreen.kt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,14 +194,22 @@ private fun OnBoardingScreenContent(
194194
modifier = Modifier.fillMaxSize(),
195195
state = pagerState,
196196
beyondBoundsPageCount = OnBoardingPage.entries.size,
197-
userScrollEnabled = false,
197+
userScrollEnabled = true,
198198
) { index ->
199199
when (OnBoardingPage.entries[index]) {
200-
OnBoardingPage.Form -> FormPageContent()
201-
OnBoardingPage.Providers -> ProviderPageContent()
200+
OnBoardingPage.Providers -> ProviderPageContent(
201+
isPageVisible = pagerState.currentPage == OnBoardingPage.Providers.ordinal
202+
)
203+
204+
OnBoardingPage.Form -> FormPageContent(
205+
isPageVisible = pagerState.currentPage == OnBoardingPage.Form.ordinal
206+
)
207+
202208
OnBoardingPage.LocalDiffusion -> LocalDiffusionPageContent()
203209
OnBoardingPage.LookAndFeel -> LookAndFeelPageContent(
204210
darkThemeToken = state.darkThemeToken,
211+
appVersion = state.appVersion,
212+
isPageVisible = pagerState.currentPage == OnBoardingPage.LookAndFeel.ordinal
205213
)
206214
}
207215
}

presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingState.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ import com.shifthackz.android.core.mvi.MviState
55

66
data class OnBoardingState(
77
val darkThemeToken: DarkThemeToken = DarkThemeToken.FRAPPE,
8+
val appVersion: String = "",
89
) : MviState

presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/OnBoardingViewModel.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.shifthackz.aisdv1.presentation.screen.onboarding
22

3+
import com.shifthackz.aisdv1.core.common.appbuild.BuildInfoProvider
34
import com.shifthackz.aisdv1.core.common.log.errorLog
45
import com.shifthackz.aisdv1.core.common.schedulers.SchedulersProvider
56
import com.shifthackz.aisdv1.core.common.schedulers.subscribeOnMainThread
@@ -19,14 +20,19 @@ class OnBoardingViewModel(
1920
private val splashNavigationUseCase: SplashNavigationUseCase,
2021
private val preferenceManager: PreferenceManager,
2122
private val schedulersProvider: SchedulersProvider,
23+
private val buildInfoProvider: BuildInfoProvider,
2224
) : MviRxViewModel<OnBoardingState, OnBoardingIntent, EmptyEffect>() {
2325

2426
override val initialState = OnBoardingState()
2527

2628
init {
2729
updateState {
2830
val token = DarkThemeToken.parse(preferenceManager.designDarkThemeToken)
29-
it.copy(darkThemeToken = token)
31+
val version = buildInfoProvider.toString()
32+
it.copy(
33+
darkThemeToken = token,
34+
appVersion = version
35+
)
3036
}
3137
}
3238

presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/page/FormPageContent.kt

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,48 @@
11
package com.shifthackz.aisdv1.presentation.screen.onboarding.page
22

3+
import androidx.compose.animation.core.tween
4+
import androidx.compose.foundation.clickable
5+
import androidx.compose.foundation.interaction.MutableInteractionSource
6+
import androidx.compose.foundation.layout.Box
37
import androidx.compose.foundation.layout.Column
48
import androidx.compose.foundation.layout.Spacer
59
import androidx.compose.foundation.layout.aspectRatio
610
import androidx.compose.foundation.layout.fillMaxSize
711
import androidx.compose.foundation.layout.fillMaxWidth
12+
import androidx.compose.foundation.rememberScrollState
813
import androidx.compose.material3.Text
914
import androidx.compose.runtime.Composable
1015
import androidx.compose.runtime.CompositionLocalProvider
16+
import androidx.compose.runtime.DisposableEffect
17+
import androidx.compose.runtime.remember
18+
import androidx.compose.runtime.rememberCoroutineScope
1119
import androidx.compose.ui.Alignment
1220
import androidx.compose.ui.Modifier
1321
import androidx.compose.ui.platform.LocalDensity
1422
import androidx.compose.ui.text.style.TextAlign
1523
import androidx.compose.ui.unit.sp
16-
import com.shifthackz.aisdv1.core.extensions.gesturesDisabled
24+
import com.shifthackz.aisdv1.core.common.extensions.EmptyLambda
1725
import com.shifthackz.aisdv1.presentation.screen.onboarding.buildOnBoardingText
1826
import com.shifthackz.aisdv1.presentation.screen.onboarding.onBoardingDensity
1927
import com.shifthackz.aisdv1.presentation.screen.onboarding.onBoardingPhoneAspectRatio
2028
import com.shifthackz.aisdv1.presentation.screen.onboarding.onBoardingPhoneWidthFraction
2129
import com.shifthackz.aisdv1.presentation.screen.txt2img.TextToImageScreenContent
2230
import com.shifthackz.aisdv1.presentation.screen.txt2img.TextToImageState
2331
import com.shifthackz.aisdv1.presentation.widget.frame.PhoneFrame
32+
import kotlinx.coroutines.delay
33+
import kotlinx.coroutines.launch
2434
import com.shifthackz.aisdv1.core.localization.R as LocalizationR
2535

2636
@Composable
2737
fun FormPageContent(
2838
modifier: Modifier = Modifier,
39+
isPageVisible: Boolean = false,
2940
) = Column(
3041
modifier = modifier.fillMaxSize(),
3142
horizontalAlignment = Alignment.CenterHorizontally,
3243
) {
44+
val scope = rememberCoroutineScope()
45+
val scrollState = rememberScrollState()
3346
Spacer(modifier = Modifier.weight(1f))
3447
Text(
3548
text = buildOnBoardingText(LocalizationR.string.on_boarding_page_form_title),
@@ -42,9 +55,7 @@ fun FormPageContent(
4255
) {
4356
CompositionLocalProvider(LocalDensity provides onBoardingDensity) {
4457
TextToImageScreenContent(
45-
modifier = Modifier
46-
.gesturesDisabled()
47-
.aspectRatio(onBoardingPhoneAspectRatio),
58+
modifier = Modifier.aspectRatio(onBoardingPhoneAspectRatio),
4859
state = TextToImageState(
4960
onBoardingDemo = true,
5061
advancedToggleButtonVisible = false,
@@ -58,8 +69,33 @@ fun FormPageContent(
5869
subSeed = "151297",
5970
subSeedStrength = 0.69f,
6071
),
72+
scrollState = scrollState,
73+
)
74+
Box(
75+
modifier = Modifier
76+
.aspectRatio(onBoardingPhoneAspectRatio)
77+
.clickable(
78+
indication = null,
79+
interactionSource = remember { MutableInteractionSource() },
80+
onClick = EmptyLambda
81+
),
6182
)
6283
}
6384
}
6485
Spacer(modifier = Modifier.weight(1f))
86+
DisposableEffect(isPageVisible) {
87+
val job = scope.launch {
88+
while (isPageVisible) {
89+
scrollState.scrollTo(0)
90+
delay(2000)
91+
scrollState.animateScrollTo(scrollState.maxValue / 2 + 60, tween(2000))
92+
delay(1000)
93+
scrollState.animateScrollTo(scrollState.maxValue, tween(2000))
94+
delay(1000)
95+
}
96+
}
97+
onDispose {
98+
job.cancel()
99+
}
100+
}
65101
}

presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/page/LocalDiffusionPageContent.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.shifthackz.aisdv1.presentation.screen.onboarding.page
22

33
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.clickable
5+
import androidx.compose.foundation.interaction.MutableInteractionSource
46
import androidx.compose.foundation.layout.Box
57
import androidx.compose.foundation.layout.Column
68
import androidx.compose.foundation.layout.Spacer
@@ -10,14 +12,15 @@ import androidx.compose.foundation.layout.fillMaxWidth
1012
import androidx.compose.material3.Text
1113
import androidx.compose.runtime.Composable
1214
import androidx.compose.runtime.CompositionLocalProvider
15+
import androidx.compose.runtime.remember
1316
import androidx.compose.ui.Alignment
1417
import androidx.compose.ui.Modifier
1518
import androidx.compose.ui.graphics.Color
1619
import androidx.compose.ui.platform.LocalDensity
1720
import androidx.compose.ui.text.font.FontWeight
1821
import androidx.compose.ui.text.style.TextAlign
1922
import androidx.compose.ui.unit.sp
20-
import com.shifthackz.aisdv1.core.extensions.gesturesDisabled
23+
import com.shifthackz.aisdv1.core.common.extensions.EmptyLambda
2124
import com.shifthackz.aisdv1.domain.entity.ServerSource
2225
import com.shifthackz.aisdv1.presentation.screen.onboarding.buildOnBoardingText
2326
import com.shifthackz.aisdv1.presentation.screen.onboarding.onBoardingDensity
@@ -49,7 +52,6 @@ fun LocalDiffusionPageContent(
4952
) {
5053
CompositionLocalProvider(LocalDensity provides onBoardingDensity) {
5154
val localModifier = Modifier
52-
.gesturesDisabled()
5355
.aspectRatio(onBoardingPhoneAspectRatio)
5456
Box(
5557
contentAlignment = Alignment.Center,
@@ -70,7 +72,12 @@ fun LocalDiffusionPageContent(
7072
Box(
7173
modifier = localModifier
7274
.fillMaxWidth()
73-
.background(Color.Black.copy(alpha = 0.7f)),
75+
.background(Color.Black.copy(alpha = 0.7f))
76+
.clickable(
77+
indication = null,
78+
interactionSource = remember { MutableInteractionSource() },
79+
onClick = EmptyLambda
80+
),
7481
contentAlignment = Alignment.Center,
7582
) {
7683
Box(

presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/page/LookAndFeelPageContent.kt

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.shifthackz.aisdv1.presentation.screen.onboarding.page
22

3+
import androidx.compose.foundation.clickable
4+
import androidx.compose.foundation.interaction.MutableInteractionSource
5+
import androidx.compose.foundation.layout.Box
36
import androidx.compose.foundation.layout.Column
47
import androidx.compose.foundation.layout.Spacer
58
import androidx.compose.foundation.layout.aspectRatio
@@ -20,9 +23,10 @@ import androidx.compose.ui.platform.LocalDensity
2023
import androidx.compose.ui.text.font.FontWeight
2124
import androidx.compose.ui.text.style.TextAlign
2225
import androidx.compose.ui.unit.sp
23-
import com.shifthackz.aisdv1.core.extensions.gesturesDisabled
26+
import com.shifthackz.aisdv1.core.common.extensions.EmptyLambda
2427
import com.shifthackz.aisdv1.domain.entity.ColorToken
2528
import com.shifthackz.aisdv1.domain.entity.DarkThemeToken
29+
import com.shifthackz.aisdv1.domain.entity.Grid
2630
import com.shifthackz.aisdv1.presentation.screen.onboarding.buildOnBoardingText
2731
import com.shifthackz.aisdv1.presentation.screen.onboarding.onBoardingDensity
2832
import com.shifthackz.aisdv1.presentation.screen.onboarding.onBoardingPhoneAspectRatio
@@ -41,6 +45,8 @@ import com.shifthackz.aisdv1.core.localization.R as LocalizationR
4145
fun LookAndFeelPageContent(
4246
modifier: Modifier = Modifier,
4347
darkThemeToken: DarkThemeToken,
48+
appVersion: String,
49+
isPageVisible: Boolean = false,
4450
) = Column(
4551
modifier = modifier.fillMaxSize(),
4652
horizontalAlignment = Alignment.CenterHorizontally,
@@ -57,6 +63,18 @@ fun LookAndFeelPageContent(
5763
),
5864
)
5965
}
66+
var settingsState by remember {
67+
mutableStateOf(
68+
SettingsState(
69+
loading = false,
70+
onBoardingDemo = true,
71+
colorToken = themeState.colorToken,
72+
darkThemeToken = themeState.darkThemeToken,
73+
darkTheme = darkTheme,
74+
appVersion = appVersion
75+
),
76+
)
77+
}
6078
Spacer(modifier = Modifier.weight(1f))
6179
Text(
6280
text = buildOnBoardingText(LocalizationR.string.on_boarding_page_ui_title),
@@ -71,26 +89,35 @@ fun LookAndFeelPageContent(
7189
CompositionLocalProvider(LocalDensity provides onBoardingDensity) {
7290
AiSdAppTheme(themeState) {
7391
SettingsScreenContent(
92+
modifier = Modifier.aspectRatio(onBoardingPhoneAspectRatio),
93+
state = settingsState,
94+
)
95+
Box(
7496
modifier = Modifier
75-
.gesturesDisabled()
76-
.aspectRatio(onBoardingPhoneAspectRatio),
77-
state = SettingsState(
78-
loading = false,
79-
onBoardingDemo = true,
80-
colorToken = themeState.colorToken,
81-
darkThemeToken = darkThemeToken,
82-
darkTheme = darkTheme,
83-
),
97+
.aspectRatio(onBoardingPhoneAspectRatio)
98+
.clickable(
99+
indication = null,
100+
interactionSource = remember { MutableInteractionSource() },
101+
onClick = EmptyLambda
102+
),
84103
)
85104
}
86105
}
87106
}
88-
DisposableEffect(Unit) {
107+
DisposableEffect(isPageVisible) {
89108
val job = scope.launch {
90-
while (true) {
109+
while (isPageVisible) {
91110
delay(700)
111+
val darkThemeTokenRnd = DarkThemeToken.entries.random()
112+
val colorTokenRnd = ColorToken.entries.random()
113+
settingsState = settingsState.copy(
114+
galleryGrid = Grid.entries.random(),
115+
darkThemeToken = darkThemeTokenRnd,
116+
colorToken = colorTokenRnd,
117+
)
92118
themeState = themeState.copy(
93-
colorToken = ColorToken.entries.random(),
119+
darkThemeToken = darkThemeTokenRnd,
120+
colorToken = colorTokenRnd,
94121
)
95122
}
96123
}

presentation/src/main/java/com/shifthackz/aisdv1/presentation/screen/onboarding/page/ProvidersPageContent.kt

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.shifthackz.aisdv1.presentation.screen.onboarding.page
22

3+
import androidx.compose.foundation.clickable
4+
import androidx.compose.foundation.interaction.MutableInteractionSource
5+
import androidx.compose.foundation.layout.Box
36
import androidx.compose.foundation.layout.Column
47
import androidx.compose.foundation.layout.Spacer
58
import androidx.compose.foundation.layout.aspectRatio
@@ -20,7 +23,7 @@ import androidx.compose.ui.platform.LocalDensity
2023
import androidx.compose.ui.text.font.FontWeight
2124
import androidx.compose.ui.text.style.TextAlign
2225
import androidx.compose.ui.unit.sp
23-
import com.shifthackz.aisdv1.core.extensions.gesturesDisabled
26+
import com.shifthackz.aisdv1.core.common.extensions.EmptyLambda
2427
import com.shifthackz.aisdv1.domain.entity.ServerSource
2528
import com.shifthackz.aisdv1.presentation.screen.onboarding.buildOnBoardingText
2629
import com.shifthackz.aisdv1.presentation.screen.onboarding.onBoardingDensity
@@ -36,6 +39,7 @@ import com.shifthackz.aisdv1.core.localization.R as LocalizationR
3639
@Composable
3740
fun ProviderPageContent(
3841
modifier: Modifier = Modifier,
42+
isPageVisible: Boolean = false,
3943
) = Column(
4044
modifier = modifier.fillMaxSize(),
4145
horizontalAlignment = Alignment.CenterHorizontally,
@@ -61,17 +65,24 @@ fun ProviderPageContent(
6165
) {
6266
CompositionLocalProvider(LocalDensity provides onBoardingDensity) {
6367
ServerSetupScreenContent(
64-
modifier = Modifier
65-
.gesturesDisabled()
66-
.aspectRatio(onBoardingPhoneAspectRatio),
68+
modifier = Modifier.aspectRatio(onBoardingPhoneAspectRatio),
6769
state = serverState,
6870
)
71+
Box(
72+
modifier = Modifier
73+
.aspectRatio(onBoardingPhoneAspectRatio)
74+
.clickable(
75+
indication = null,
76+
interactionSource = remember { MutableInteractionSource() },
77+
onClick = EmptyLambda
78+
),
79+
)
6980
}
7081
}
7182
Spacer(modifier = Modifier.weight(1f))
72-
DisposableEffect(Unit) {
83+
DisposableEffect(isPageVisible) {
7384
val job = scope.launch {
74-
while (true) {
85+
while (isPageVisible) {
7586
delay(1200)
7687
serverState = serverState.copy(
7788
mode = ServerSource.entries.random(),

0 commit comments

Comments
 (0)