Skip to content

Commit f182777

Browse files
feature: Rework flocon panel
1 parent b28d584 commit f182777

File tree

6 files changed

+186
-87
lines changed

6 files changed

+186
-87
lines changed

FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/database/view/DatabaseResultView.kt

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,7 @@ import androidx.compose.foundation.lazy.itemsIndexed
2020
import androidx.compose.foundation.rememberScrollState
2121
import androidx.compose.foundation.text.selection.SelectionContainer
2222
import androidx.compose.material.icons.Icons
23-
import androidx.compose.material.icons.automirrored.filled.CallMade
2423
import androidx.compose.material.icons.automirrored.outlined.DriveFileMove
25-
import androidx.compose.material.icons.filled.FileUpload
26-
import androidx.compose.material.icons.outlined.Download
27-
import androidx.compose.material.icons.outlined.ImportExport
28-
import androidx.compose.material.icons.outlined.Save
29-
import androidx.compose.material.icons.outlined.SaveAs
3024
import androidx.compose.material3.Text
3125
import androidx.compose.runtime.Composable
3226
import androidx.compose.runtime.getValue
@@ -200,7 +194,7 @@ fun DatabaseResultView(
200194
}
201195
) {
202196
DatabaseRowDetailView(
203-
modifier = Modifier.matchParentSize(),
197+
modifier = Modifier.fillMaxSize(),
204198
state = it,
205199
columns = result.columns,
206200
)

FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/list/view/NetworkScreen.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.Spacer
1111
import androidx.compose.foundation.layout.fillMaxHeight
1212
import androidx.compose.foundation.layout.fillMaxSize
1313
import androidx.compose.foundation.layout.fillMaxWidth
14-
import androidx.compose.foundation.layout.padding
1514
import androidx.compose.foundation.layout.width
1615
import androidx.compose.foundation.lazy.LazyColumn
1716
import androidx.compose.foundation.lazy.rememberLazyListState
@@ -80,6 +79,7 @@ import io.github.openflocon.library.designsystem.components.FloconIconTonalButto
8079
import io.github.openflocon.library.designsystem.components.FloconOverflow
8180
import io.github.openflocon.library.designsystem.components.FloconPageTopBar
8281
import io.github.openflocon.library.designsystem.components.FloconVerticalScrollbar
82+
import io.github.openflocon.library.designsystem.components.panel.PanelWidth
8383
import io.github.openflocon.library.designsystem.components.rememberFloconScrollbarAdapter
8484
import kotlinx.coroutines.flow.MutableStateFlow
8585
import org.koin.compose.viewmodel.koinViewModel
@@ -323,15 +323,16 @@ fun NetworkScreen(
323323
}
324324
}
325325
FloconAnimateVisibility(
326-
uiState.detailState
326+
state = uiState.detailState,
327+
modifier = Modifier.fillMaxHeight()
327328
) {
328329
Row {
329330
Spacer(Modifier.width(8.dp))
330331
NetworkDetailContent(
331332
uiState = it,
332333
onAction = onAction,
333334
modifier = Modifier
334-
.width(300.dp) // TODO Change, settings ?
335+
.width(PanelWidth)
335336
.clip(FloconTheme.shapes.medium)
336337
)
337338
}

FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconAnimateVisibility.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,29 @@ import androidx.compose.animation.ContentTransform
77
import androidx.compose.animation.core.tween
88
import androidx.compose.animation.fadeIn
99
import androidx.compose.animation.fadeOut
10-
import androidx.compose.animation.scaleIn
1110
import androidx.compose.animation.togetherWith
1211
import androidx.compose.runtime.Composable
12+
import androidx.compose.ui.Modifier
1313

1414
@Composable
1515
fun <T> FloconAnimateVisibility(
1616
state: T?,
17+
modifier: Modifier = Modifier,
1718
transitionSpec: AnimatedContentTransitionScope<T?>.() -> ContentTransform = {
1819
(fadeIn(animationSpec = tween(220, delayMillis = 90)) +
19-
scaleIn(initialScale = 0.92f, animationSpec = tween(220, delayMillis = 90)))
20+
slideIntoContainer(
21+
towards = AnimatedContentTransitionScope.SlideDirection.Start,
22+
animationSpec = tween(220, delayMillis = 90)
23+
)
24+
)
2025
.togetherWith(fadeOut(animationSpec = tween(90)))
2126
},
2227
content: @Composable AnimatedContentScope.(T & Any) -> Unit
2328
) {
2429
AnimatedContent(
2530
targetState = state,
26-
transitionSpec = transitionSpec
31+
transitionSpec = transitionSpec,
32+
modifier = modifier
2733
) {
2834
if (it != null) {
2935
content(it)

FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/FloconIconButton.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import androidx.compose.foundation.layout.PaddingValues
1616
import androidx.compose.foundation.layout.padding
1717
import androidx.compose.foundation.layout.size
1818
import androidx.compose.foundation.selection.toggleable
19+
import androidx.compose.material.icons.Icons
20+
import androidx.compose.material.icons.outlined.Close
1921
import androidx.compose.material3.LocalContentColor
2022
import androidx.compose.material3.Text
2123
import androidx.compose.runtime.Composable

FloconDesktop/library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components/panel/FloconPanel.kt

Lines changed: 129 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,20 @@ import androidx.compose.animation.core.tween
88
import androidx.compose.foundation.border
99
import androidx.compose.foundation.layout.Arrangement
1010
import androidx.compose.foundation.layout.Box
11-
import androidx.compose.foundation.layout.BoxScope
1211
import androidx.compose.foundation.layout.Column
1312
import androidx.compose.foundation.layout.Row
1413
import androidx.compose.foundation.layout.fillMaxHeight
1514
import androidx.compose.foundation.layout.padding
1615
import androidx.compose.foundation.layout.width
1716
import androidx.compose.material.icons.Icons
1817
import androidx.compose.material.icons.outlined.Close
19-
import androidx.compose.material.icons.outlined.Pin
2018
import androidx.compose.runtime.Composable
2119
import androidx.compose.runtime.LaunchedEffect
20+
import androidx.compose.runtime.Stable
2221
import androidx.compose.runtime.getValue
2322
import androidx.compose.runtime.mutableStateOf
2423
import androidx.compose.runtime.remember
24+
import androidx.compose.runtime.rememberCoroutineScope
2525
import androidx.compose.runtime.setValue
2626
import androidx.compose.ui.Modifier
2727
import androidx.compose.ui.graphics.graphicsLayer
@@ -30,106 +30,152 @@ import androidx.compose.ui.unit.dp
3030
import io.github.openflocon.library.designsystem.FloconTheme
3131
import io.github.openflocon.library.designsystem.components.FloconIcon
3232
import io.github.openflocon.library.designsystem.components.FloconIconTonalButton
33+
import io.github.openflocon.library.designsystem.components.escape.EscapeHandler
34+
import kotlinx.coroutines.launch
3335

3436
private const val AnimDuration = 500
35-
private val PanelWidth = 500.dp
37+
val PanelWidth = 500.dp
38+
39+
@Stable
40+
class FloconPanelState internal constructor(initialValue: Boolean) {
41+
42+
internal var expanded by mutableStateOf(initialValue)
43+
44+
val translationX = AnimationState(typeConverter = Dp.VectorConverter, PanelWidth)
45+
46+
suspend fun show() {
47+
expanded = true
48+
translationX.animateTo(0.dp, animationSpec = tween(AnimDuration, easing = EaseOutExpo))
49+
}
50+
51+
suspend fun hide() {
52+
translationX.animateTo(PanelWidth, animationSpec = tween(AnimDuration, easing = EaseOutExpo))
53+
expanded = false
54+
}
55+
56+
}
57+
58+
@Composable
59+
fun rememberFloconPanelState(initialValue: Boolean = false): FloconPanelState {
60+
return remember { FloconPanelState(initialValue) }
61+
}
62+
63+
64+
interface FloconPanelScope {
65+
val state: FloconPanelState
66+
67+
fun Modifier.animatePanelAction(): Modifier
68+
69+
}
70+
71+
private class FloconPanelScopeImpl(
72+
override val state: FloconPanelState
73+
) : FloconPanelScope {
74+
75+
@Stable
76+
override fun Modifier.animatePanelAction(): Modifier = graphicsLayer {
77+
this.alpha = 1f - state.translationX.value.div(PanelWidth)
78+
}
79+
80+
}
81+
3682

37-
// TODO Rework
3883
@Composable
3984
fun FloconPanel(
40-
expanded: Boolean,
41-
onClose: (() -> Unit)? = null,
42-
onPin: (() -> Unit)? = null,
43-
content: @Composable BoxScope.() -> Unit
85+
state: FloconPanelState,
86+
onDismissRequest: () -> Unit,
87+
actions: @Composable FloconPanelScope.() -> Unit = {},
88+
content: @Composable FloconPanelScope.() -> Unit
4489
) {
45-
var innerExpanded by remember { mutableStateOf(expanded) }
46-
val translationX = remember { AnimationState(typeConverter = Dp.VectorConverter, PanelWidth) }
90+
val scope = remember(state) { FloconPanelScopeImpl(state) }
91+
val coroutineScope = rememberCoroutineScope()
4792

48-
suspend fun hide() {
49-
translationX.animateTo(PanelWidth, animationSpec = tween(AnimDuration, easing = EaseOutExpo))
50-
innerExpanded = false
93+
LaunchedEffect(Unit) {
94+
if (state.expanded) {
95+
state.show()
96+
}
5197
}
5298

53-
LaunchedEffect(expanded) {
54-
if (expanded) {
55-
innerExpanded = true
56-
translationX.animateTo(0.dp, animationSpec = tween(AnimDuration, easing = EaseOutExpo))
57-
} else {
58-
hide()
99+
LaunchedEffect(state.expanded) {
100+
if (!state.expanded) {
101+
onDismissRequest()
59102
}
60103
}
61104

105+
EscapeHandler {
106+
coroutineScope.launch {
107+
state.hide()
108+
onDismissRequest()
109+
}
110+
true
111+
}
112+
62113
Row(
63114
modifier = Modifier
64115
.fillMaxHeight()
65116
) {
66-
if (onClose != null) {
67-
Column(
68-
verticalArrangement = Arrangement.spacedBy(8.dp),
69-
modifier = Modifier.padding(8.dp)
70-
) {
71-
FloconIconTonalButton(
72-
onClick = onClose,
73-
modifier = Modifier
74-
.graphicsLayer {
75-
this.alpha = 1f - translationX.value.div(PanelWidth)
76-
}
77-
) {
78-
FloconIcon(
79-
Icons.Outlined.Close
80-
)
81-
}
82-
if (onPin != null) {
83-
FloconIconTonalButton(
84-
onClick = onPin,
85-
modifier = Modifier
86-
.graphicsLayer {
87-
this.alpha = 1f - translationX.value.div(PanelWidth)
88-
}
89-
) {
90-
FloconIcon(
91-
Icons.Outlined.Pin
92-
)
93-
}
94-
}
95-
}
96-
}
117+
Column(
118+
verticalArrangement = Arrangement.spacedBy(8.dp),
119+
modifier = Modifier.padding(8.dp),
120+
content = { scope.actions() }
121+
)
97122
Box(
98123
modifier = Modifier
99124
.width(PanelWidth)
100125
.fillMaxHeight()
101126
.graphicsLayer {
102-
this.translationX = translationX.value.toPx()
127+
this.translationX = state.translationX.value.toPx()
103128
}
104-
.border(width = 1.dp, color = FloconTheme.colorPalette.surface),
105-
content = content
106-
)
129+
.border(width = 1.dp, color = FloconTheme.colorPalette.surface)
130+
) {
131+
scope.content()
132+
}
107133
}
108134
}
109135

110-
// val floconPanelController = LocalFloconPanelController.current
136+
// TODO Rework
137+
@Composable
138+
fun FloconPanel(
139+
expanded: Boolean,
140+
onDismissRequest: () -> Unit,
141+
actions: @Composable FloconPanelScope.() -> Unit = {},
142+
content: @Composable FloconPanelScope.() -> Unit
143+
) {
144+
var innerExpand by remember { mutableStateOf(expanded) }
145+
val state = rememberFloconPanelState(expanded)
146+
val scope = rememberCoroutineScope()
111147

112-
// if (innerExpanded) {
113-
// DisposableEffect(Unit) {
114-
// floconPanelController.display {
115-
// if (onClose != null) {
116-
// EscapeHandler {
117-
// onClose()
118-
// true
119-
// }
120-
// }
121-
//
148+
LaunchedEffect(expanded) {
149+
if (expanded) {
150+
innerExpand = true
151+
state.show()
152+
} else {
153+
state.hide()
154+
innerExpand = false
155+
}
156+
}
122157

123-
// onDispose { floconPanelController.hide() }
124-
// }
125-
// }
126-
//}
158+
if (innerExpand) {
159+
FloconPanel(
160+
state = state,
161+
onDismissRequest = {
162+
scope.launch {
163+
state.hide()
164+
innerExpand = false
165+
onDismissRequest()
166+
}
167+
},
168+
actions = actions,
169+
content = content
170+
)
171+
}
172+
}
127173

128174
@Composable
129175
fun <T : Any?> FloconPanel(
130176
contentState: T,
131177
onClose: (() -> Unit)? = null,
132-
content: @Composable BoxScope.(T & Any) -> Unit
178+
content: @Composable FloconPanelScope.(T & Any) -> Unit
133179
) {
134180
var rememberTarget by remember { mutableStateOf(contentState) }
135181

@@ -141,7 +187,19 @@ fun <T : Any?> FloconPanel(
141187

142188
FloconPanel(
143189
expanded = contentState != null,
144-
onClose = onClose,
190+
onDismissRequest = { onClose?.invoke() },
191+
actions = {
192+
if (onClose != null) {
193+
FloconIconTonalButton(
194+
onClick = onClose,
195+
modifier = Modifier
196+
) {
197+
FloconIcon(
198+
Icons.Outlined.Close
199+
)
200+
}
201+
}
202+
},
145203
) {
146204
rememberTarget?.let { content(this, it) }
147205
}

0 commit comments

Comments
 (0)