Skip to content

Commit 63a178a

Browse files
committed
Refactor: Add adaptive layout onboarding screen and update strings
This commit introduces a new onboarding screen, `AdaptiveLayoutPage.kt`, to explain the app's adaptive layout features. It also updates various strings in `strings.xml` for clarity and conciseness, primarily in the onboarding workspace section. The `OnboardingViewModel` and `OnboardingScreen` are updated to include this new page.
1 parent 66e423e commit 63a178a

5 files changed

Lines changed: 238 additions & 8 deletions

File tree

app/src/main/java/eu/darken/butler/main/ui/onboarding/OnboardingScreen.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import eu.darken.butler.common.compose.PreviewWrapper
1717
import eu.darken.butler.common.error.ErrorEventHandler
1818
import eu.darken.butler.common.ui.waitForState
1919
import eu.darken.butler.main.ui.onboarding.OnboardingViewModel.State.*
20+
import eu.darken.butler.main.ui.onboarding.pages.AdaptiveLayoutPage
2021
import eu.darken.butler.main.ui.onboarding.pages.BetaPage
2122
import eu.darken.butler.main.ui.onboarding.pages.PrivacyPage
2223
import eu.darken.butler.main.ui.onboarding.pages.WelcomePage
@@ -79,6 +80,15 @@ private fun OnboardingScreen(
7980
}
8081
)
8182

83+
Page.ADAPTIVE_LAYOUT ->
84+
AdaptiveLayoutPage(
85+
onContinue = {
86+
scope.launch {
87+
pagerState.animateScrollToPage(pagerState.currentPage + 1)
88+
}
89+
}
90+
)
91+
8292
Page.PRIVACY ->
8393
PrivacyPage(
8494
isUpdateCheckEnabled = state.isUpdateCheckEnabled,

app/src/main/java/eu/darken/butler/main/ui/onboarding/OnboardingViewModel.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class OnboardingViewModel @Inject constructor(
7373
WELCOME,
7474
BETA,
7575
WORKSPACES,
76+
ADAPTIVE_LAYOUT,
7677
PRIVACY,
7778
;
7879
}
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
package eu.darken.butler.main.ui.onboarding.pages
2+
3+
import androidx.compose.animation.AnimatedVisibility
4+
import androidx.compose.animation.core.tween
5+
import androidx.compose.animation.fadeIn
6+
import androidx.compose.animation.slideInVertically
7+
import androidx.compose.foundation.layout.Arrangement
8+
import androidx.compose.foundation.layout.Column
9+
import androidx.compose.foundation.layout.Row
10+
import androidx.compose.foundation.layout.Spacer
11+
import androidx.compose.foundation.layout.fillMaxSize
12+
import androidx.compose.foundation.layout.fillMaxWidth
13+
import androidx.compose.foundation.layout.height
14+
import androidx.compose.foundation.layout.padding
15+
import androidx.compose.foundation.layout.size
16+
import androidx.compose.foundation.rememberScrollState
17+
import androidx.compose.foundation.verticalScroll
18+
import androidx.compose.material.icons.Icons
19+
import androidx.compose.material.icons.twotone.Devices
20+
import androidx.compose.material.icons.twotone.PhoneAndroid
21+
import androidx.compose.material.icons.twotone.ScreenRotation
22+
import androidx.compose.material.icons.twotone.TabletAndroid
23+
import androidx.compose.material3.Button
24+
import androidx.compose.material3.Card
25+
import androidx.compose.material3.CardDefaults
26+
import androidx.compose.material3.Icon
27+
import androidx.compose.material3.MaterialTheme
28+
import androidx.compose.material3.Text
29+
import androidx.compose.runtime.Composable
30+
import androidx.compose.runtime.LaunchedEffect
31+
import androidx.compose.runtime.getValue
32+
import androidx.compose.runtime.mutableStateOf
33+
import androidx.compose.runtime.remember
34+
import androidx.compose.runtime.setValue
35+
import androidx.compose.ui.Alignment
36+
import androidx.compose.ui.Modifier
37+
import androidx.compose.ui.graphics.vector.ImageVector
38+
import androidx.compose.ui.res.stringResource
39+
import androidx.compose.ui.text.font.FontWeight
40+
import androidx.compose.ui.text.style.TextAlign
41+
import androidx.compose.ui.unit.dp
42+
import eu.darken.butler.R
43+
import eu.darken.butler.common.compose.Preview2
44+
import eu.darken.butler.common.compose.PreviewWrapper
45+
46+
@Composable
47+
internal fun AdaptiveLayoutPage(
48+
onContinue: () -> Unit = {},
49+
) {
50+
var isVisible by remember { mutableStateOf(false) }
51+
52+
LaunchedEffect(Unit) {
53+
isVisible = true
54+
}
55+
56+
Column(
57+
modifier = Modifier
58+
.fillMaxSize()
59+
.padding(32.dp)
60+
) {
61+
AnimatedVisibility(
62+
visible = isVisible,
63+
enter = fadeIn(
64+
animationSpec = tween(400)
65+
) + slideInVertically(
66+
initialOffsetY = { 30 },
67+
animationSpec = tween(400)
68+
),
69+
modifier = Modifier.weight(1f)
70+
) {
71+
Column(
72+
modifier = Modifier
73+
.fillMaxWidth()
74+
.verticalScroll(rememberScrollState()),
75+
horizontalAlignment = Alignment.CenterHorizontally,
76+
verticalArrangement = Arrangement.Center
77+
) {
78+
Icon(
79+
imageVector = Icons.TwoTone.Devices,
80+
contentDescription = null,
81+
modifier = Modifier.size(72.dp),
82+
tint = MaterialTheme.colorScheme.primary
83+
)
84+
85+
Spacer(modifier = Modifier.height(24.dp))
86+
87+
Text(
88+
text = stringResource(R.string.onboarding_adaptive_title),
89+
style = MaterialTheme.typography.headlineMedium,
90+
fontWeight = FontWeight.Bold,
91+
textAlign = TextAlign.Center,
92+
color = MaterialTheme.colorScheme.onSurface,
93+
)
94+
95+
Spacer(modifier = Modifier.height(16.dp))
96+
97+
Text(
98+
text = stringResource(R.string.onboarding_adaptive_message),
99+
style = MaterialTheme.typography.bodyLarge,
100+
textAlign = TextAlign.Center,
101+
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.8f),
102+
)
103+
104+
Spacer(modifier = Modifier.height(32.dp))
105+
106+
Column(
107+
modifier = Modifier.fillMaxWidth(),
108+
verticalArrangement = Arrangement.spacedBy(12.dp)
109+
) {
110+
AdaptiveFeatureCard(
111+
icon = Icons.TwoTone.PhoneAndroid,
112+
title = stringResource(R.string.onboarding_adaptive_phone_title),
113+
description = stringResource(R.string.onboarding_adaptive_phone_description)
114+
)
115+
116+
AdaptiveFeatureCard(
117+
icon = Icons.TwoTone.ScreenRotation,
118+
title = stringResource(R.string.onboarding_adaptive_landscape_title),
119+
description = stringResource(R.string.onboarding_adaptive_landscape_description)
120+
)
121+
122+
AdaptiveFeatureCard(
123+
icon = Icons.TwoTone.TabletAndroid,
124+
title = stringResource(R.string.onboarding_adaptive_tablet_title),
125+
description = stringResource(R.string.onboarding_adaptive_tablet_description)
126+
)
127+
}
128+
129+
Spacer(modifier = Modifier.height(24.dp))
130+
}
131+
}
132+
133+
AnimatedVisibility(
134+
visible = isVisible,
135+
enter = fadeIn(
136+
animationSpec = tween(
137+
durationMillis = 400,
138+
delayMillis = 200
139+
)
140+
)
141+
) {
142+
Button(
143+
onClick = onContinue,
144+
modifier = Modifier.fillMaxWidth()
145+
) {
146+
Text(text = stringResource(R.string.onboarding_adaptive_action))
147+
}
148+
}
149+
}
150+
}
151+
152+
@Composable
153+
private fun AdaptiveFeatureCard(
154+
icon: ImageVector,
155+
title: String,
156+
description: String,
157+
modifier: Modifier = Modifier
158+
) {
159+
Card(
160+
modifier = modifier.fillMaxWidth(),
161+
colors = CardDefaults.cardColors(
162+
containerColor = MaterialTheme.colorScheme.surfaceVariant
163+
)
164+
) {
165+
Row(
166+
modifier = Modifier
167+
.padding(16.dp)
168+
.fillMaxWidth(),
169+
verticalAlignment = Alignment.CenterVertically,
170+
horizontalArrangement = Arrangement.Start
171+
) {
172+
Icon(
173+
imageVector = icon,
174+
contentDescription = null,
175+
modifier = Modifier.size(40.dp),
176+
tint = MaterialTheme.colorScheme.primary
177+
)
178+
179+
Column(
180+
modifier = Modifier
181+
.weight(1f)
182+
.padding(start = 16.dp)
183+
) {
184+
Text(
185+
text = title,
186+
style = MaterialTheme.typography.titleSmall,
187+
fontWeight = FontWeight.Bold,
188+
color = MaterialTheme.colorScheme.onSurface
189+
)
190+
Spacer(modifier = Modifier.height(4.dp))
191+
Text(
192+
text = description,
193+
style = MaterialTheme.typography.bodySmall,
194+
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f)
195+
)
196+
}
197+
}
198+
}
199+
}
200+
201+
@Preview2
202+
@Composable
203+
private fun AdaptiveLayoutPagePreview() {
204+
PreviewWrapper {
205+
AdaptiveLayoutPage()
206+
}
207+
}

app/src/main/java/eu/darken/butler/main/ui/onboarding/pages/WorkspacesPage.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,9 @@ internal fun WorkspacesPage(
148148
style = MaterialTheme.typography.bodyMedium,
149149
textAlign = TextAlign.Center,
150150
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f),
151-
modifier = Modifier.padding(16.dp)
151+
modifier = Modifier
152+
.fillMaxWidth()
153+
.padding(16.dp)
152154
)
153155
}
154156

app/src/main/res/values/strings.xml

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,28 @@
1010
<string name="onboarding_privacy_read_action">Read Privacy Policy</string>
1111
<string name="onboarding_privacy_action">Accept</string>
1212

13-
<string name="onboarding_workspaces_title">Your Workspace</string>
14-
<string name="onboarding_workspaces_message">Butler organizes your work into specialized workspaces</string>
13+
<string name="onboarding_workspaces_title">Work in Tabs</string>
14+
<string name="onboarding_workspaces_message">Open multiple tabs and switch between them - just like your web browser</string>
1515
<string name="onboarding_workspaces_action">Continue</string>
16-
<string name="onboarding_workspaces_hint">💡 Swipe between workspaces like browser tabs</string>
16+
<string name="onboarding_workspaces_hint"> Swipe to switch tabs</string>
1717
<string name="onboarding_workspaces_explorer_title">Explorer</string>
18-
<string name="onboarding_workspaces_explorer_description">Browse and manage files</string>
18+
<string name="onboarding_workspaces_explorer_description">Browse your files</string>
1919
<string name="onboarding_workspaces_searcher_title">Searcher</string>
20-
<string name="onboarding_workspaces_searcher_description">Find files quickly</string>
20+
<string name="onboarding_workspaces_searcher_description">Find stuff</string>
2121
<string name="onboarding_workspaces_editor_title">Editor</string>
22-
<string name="onboarding_workspaces_editor_description">View and edit text files</string>
22+
<string name="onboarding_workspaces_editor_description">Edit files</string>
2323
<string name="onboarding_workspaces_templates_title">Templates</string>
24-
<string name="onboarding_workspaces_templates_description">Save workspace setups</string>
24+
<string name="onboarding_workspaces_templates_description">Save your setup</string>
25+
26+
<string name="onboarding_adaptive_title">Fits Any Screen</string>
27+
<string name="onboarding_adaptive_message">Butler adapts to your device for the best experience</string>
28+
<string name="onboarding_adaptive_action">Continue</string>
29+
<string name="onboarding_adaptive_phone_title">Phone</string>
30+
<string name="onboarding_adaptive_phone_description">Full-screen tabs on your phone</string>
31+
<string name="onboarding_adaptive_landscape_title">Landscape</string>
32+
<string name="onboarding_adaptive_landscape_description">See more content when you rotate</string>
33+
<string name="onboarding_adaptive_tablet_title">Tablet</string>
34+
<string name="onboarding_adaptive_tablet_description">Multiple panels side by side</string>
2535

2636
<string name="setup_usagestats_title">Usage stats</string>
2737
<string name="setup_shizuku_card_title">Shizuku</string>

0 commit comments

Comments
 (0)