11package dev.abd3lraouf.learn.decompose.features.settings.presentation
22
3+ import androidx.compose.animation.AnimatedVisibility
4+ import androidx.compose.animation.core.animateFloatAsState
5+ import androidx.compose.foundation.background
36import androidx.compose.foundation.clickable
47import androidx.compose.foundation.layout.Arrangement
58import androidx.compose.foundation.layout.Box
69import androidx.compose.foundation.layout.Column
710import androidx.compose.foundation.layout.Row
11+ import androidx.compose.foundation.layout.Spacer
812import androidx.compose.foundation.layout.fillMaxSize
913import androidx.compose.foundation.layout.fillMaxWidth
14+ import androidx.compose.foundation.layout.height
1015import androidx.compose.foundation.layout.padding
16+ import androidx.compose.foundation.layout.size
17+ import androidx.compose.foundation.layout.width
18+ import androidx.compose.foundation.rememberScrollState
19+ import androidx.compose.foundation.shape.CircleShape
20+ import androidx.compose.foundation.verticalScroll
1121import androidx.compose.material3.Card
12- import androidx.compose.material3.DropdownMenu
13- import androidx.compose.material3.DropdownMenuItem
22+ import androidx.compose.material3.CardDefaults
23+ import androidx.compose.material3.Divider
1424import androidx.compose.material3.Icon
1525import androidx.compose.material3.MaterialTheme
1626import androidx.compose.material3.Switch
27+ import androidx.compose.material3.SwitchDefaults
1728import androidx.compose.material3.Text
1829import androidx.compose.runtime.Composable
1930import androidx.compose.runtime.getValue
@@ -22,14 +33,24 @@ import androidx.compose.runtime.remember
2233import androidx.compose.runtime.setValue
2334import androidx.compose.ui.Alignment
2435import androidx.compose.ui.Modifier
36+ import androidx.compose.ui.draw.clip
2537import androidx.compose.ui.draw.rotate
38+ import androidx.compose.ui.graphics.Color
2639import androidx.compose.ui.text.font.FontWeight
2740import androidx.compose.ui.tooling.preview.Preview
2841import androidx.compose.ui.unit.dp
2942import com.arkivanov.decompose.extensions.compose.subscribeAsState
3043import com.woowla.compose.icon.collections.heroicons.Heroicons
44+ import com.woowla.compose.icon.collections.heroicons.heroicons.Outline
3145import com.woowla.compose.icon.collections.heroicons.heroicons.Solid
32- import com.woowla.compose.icon.collections.heroicons.heroicons.solid.ArrowLeft
46+ import com.woowla.compose.icon.collections.heroicons.heroicons.outline.ChevronDown
47+ import com.woowla.compose.icon.collections.heroicons.heroicons.outline.InformationCircle
48+ import com.woowla.compose.icon.collections.heroicons.heroicons.outline.MoonIcon
49+ import com.woowla.compose.icon.collections.heroicons.heroicons.outline.SunIcon
50+ import com.woowla.compose.icon.collections.heroicons.heroicons.solid.Cog
51+ import com.woowla.compose.icon.collections.heroicons.heroicons.solid.Document
52+ import com.woowla.compose.icon.collections.heroicons.heroicons.solid.Heart
53+ import com.woowla.compose.icon.collections.heroicons.heroicons.solid.ShieldCheck
3354import dev.abd3lraouf.learn.decompose.ui.preview.PreviewSettingsComponent
3455import dev.abd3lraouf.learn.decompose.ui.theme.DecomposeTutorialTheme
3556
@@ -39,72 +60,250 @@ fun SettingsContent(
3960 modifier : Modifier = Modifier
4061) {
4162 val settings by component.model.subscribeAsState()
42- var expanded by remember { mutableStateOf( false ) }
63+ val scrollState = rememberScrollState()
4364
4465 Column (
4566 modifier = modifier
4667 .fillMaxSize()
47- .padding(16 .dp),
68+ .padding(16 .dp)
69+ .verticalScroll(scrollState),
4870 verticalArrangement = Arrangement .spacedBy(16 .dp)
4971 ) {
50- Text (
51- text = " Settings" ,
52- style = MaterialTheme .typography.headlineMedium,
53- fontWeight = FontWeight .Bold
54- )
72+ // Header
73+ Row (
74+ modifier = Modifier .fillMaxWidth(),
75+ verticalAlignment = Alignment .CenterVertically
76+ ) {
77+ Box (
78+ modifier = Modifier
79+ .size(48 .dp)
80+ .clip(CircleShape )
81+ .background(MaterialTheme .colorScheme.primaryContainer),
82+ contentAlignment = Alignment .Center
83+ ) {
84+ Icon (
85+ imageVector = Heroicons .Solid .Cog ,
86+ contentDescription = " Settings" ,
87+ tint = MaterialTheme .colorScheme.onPrimaryContainer,
88+ modifier = Modifier .size(24 .dp)
89+ )
90+ }
91+ Spacer (modifier = Modifier .width(16 .dp))
92+ Text (
93+ text = " Settings" ,
94+ style = MaterialTheme .typography.headlineMedium,
95+ fontWeight = FontWeight .Bold
96+ )
97+ }
5598
56- Card (
57- modifier = Modifier .fillMaxWidth()
99+ Spacer (modifier = Modifier .height(8 .dp))
100+
101+ // Appearance Card
102+ SettingsCard (
103+ title = " Appearance" ,
104+ icon = Heroicons .Outline .SunIcon ,
105+ iconTint = Color (0xFFFFA000 ) // Amber
58106 ) {
59- Column (
107+ Row (
60108 modifier = Modifier
61109 .fillMaxWidth()
62- .padding(16 .dp),
63- verticalArrangement = Arrangement .spacedBy(16 .dp)
110+ .padding(vertical = 8 .dp),
111+ horizontalArrangement = Arrangement .SpaceBetween ,
112+ verticalAlignment = Alignment .CenterVertically
64113 ) {
65- Text (
66- text = " Appearance" ,
67- style = MaterialTheme .typography.titleMedium,
68- fontWeight = FontWeight .Bold
69- )
70-
71114 Row (
72- modifier = Modifier .fillMaxWidth(),
73- horizontalArrangement = Arrangement .SpaceBetween ,
74115 verticalAlignment = Alignment .CenterVertically
75116 ) {
76- Text (" Dark Mode" )
77- Switch (
78- checked = settings.isDarkMode,
79- onCheckedChange = { component.onThemeChanged(it) }
117+ Icon (
118+ imageVector = if (settings.isDarkMode) Heroicons .Outline .MoonIcon else Heroicons .Outline .SunIcon ,
119+ contentDescription = " Theme" ,
120+ tint = MaterialTheme .colorScheme.onSurfaceVariant,
121+ modifier = Modifier .size(20 .dp)
122+ )
123+ Spacer (modifier = Modifier .width(12 .dp))
124+ Text (
125+ text = if (settings.isDarkMode) " Dark Mode" else " Light Mode" ,
126+ style = MaterialTheme .typography.bodyLarge
80127 )
81128 }
129+
130+ Switch (
131+ checked = settings.isDarkMode,
132+ onCheckedChange = { component.onThemeChanged(it) },
133+ thumbContent = if (settings.isDarkMode) {
134+ {
135+ Icon (
136+ imageVector = Heroicons .Outline .MoonIcon ,
137+ contentDescription = null ,
138+ modifier = Modifier .size(SwitchDefaults .IconSize )
139+ )
140+ }
141+ } else {
142+ {
143+ Icon (
144+ imageVector = Heroicons .Outline .SunIcon ,
145+ contentDescription = null ,
146+ modifier = Modifier .size(SwitchDefaults .IconSize )
147+ )
148+ }
149+ }
150+ )
82151 }
83152 }
84153
85- Card (
86- modifier = Modifier .fillMaxWidth()
154+ // Help & Support
155+ SettingsCard (
156+ title = " Help & Support" ,
157+ icon = Heroicons .Outline .InformationCircle ,
158+ iconTint = MaterialTheme .colorScheme.primary
87159 ) {
88- Column (
89- modifier = Modifier
90- .fillMaxWidth()
91- .padding(16 .dp),
92- verticalArrangement = Arrangement .spacedBy(8 .dp)
93- ) {
94- Text (
95- text = " About" ,
96- style = MaterialTheme .typography.titleMedium,
97- fontWeight = FontWeight .Bold
98- )
99-
100- Text (
101- text = " Decompose Tutorial App v1.0" ,
102- style = MaterialTheme .typography.bodyMedium
160+ SettingsItem (
161+ icon = Heroicons .Solid .Document ,
162+ title = " Documentation" ,
163+ subtitle = " Learn how to use this app" ,
164+ onClick = { /* Open documentation */ }
165+ )
166+
167+ Divider (modifier = Modifier .padding(vertical = 8 .dp))
168+
169+ SettingsItem (
170+ icon = Heroicons .Solid .Heart ,
171+ title = " Rate the App" ,
172+ subtitle = " Let us know what you think" ,
173+ onClick = { /* Open rating */ }
174+ )
175+ }
176+
177+ // About Card
178+ var showAboutDetails by remember { mutableStateOf(false ) }
179+ val rotationState by animateFloatAsState(
180+ targetValue = if (showAboutDetails) 180f else 0f ,
181+ label = " Rotation Animation"
182+ )
183+
184+ SettingsCard (
185+ title = " About" ,
186+ icon = Heroicons .Solid .ShieldCheck ,
187+ iconTint = Color (0xFF4CAF50 ), // Green
188+ titleTrailingContent = {
189+ Icon (
190+ imageVector = Heroicons .Outline .ChevronDown ,
191+ contentDescription = " Expand" ,
192+ modifier = Modifier
193+ .rotate(rotationState)
194+ .clickable { showAboutDetails = ! showAboutDetails }
103195 )
196+ }
197+ ) {
198+ Text (
199+ text = " Decompose Tutorial App v1.0" ,
200+ style = MaterialTheme .typography.bodyMedium,
201+ fontWeight = FontWeight .Medium
202+ )
203+
204+ AnimatedVisibility (visible = showAboutDetails) {
205+ Column (modifier = Modifier .padding(top = 8 .dp)) {
206+ Text (
207+ text = " This app demonstrates the capabilities of the Decompose library for navigation and state management in Jetpack Compose applications." ,
208+ style = MaterialTheme .typography.bodyMedium
209+ )
210+
211+ Spacer (modifier = Modifier .height(8 .dp))
212+
213+ Text (
214+ text = " Developed by Abdelraouf Sabri" ,
215+ style = MaterialTheme .typography.bodySmall
216+ )
217+
218+ Text (
219+ text = " © 2023 abd3lraouf.dev" ,
220+ style = MaterialTheme .typography.bodySmall
221+ )
222+ }
223+ }
224+ }
225+ }
226+ }
227+
228+ @Composable
229+ fun SettingsCard (
230+ title : String ,
231+ icon : Any ,
232+ iconTint : Color = MaterialTheme .colorScheme.primary,
233+ titleTrailingContent : @Composable (() -> Unit )? = null,
234+ content : @Composable () -> Unit
235+ ) {
236+ Card (
237+ modifier = Modifier .fillMaxWidth(),
238+ elevation = CardDefaults .cardElevation(defaultElevation = 2 .dp)
239+ ) {
240+ Column (
241+ modifier = Modifier
242+ .fillMaxWidth()
243+ .padding(16 .dp),
244+ verticalArrangement = Arrangement .spacedBy(12 .dp)
245+ ) {
246+ Row (
247+ modifier = Modifier .fillMaxWidth(),
248+ verticalAlignment = Alignment .CenterVertically ,
249+ horizontalArrangement = Arrangement .SpaceBetween
250+ ) {
251+ Row (verticalAlignment = Alignment .CenterVertically ) {
252+ Icon (
253+ imageVector = icon as androidx.compose.ui.graphics.vector.ImageVector ,
254+ contentDescription = null ,
255+ tint = iconTint,
256+ modifier = Modifier .size(24 .dp)
257+ )
258+ Spacer (modifier = Modifier .width(12 .dp))
259+ Text (
260+ text = title,
261+ style = MaterialTheme .typography.titleMedium,
262+ fontWeight = FontWeight .Bold
263+ )
264+ }
104265
266+ if (titleTrailingContent != null ) {
267+ titleTrailingContent()
268+ }
269+ }
270+
271+ content()
272+ }
273+ }
274+ }
275+
276+ @Composable
277+ fun SettingsItem (
278+ icon : Any ,
279+ title : String ,
280+ subtitle : String? = null,
281+ onClick : () -> Unit
282+ ) {
283+ Row (
284+ modifier = Modifier
285+ .fillMaxWidth()
286+ .clickable(onClick = onClick)
287+ .padding(vertical = 8 .dp),
288+ verticalAlignment = Alignment .CenterVertically
289+ ) {
290+ Icon (
291+ imageVector = icon as androidx.compose.ui.graphics.vector.ImageVector ,
292+ contentDescription = null ,
293+ tint = MaterialTheme .colorScheme.onSurfaceVariant,
294+ modifier = Modifier .size(20 .dp)
295+ )
296+ Spacer (modifier = Modifier .width(12 .dp))
297+ Column {
298+ Text (
299+ text = title,
300+ style = MaterialTheme .typography.bodyLarge
301+ )
302+ if (subtitle != null ) {
105303 Text (
106- text = " This app demonstrates the capabilities of the Decompose library for navigation and state management in Jetpack Compose applications." ,
107- style = MaterialTheme .typography.bodySmall
304+ text = subtitle,
305+ style = MaterialTheme .typography.bodySmall,
306+ color = MaterialTheme .colorScheme.onSurfaceVariant
108307 )
109308 }
110309 }
0 commit comments