11package com.konyaco.fluent.example
22
3- import androidx.compose.foundation.*
4- import androidx.compose.foundation.layout.*
5- import androidx.compose.foundation.shape.RoundedCornerShape
3+ import androidx.compose.animation.*
4+ import androidx.compose.animation.core.tween
5+ import androidx.compose.foundation.isSystemInDarkTheme
6+ import androidx.compose.foundation.layout.Row
7+ import androidx.compose.foundation.layout.fillMaxHeight
8+ import androidx.compose.foundation.layout.fillMaxSize
69import androidx.compose.runtime.*
7- import androidx.compose.ui.Alignment
810import androidx.compose.ui.Modifier
9- import androidx.compose.ui.platform.LocalDensity
10- import androidx.compose.ui.text.input.TextFieldValue
11- import androidx.compose.ui.unit.Density
12- import androidx.compose.ui.unit.dp
11+ import androidx.compose.ui.graphics.vector.ImageVector
1312import com.konyaco.fluent.FluentTheme
14- import com.konyaco.fluent.LocalContentColor
15- import com.konyaco.fluent.background.Layer
13+ import com.konyaco.fluent.animation.FluentDuration
14+ import com.konyaco.fluent.animation.FluentEasing
1615import com.konyaco.fluent.background.Mica
17- import com.konyaco.fluent.component.*
16+ import com.konyaco.fluent.component.Icon
17+ import com.konyaco.fluent.component.SideNav
18+ import com.konyaco.fluent.component.SideNavItem
19+ import com.konyaco.fluent.component.Text
1820import com.konyaco.fluent.darkColors
19- import com.konyaco.fluent.lightColors
21+ import com.konyaco.fluent.example.screen.HomeScreen
22+ import com.konyaco.fluent.example.screen.TodoScreen
2023import com.konyaco.fluent.icons.Icons
2124import com.konyaco.fluent.icons.regular.*
25+ import com.konyaco.fluent.lightColors
26+
27+ private data class NavItem (
28+ val label : String ,
29+ val icon : ImageVector ,
30+ val content : @Composable () -> Unit
31+ )
32+
33+ private val navs = listOf (
34+ NavItem (" Home" , Icons .Default .Home ) { HomeScreen () },
35+ NavItem (" Design guidance" , Icons .Default .Ruler ) { TodoScreen () },
36+ NavItem (" All samples" , Icons .Default .AppsList ) { TodoScreen () },
37+ NavItem (" Basic input" , Icons .Default .CheckboxChecked ) { TodoScreen () },
38+ NavItem (" Collections" , Icons .Default .Table ) { TodoScreen () },
39+ NavItem (" Date & time" , Icons .Default .CalendarClock ) { TodoScreen () },
40+ NavItem (" Dialogs & flyouts" , Icons .Default .Chat ) { TodoScreen () },
41+ NavItem (" Layout" , Icons .Default .SlideLayout ) { TodoScreen () },
42+ NavItem (" Media" , Icons .Default .VideoClip ) { TodoScreen () },
43+ NavItem (" Menus & toolbars" , Icons .Default .Save ) { TodoScreen () },
44+ NavItem (" Motion" , Icons .Default .Flash ) { TodoScreen () },
45+ NavItem (" Navigation" , Icons .Default .Navigation ) { TodoScreen () },
46+ NavItem (" Scrolling" , Icons .Default .ArrowSort ) { TodoScreen () },
47+ NavItem (" Status & info" , Icons .Default .ChatMultiple ) { TodoScreen () },
48+ NavItem (" Styles" , Icons .Default .Color ) { TodoScreen () },
49+ NavItem (" System" , Icons .Default .System ) { TodoScreen () },
50+ NavItem (" Text" , Icons .Default .TextFont ) { TodoScreen () },
51+ NavItem (" Windowing" , Icons .Default .Window ) { TodoScreen () },
52+ )
53+
54+
55+ internal val LocalStore = compositionLocalOf<Store > { error(" Not provided" ) }
56+ class Store (
57+ systemDarkMode : Boolean
58+ ) {
59+ var darkMode by mutableStateOf(systemDarkMode)
60+ }
2261
62+ @OptIn(ExperimentalAnimationApi ::class )
2363@Composable
2464fun App () {
2565 val systemDarkMode = isSystemInDarkTheme()
26- var darkMode by remember(systemDarkMode) { mutableStateOf(systemDarkMode) }
27- var displayDialog by remember { mutableStateOf(false ) }
28-
29- FluentTheme (colors = if (darkMode) darkColors() else lightColors()) {
30- Mica (Modifier .fillMaxSize().verticalScroll(rememberScrollState()).horizontalScroll(rememberScrollState())) {
31- val density = LocalDensity .current
32- var scale by remember(density) { mutableStateOf(density.density) }
33-
34- Layer (
35- modifier = Modifier .padding(start = 32 .dp, top = 16 .dp, end = 16 .dp, bottom = 16 .dp)
36- .defaultMinSize(minWidth = 600 .dp),
37- shape = RoundedCornerShape (8 .dp),
38- border = BorderStroke (1 .dp, FluentTheme .colors.stroke.control.default),
39- cornerRadius = 8 .dp
40- ) {
41- Column (Modifier .padding(16 .dp), Arrangement .spacedBy(8 .dp)) {
42- Controller (scale, { scale = it }, darkMode, { darkMode = it })
43-
44- CompositionLocalProvider (LocalDensity provides Density (scale)) {
45- Content ()
46- }
47-
48- AccentButton (onClick = {
49- displayDialog = true
50- }) { Text (" Display Dialog" ) }
51- Box {
52- var expanded by remember { mutableStateOf(false ) }
66+
67+ val store = remember { Store (systemDarkMode) }
68+
69+ LaunchedEffect (systemDarkMode) {
70+ store.darkMode = systemDarkMode
71+ }
5372
54- Button (onClick = {
55- expanded = true
56- }) {
57- Text (" Show DropdownMenu" )
73+ CompositionLocalProvider (LocalStore provides store) {
74+ FluentTheme (colors = if (store.darkMode) darkColors() else lightColors()) {
75+ Mica (Modifier .fillMaxSize()) {
76+ Row (Modifier .fillMaxSize()) {
77+ var expanded by remember { mutableStateOf(true ) }
78+ var selected by remember { mutableStateOf(0 ) }
79+
80+ SideNav (Modifier .fillMaxHeight(), expanded, { expanded = it },
81+ footer = {
82+ SideNavItem (false , onClick = {
83+ // TODO
84+ }, icon = { Icon (Icons .Default .Settings , " Settings" ) }) {
85+ Text (" Settings" )
86+ }
5887 }
59-
60- fun close () {
61- expanded = false
88+ ) {
89+ navs.forEachIndexed { index, navItem ->
90+ SideNavItem (
91+ selected == index,
92+ onClick = { selected = index },
93+ icon = { Icon (navItem.icon, null ) },
94+ content = { Text (navItem.label) }
95+ )
6296 }
97+ }
6398
64- DropdownMenu (expanded, ::close) {
65- DropdownMenuItem (::close) { Text (" Option 1" )}
66- DropdownMenuItem (::close) { Text (" Option 2" )}
67- DropdownMenuItem (::close) { Text (" Option 3" )}
68- }
99+ AnimatedContent (selected, Modifier .fillMaxHeight().weight(1f ), transitionSpec = {
100+ fadeIn(tween(FluentDuration .ShortDuration , easing = FluentEasing .FastInvokeEasing )) +
101+ slideInVertically(
102+ tween(
103+ FluentDuration .ShortDuration ,
104+ easing = FluentEasing .FastInvokeEasing
105+ ), { it / 6 }) with
106+ fadeOut(tween(FluentDuration .QuickDuration , easing = FluentEasing .FastInvokeEasing ))
107+ }) {
108+ navs[it].content()
69109 }
70110 }
71- Dialog (
72- title = " This is a example dialog" ,
73- visible = displayDialog,
74- cancelButtonText = " Cancel" ,
75- confirmButtonText = " Confirm" ,
76- onCancel = {
77- displayDialog = false
78- },
79- onConfirm = {
80- displayDialog = false
81- }
82- )
83111 }
84112 }
85113 }
86- }
87-
88- @Composable
89- private fun Controller (
90- scale : Float ,
91- onScaleChange : (Float ) -> Unit ,
92- darkMode : Boolean ,
93- onDarkModeChange : (Boolean ) -> Unit
94- ) {
95- Row (
96- verticalAlignment = Alignment .CenterVertically ,
97- horizontalArrangement = Arrangement .spacedBy(8 .dp)
98- ) {
99- Text (" Scale: %.2f" .format(scale))
100- val density = LocalDensity .current
101- Button (onClick = { onScaleChange(density.density) }) { Text (" Reset" ) }
102- Switcher (darkMode, text = " Dark Mode" , onCheckStateChange = { onDarkModeChange(it) })
103- }
104- Slider (
105- modifier = Modifier .width(200 .dp),
106- value = scale,
107- onValueChange = { onScaleChange(it) },
108- valueRange = 1f .. 10f
109- )
110- }
111-
112- @Composable
113- private fun Content () {
114-
115- var sliderValue by remember { mutableStateOf(0.5f ) }
116- Slider (
117- modifier = Modifier .width(200 .dp),
118- value = sliderValue,
119- onValueChange = { sliderValue = it },
120- )
121- Buttons ()
122-
123- Controls ()
124-
125- Row {
126- Layer (
127- modifier = Modifier .size(32 .dp),
128- shape = RoundedCornerShape (4 .dp),
129- cornerRadius = 4 .dp,
130- color = FluentTheme .colors.fillAccent.default,
131- border = BorderStroke (1 .dp, FluentTheme .colors.stroke.control.default),
132- content = {},
133- outsideBorder = false
134- )
135- Layer (
136- modifier = Modifier .size(32 .dp),
137- shape = RoundedCornerShape (4 .dp),
138- cornerRadius = 4 .dp,
139- color = FluentTheme .colors.fillAccent.default,
140- border = BorderStroke (1 .dp, FluentTheme .colors.stroke.control.default),
141- content = {},
142- outsideBorder = true
143- )
144- }
145-
146- var value by remember { mutableStateOf(TextFieldValue (" Hello Fluent!" )) }
147- TextField (value, onValueChange = { value = it })
148- TextField (
149- value = value, onValueChange = { value = it }, enabled = false ,
150- header = { Text (" With Header" ) }
151- )
152-
153- // ProgressRings
154- Row (
155- horizontalArrangement = Arrangement .spacedBy(32 .dp),
156- verticalAlignment = Alignment .CenterVertically
157- ) {
158- ProgressRing (size = ProgressRingSize .Medium )
159- ProgressRing (progress = sliderValue)
160- AccentButton (onClick = {}) {
161- ProgressRing (size = ProgressRingSize .Small , color = LocalContentColor .current)
162- Text (" Small" )
163- }
164- }
165-
166- ProgressBar (sliderValue)
167- ProgressBar ()
168-
169- Row (horizontalArrangement = Arrangement .spacedBy(8 .dp)) {
170- for (imageVector in icons) {
171- Icon (
172- modifier = Modifier .size(18 .dp),
173- imageVector = imageVector, contentDescription = null
174- )
175- }
176- }
177- }
178-
179- @Composable
180- private fun Controls () {
181- var checked by remember { mutableStateOf(false ) }
182- Switcher (checked, text = null , onCheckStateChange = { checked = it })
183-
184- var checked2 by remember { mutableStateOf(true ) }
185- Switcher (checked2, text = " With Label" , onCheckStateChange = { checked2 = it })
186-
187- var checked3 by remember { mutableStateOf(true ) }
188- Switcher (
189- checked3,
190- text = " Before Label" ,
191- textBefore = true ,
192- onCheckStateChange = { checked3 = it }
193- )
194-
195- var checked4 by remember { mutableStateOf(false ) }
196- CheckBox (checked4) { checked4 = it }
197-
198- var checked5 by remember { mutableStateOf(true ) }
199- CheckBox (checked5, label = " With Label" ) { checked5 = it }
200-
201- var selectedRadio by remember { mutableStateOf(0 ) }
202- RadioButton (selectedRadio == 0 , onClick = { selectedRadio = 0 })
203- RadioButton (selectedRadio == 1 , onClick = { selectedRadio = 1 }, label = " With Label" )
204- }
205-
206- @Composable
207- private fun Buttons () {
208- var text by remember { mutableStateOf(" Hello World" ) }
209- Row (horizontalArrangement = Arrangement .spacedBy(8 .dp)) {
210- val onClick = { text = " Hello, Fluent Design!" }
211- Button (onClick) { Text (text) }
212-
213- AccentButton (onClick) {
214- Icon (Icons .Default .Checkmark , contentDescription = null )
215- Text (text)
216- }
217-
218- SubtleButton (onClick) {
219- Text (" Text Button" )
220- }
221- }
222- Row (horizontalArrangement = Arrangement .spacedBy(8 .dp)) {
223- AccentButton ({}, iconOnly = true ) {
224- Icon (Icons .Default .Navigation , contentDescription = null )
225- }
226- Button ({}, iconOnly = true ) {
227- Icon (Icons .Default .Navigation , contentDescription = null )
228- }
229- SubtleButton ({}, iconOnly = true ) {
230- Icon (Icons .Default .Navigation , contentDescription = null )
231- }
232- }
233- }
234-
235- private val icons = arrayOf(
236- Icons .Default .Add ,
237- Icons .Default .Delete ,
238- Icons .Default .Dismiss ,
239- Icons .Default .ArrowLeft ,
240- Icons .Default .Navigation ,
241- Icons .Default .List
242- )
114+ }
0 commit comments