mirror of
https://github.com/BetterAndroid/FlexiUI.git
synced 2025-09-07 19:14:12 +08:00
feat: update demo
This commit is contained in:
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Flexi UI - A flexible and useful UI component library.
|
||||||
|
* Copyright (C) 2019-2024 HighCapable
|
||||||
|
* https://github.com/BetterAndroid/FlexiUI
|
||||||
|
*
|
||||||
|
* Apache License Version 2.0
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* This file is created by fankes on 2024/1/13.
|
||||||
|
*/
|
||||||
|
package com.highcapable.flexiui.demo.bean
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import androidx.compose.runtime.Stable
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class SimpleListBean(
|
||||||
|
val index: Int,
|
||||||
|
val title: String,
|
||||||
|
val subtitle: String
|
||||||
|
) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
@Stable
|
||||||
|
fun create(index: Int) = SimpleListBean(
|
||||||
|
index = index,
|
||||||
|
title = "Item $index",
|
||||||
|
subtitle = "This is a simple data of index $index"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@@ -24,23 +24,46 @@
|
|||||||
package com.highcapable.flexiui.demo.screen
|
package com.highcapable.flexiui.demo.screen
|
||||||
|
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
|
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
||||||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.pager.HorizontalPager
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateListOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import com.highcapable.betterandroid.compose.multiplatform.backpress.BackHandler
|
import com.highcapable.betterandroid.compose.multiplatform.backpress.BackHandler
|
||||||
|
import com.highcapable.flexiui.component.Button
|
||||||
|
import com.highcapable.flexiui.component.DropdownMenu
|
||||||
|
import com.highcapable.flexiui.component.DropdownMenuItem
|
||||||
|
import com.highcapable.flexiui.component.HorizontalItemBox
|
||||||
import com.highcapable.flexiui.component.Icon
|
import com.highcapable.flexiui.component.Icon
|
||||||
import com.highcapable.flexiui.component.Scaffold
|
import com.highcapable.flexiui.component.Scaffold
|
||||||
import com.highcapable.flexiui.component.SecondaryAppBar
|
import com.highcapable.flexiui.component.SecondaryAppBar
|
||||||
import com.highcapable.flexiui.component.Tab
|
import com.highcapable.flexiui.component.Tab
|
||||||
import com.highcapable.flexiui.component.TabRow
|
import com.highcapable.flexiui.component.TabRow
|
||||||
import com.highcapable.flexiui.component.Text
|
import com.highcapable.flexiui.component.Text
|
||||||
|
import com.highcapable.flexiui.component.window.FlexiDialog
|
||||||
|
import com.highcapable.flexiui.demo.Delete
|
||||||
import com.highcapable.flexiui.demo.DeleteForever
|
import com.highcapable.flexiui.demo.DeleteForever
|
||||||
import com.highcapable.flexiui.demo.ListAdd
|
import com.highcapable.flexiui.demo.ListAdd
|
||||||
|
import com.highcapable.flexiui.demo.PrimarySpacer
|
||||||
|
import com.highcapable.flexiui.demo.bean.SimpleListBean
|
||||||
import com.highcapable.flexiui.demo.rememberRouter
|
import com.highcapable.flexiui.demo.rememberRouter
|
||||||
import com.highcapable.flexiui.resources.FlexiIcons
|
import com.highcapable.flexiui.resources.FlexiIcons
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -49,54 +72,154 @@ import kotlinx.coroutines.launch
|
|||||||
fun LazyListScreen() {
|
fun LazyListScreen() {
|
||||||
val router = rememberRouter()
|
val router = rememberRouter()
|
||||||
val pageCount = 2
|
val pageCount = 2
|
||||||
val state = rememberPagerState(pageCount = { pageCount })
|
val pagerState = rememberPagerState(pageCount = { pageCount })
|
||||||
|
val lazyListState = rememberLazyListState()
|
||||||
|
val lazyGridState = rememberLazyGridState()
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
val testListData = remember {
|
||||||
|
mutableStateListOf<SimpleListBean>().apply {
|
||||||
|
for (i in 1..5) add(SimpleListBean.create(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
Scaffold(
|
Scaffold(
|
||||||
appBar = {
|
appBar = {
|
||||||
|
var showRemoveAllDialog by remember { mutableStateOf(false) }
|
||||||
|
FlexiDialog(
|
||||||
|
visible = showRemoveAllDialog,
|
||||||
|
onDismissRequest = { showRemoveAllDialog = false },
|
||||||
|
title = { Text("Remove All") },
|
||||||
|
content = { Text("Are you sure you want to remove all data?") },
|
||||||
|
confirmButton = {
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
showRemoveAllDialog = false
|
||||||
|
testListData.clear()
|
||||||
|
}
|
||||||
|
) { Text("OK") }
|
||||||
|
},
|
||||||
|
cancelButton = {
|
||||||
|
Button(
|
||||||
|
onClick = { showRemoveAllDialog = false }
|
||||||
|
) { Text("Cancel") }
|
||||||
|
}
|
||||||
|
)
|
||||||
SecondaryAppBar(
|
SecondaryAppBar(
|
||||||
title = { Text("Lazy List Demo") },
|
title = { Text("Lazy List Demo") },
|
||||||
subtitle = { Text("0 items of list data", singleLine = true) },
|
subtitle = { Text("${testListData.size} items of list data", singleLine = true) },
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
NavigationIconButton(onClick = { router.goHome() })
|
NavigationIconButton(onClick = { router.goHome() })
|
||||||
},
|
},
|
||||||
actions = {
|
actions = {
|
||||||
ActionIconButton(onClick = { /* TODO */ }) {
|
ActionIconButton(
|
||||||
Icon(FlexiIcons.ListAdd)
|
onClick = {
|
||||||
}
|
val lastIndex = if (testListData.isNotEmpty())
|
||||||
ActionIconButton(onClick = { /* TODO */ }) {
|
testListData[testListData.lastIndex].index + 1
|
||||||
Icon(FlexiIcons.DeleteForever)
|
else 1
|
||||||
}
|
testListData.add(SimpleListBean.create(lastIndex))
|
||||||
|
scope.launch {
|
||||||
|
lazyListState.animateScrollToItem(testListData.lastIndex)
|
||||||
|
lazyGridState.animateScrollToItem(testListData.lastIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) { Icon(FlexiIcons.ListAdd) }
|
||||||
|
ActionIconButton(
|
||||||
|
onClick = { showRemoveAllDialog = testListData.isNotEmpty() }
|
||||||
|
) { Icon(FlexiIcons.DeleteForever) }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
BackHandler { router.goHome() }
|
||||||
},
|
},
|
||||||
tab = {
|
tab = {
|
||||||
TabRow(
|
TabRow(
|
||||||
selectedTabIndex = state.currentPage,
|
selectedTabIndex = pagerState.currentPage,
|
||||||
indicator = {
|
indicator = {
|
||||||
TabIndicator(modifier = Modifier.pagerTabIndicatorOffset(state))
|
TabIndicator(modifier = Modifier.pagerTabIndicatorOffset(pagerState))
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Tab(
|
Tab(
|
||||||
selected = state.currentPage == 0,
|
selected = pagerState.currentPage == 0,
|
||||||
onClick = { scope.launch { state.animateScrollToPage(0) } }
|
onClick = { scope.launch { pagerState.animateScrollToPage(0) } }
|
||||||
) { Text("Linear List") }
|
) { Text("Linear List") }
|
||||||
Tab(
|
Tab(
|
||||||
selected = state.currentPage == 1,
|
selected = pagerState.currentPage == 1,
|
||||||
onClick = { scope.launch { state.animateScrollToPage(1) } }
|
onClick = { scope.launch { pagerState.animateScrollToPage(1) } }
|
||||||
) { Text("Grid List") }
|
) { Text("Grid List") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) {
|
) { innerPadding ->
|
||||||
HorizontalPager(
|
HorizontalPager(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
state = state,
|
state = pagerState,
|
||||||
|
beyondBoundsPageCount = pageCount
|
||||||
) { index ->
|
) { index ->
|
||||||
// TODO: To be implemented.
|
@Composable
|
||||||
Box(
|
fun LazyItem(modifier: Modifier, index: Int) {
|
||||||
modifier = Modifier.fillMaxSize(),
|
Box(modifier = modifier) {
|
||||||
|
val hapticFeedback = LocalHapticFeedback.current
|
||||||
|
var showDropdownMenu by remember { mutableStateOf(false) }
|
||||||
|
HorizontalItemBox(
|
||||||
|
onLongClick = {
|
||||||
|
showDropdownMenu = true
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
},
|
||||||
|
title = { Text(testListData[index].title) },
|
||||||
|
subtitle = { Text(testListData[index].subtitle) },
|
||||||
|
showArrowIcon = false
|
||||||
|
)
|
||||||
|
DropdownMenu(
|
||||||
|
expanded = showDropdownMenu,
|
||||||
|
onDismissRequest = { showDropdownMenu = false }
|
||||||
|
) {
|
||||||
|
DropdownMenuItem(
|
||||||
|
onClick = { testListData.removeAt(index) }
|
||||||
|
) {
|
||||||
|
Icon(FlexiIcons.Delete)
|
||||||
|
PrimarySpacer()
|
||||||
|
Text("Remove this data")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (testListData.isNotEmpty()) when (index) {
|
||||||
|
0 -> LazyColumn(
|
||||||
|
modifier = Modifier.fillMaxSize().padding(innerPadding),
|
||||||
|
state = lazyListState,
|
||||||
|
verticalArrangement = ListSpacing
|
||||||
|
) {
|
||||||
|
items(
|
||||||
|
count = testListData.size,
|
||||||
|
key = { testListData[it].index }
|
||||||
|
) { index ->
|
||||||
|
LazyItem(
|
||||||
|
modifier = Modifier.animateItemPlacement(),
|
||||||
|
index = index
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
1 -> LazyVerticalGrid(
|
||||||
|
modifier = Modifier.fillMaxSize().padding(innerPadding),
|
||||||
|
state = lazyGridState,
|
||||||
|
columns = GridCells.Adaptive(GridMaxWidth),
|
||||||
|
verticalArrangement = ListSpacing,
|
||||||
|
horizontalArrangement = ListSpacing
|
||||||
|
) {
|
||||||
|
items(
|
||||||
|
count = testListData.size,
|
||||||
|
key = { testListData[it].index }
|
||||||
|
) { index ->
|
||||||
|
LazyItem(
|
||||||
|
modifier = Modifier.animateItemPlacement(),
|
||||||
|
index = index
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else Box(
|
||||||
|
modifier = Modifier.fillMaxSize().padding(innerPadding),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) { Text("Page ${index + 1}. To be implemented.") }
|
) { Text("No data to show") }
|
||||||
}
|
}
|
||||||
BackHandler { router.goHome() }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val ListSpacing = Arrangement.spacedBy(10.dp)
|
||||||
|
private val GridMaxWidth = 100.dp
|
@@ -31,6 +31,7 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.pager.HorizontalPager
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
import androidx.compose.foundation.pager.rememberPagerState
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
@@ -78,7 +79,7 @@ import kotlinx.coroutines.launch
|
|||||||
@Composable
|
@Composable
|
||||||
fun MainScreen() {
|
fun MainScreen() {
|
||||||
val pageCount = 2
|
val pageCount = 2
|
||||||
val state = rememberPagerState(pageCount = { pageCount })
|
val pagerState = rememberPagerState(pageCount = { pageCount })
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val uriHandler = LocalUriHandler.current
|
val uriHandler = LocalUriHandler.current
|
||||||
Scaffold(
|
Scaffold(
|
||||||
@@ -117,36 +118,37 @@ fun MainScreen() {
|
|||||||
arrangement = Arrangement.SpaceAround
|
arrangement = Arrangement.SpaceAround
|
||||||
) {
|
) {
|
||||||
NavigationBarItem(
|
NavigationBarItem(
|
||||||
selected = state.currentPage == 0,
|
selected = pagerState.currentPage == 0,
|
||||||
onClick = { scope.launch { state.animateScrollToPage(page = 0) } },
|
onClick = { scope.launch { pagerState.animateScrollToPage(page = 0) } },
|
||||||
icon = { Icon(FlexiIcons.Home, style = IconDefaults.style(size = 24.dp)) },
|
icon = { Icon(FlexiIcons.Home, style = IconDefaults.style(size = 24.dp)) },
|
||||||
text = { Text("Home") }
|
text = { Text("Home") }
|
||||||
)
|
)
|
||||||
NavigationBarItem(
|
NavigationBarItem(
|
||||||
selected = state.currentPage == 1,
|
selected = pagerState.currentPage == 1,
|
||||||
onClick = { scope.launch { state.animateScrollToPage(page = 1) } },
|
onClick = { scope.launch { pagerState.animateScrollToPage(page = 1) } },
|
||||||
icon = { Icon(FlexiIcons.Component, style = IconDefaults.style(size = 24.dp)) },
|
icon = { Icon(FlexiIcons.Component, style = IconDefaults.style(size = 24.dp)) },
|
||||||
text = { Text("Component") }
|
text = { Text("Component") }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) {
|
) { innerPadding ->
|
||||||
HorizontalPager(
|
HorizontalPager(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
state = state,
|
state = pagerState,
|
||||||
) { index ->
|
) { index ->
|
||||||
|
val modifier = Modifier.padding(innerPadding)
|
||||||
when (index) {
|
when (index) {
|
||||||
0 -> MainHomePage()
|
0 -> MainHomePage(modifier)
|
||||||
1 -> MainComponentPage()
|
1 -> MainComponentPage(modifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MainHomePage() {
|
fun MainHomePage(modifier: Modifier) {
|
||||||
val scrollState = rememberScrollState()
|
val scrollState = rememberScrollState()
|
||||||
Column(modifier = Modifier.fillMaxSize().verticalScroll(scrollState)) {
|
Column(modifier = modifier.fillMaxSize().verticalScroll(scrollState)) {
|
||||||
AreaBox(modifier = Modifier.fillMaxWidth()) {
|
AreaBox(modifier = Modifier.fillMaxWidth()) {
|
||||||
Text("Flexi UI is a flexible and useful UI component library.")
|
Text("Flexi UI is a flexible and useful UI component library.")
|
||||||
}
|
}
|
||||||
@@ -213,15 +215,14 @@ fun MainHomePage() {
|
|||||||
title = { Text("Lazy List Demo") },
|
title = { Text("Lazy List Demo") },
|
||||||
subtitle = { Text("Open a lazy list page") }
|
subtitle = { Text("Open a lazy list page") }
|
||||||
)
|
)
|
||||||
PrimarySpacer()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MainComponentPage() {
|
fun MainComponentPage(modifier: Modifier) {
|
||||||
// TODO: To be implemented.
|
// TODO: To be implemented.
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = modifier.fillMaxSize(),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) { Text("To be implemented.") }
|
) { Text("To be implemented.") }
|
||||||
}
|
}
|
@@ -21,7 +21,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.highcapable.flexiui.demo.screen
|
package com.highcapable.flexiui.demo.screen
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.em
|
import androidx.compose.ui.unit.em
|
||||||
@@ -46,22 +48,27 @@ fun SecondaryScreen() {
|
|||||||
NavigationIconButton(onClick = { router.goHome() })
|
NavigationIconButton(onClick = { router.goHome() })
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
BackHandler { router.goHome() }
|
||||||
}
|
}
|
||||||
) {
|
) { innerPadding ->
|
||||||
AreaColumn(modifier = Modifier.fillMaxWidth()) {
|
Box(
|
||||||
Text(
|
modifier = Modifier.fillMaxWidth()
|
||||||
"""
|
.padding(innerPadding)
|
||||||
|
) {
|
||||||
|
AreaColumn(modifier = Modifier.fillMaxWidth()) {
|
||||||
|
Text(
|
||||||
|
"""
|
||||||
Now, you open a separate secondary page.
|
Now, you open a separate secondary page.
|
||||||
You can click the button below to back to the homepage.
|
You can click the button below to back to the homepage.
|
||||||
""".trimIndent(),
|
""".trimIndent(),
|
||||||
style = FlexiTheme.typography.primary.copy(lineHeight = 2.em)
|
style = FlexiTheme.typography.primary.copy(lineHeight = 2.em)
|
||||||
)
|
)
|
||||||
PrimarySpacer()
|
PrimarySpacer()
|
||||||
Button(
|
Button(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
onClick = { router.goHome() }
|
onClick = { router.goHome() }
|
||||||
) { Text("Take Me Home") }
|
) { Text("Take Me Home") }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
BackHandler { router.goHome() }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user