Add alternative layout

This commit is contained in:
MM20 2022-05-10 20:24:58 +02:00
parent 78593e0391
commit 7fda28aedd
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
19 changed files with 264 additions and 60 deletions

View File

@ -10,7 +10,7 @@
android:exported="true" android:exported="true"
android:launchMode="singleTask" android:launchMode="singleTask"
android:theme="@style/LauncherTheme" android:theme="@style/LauncherTheme"
android:windowSoftInputMode="stateHidden"> android:windowSoftInputMode="stateHidden|adjustNothing">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View File

@ -71,7 +71,7 @@ class LauncherActivity : BaseActivity() {
contentAlignment = Alignment.BottomCenter contentAlignment = Alignment.BottomCenter
) { ) {
NavBarEffects(modifier = Modifier.fillMaxSize()) NavBarEffects(modifier = Modifier.fillMaxSize())
PullDownScaffold( PagerScaffold(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.systemBarsPadding() .systemBarsPadding()

View File

@ -0,0 +1,180 @@
package de.mm20.launcher2.ui.launcher
import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.slideIn
import androidx.compose.animation.slideOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Done
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.google.accompanist.pager.ExperimentalPagerApi
import com.google.accompanist.pager.HorizontalPager
import com.google.accompanist.pager.rememberPagerState
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.ktx.toDp
import de.mm20.launcher2.ui.launcher.search.SearchBar
import de.mm20.launcher2.ui.launcher.search.SearchBarLevel
import de.mm20.launcher2.ui.launcher.search.SearchColumn
import de.mm20.launcher2.ui.launcher.search.SearchVM
import de.mm20.launcher2.ui.launcher.widgets.WidgetColumn
@OptIn(ExperimentalPagerApi::class)
@Composable
fun PagerScaffold(
modifier: Modifier = Modifier,
darkStatusBarIcons: Boolean = false,
darkNavBarIcons: Boolean = false,
) {
val viewModel: LauncherScaffoldVM = viewModel()
val searchVM: SearchVM = viewModel()
val context = LocalContext.current
val isSearchOpen by viewModel.isSearchOpen.observeAsState(false)
val isWidgetEditMode by viewModel.isWidgetEditMode.observeAsState(false)
val pagerState = rememberPagerState()
val widgetsScrollState = rememberScrollState()
val searchScrollState = rememberScrollState()
val currentPage = pagerState.currentPage
LaunchedEffect(currentPage) {
if (currentPage == 1) viewModel.openSearch()
else viewModel.closeSearch()
}
LaunchedEffect(isSearchOpen) {
if (isSearchOpen) pagerState.animateScrollToPage(1)
else {
pagerState.animateScrollToPage(0)
searchVM.search("")
}
}
BackHandler {
when {
isSearchOpen -> {
viewModel.closeSearch()
searchVM.search("")
}
isWidgetEditMode -> {
viewModel.setWidgetEditMode(false)
}
}
}
Box(
modifier = modifier
) {
var size by remember { mutableStateOf(IntSize.Zero) }
HorizontalPager(
count = 2,
state = pagerState,
modifier = Modifier
.fillMaxSize(),
userScrollEnabled = !isWidgetEditMode
) {
if (it == 1) {
val websearches by searchVM.websearchResults.observeAsState(emptyList())
val webSearchPadding by animateDpAsState(
if (websearches.isEmpty()) 0.dp else 48.dp
)
SearchColumn(
modifier = Modifier
.fillMaxSize()
.onSizeChanged {
size = it
}
.verticalScroll(searchScrollState, reverseScrolling = true)
.padding(start = 8.dp, end = 8.dp, top = 8.dp, bottom = 56.dp)
.padding(bottom = webSearchPadding)
)
}
if (it == 0) {
val editModePadding by animateDpAsState(if (isWidgetEditMode) 56.dp else 0.dp)
val showClockPadding by derivedStateOf {
widgetsScrollState.value == 0
}
val clockPadding by animateDpAsState(
if (showClockPadding) 64.dp else 0.dp
)
WidgetColumn(
modifier =
Modifier
.fillMaxSize()
.verticalScroll(widgetsScrollState)
.padding(start = 8.dp, end = 8.dp, top = 8.dp, bottom = 64.dp)
.padding(top = editModePadding),
clockHeight = size.height.toDp() - (64.dp - clockPadding),
clockBottomPadding = clockPadding,
editMode = isWidgetEditMode,
onEditModeChange = {
viewModel.setWidgetEditMode(it)
}
)
}
}
AnimatedVisibility(visible = isWidgetEditMode,
enter = slideIn { IntOffset(0, -it.height) },
exit = slideOut { IntOffset(0, -it.height) }
) {
CenterAlignedTopAppBar(
title = {
Text(stringResource(R.string.menu_edit_widgets))
},
navigationIcon = {
IconButton(onClick = { viewModel.setWidgetEditMode(false) }) {
Icon(imageVector = Icons.Rounded.Done, contentDescription = null)
}
},
)
}
val searchBarLevel by derivedStateOf {
when {
pagerState.isScrollInProgress -> SearchBarLevel.Raised
!isSearchOpen && widgetsScrollState.value == 0 -> SearchBarLevel.Resting
isSearchOpen && searchScrollState.value == 0 -> SearchBarLevel.Active
else -> SearchBarLevel.Raised
}
}
val focusSearchBar by viewModel.searchBarFocused.observeAsState(false)
val widgetEditModeOffset by animateDpAsState(
if (isWidgetEditMode) 128.dp else 0.dp
)
SearchBar(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(start = 8.dp, end = 8.dp, bottom = 8.dp)
.offset(y = widgetEditModeOffset),
level = searchBarLevel, focused = focusSearchBar, onFocusChange = {
if (it) viewModel.openSearch()
viewModel.setSearchbarFocus(it)
},
reverse = true
)
}
}

View File

@ -7,10 +7,7 @@ import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.slideIn import androidx.compose.animation.slideIn
import androidx.compose.animation.slideOut import androidx.compose.animation.slideOut
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
@ -298,7 +295,10 @@ fun PullDownScaffold(
SearchBar( SearchBar(
level = searchBarLevel, level = searchBarLevel,
modifier = Modifier modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.clipToBounds() .clipToBounds()
.padding(8.dp)
.offset { IntOffset(0, searchBarOffset.value.toInt()) } .offset { IntOffset(0, searchBarOffset.value.toInt()) }
.offset(y = editModeSearchBarOffset), .offset(y = editModeSearchBarOffset),
focused = searchBarFocused, focused = searchBarFocused,

View File

@ -46,6 +46,7 @@ import de.mm20.launcher2.search.data.Websearch
import de.mm20.launcher2.ui.R import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.LauncherCard import de.mm20.launcher2.ui.component.LauncherCard
import de.mm20.launcher2.ui.launcher.LauncherActivityVM import de.mm20.launcher2.ui.launcher.LauncherActivityVM
import de.mm20.launcher2.ui.layout.BottomReversed
import de.mm20.launcher2.ui.locals.LocalCardStyle import de.mm20.launcher2.ui.locals.LocalCardStyle
import de.mm20.launcher2.ui.settings.SettingsActivity import de.mm20.launcher2.ui.settings.SettingsActivity
import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.awaitCancellation
@ -58,7 +59,8 @@ fun SearchBar(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
level: SearchBarLevel, level: SearchBarLevel,
focused: Boolean, focused: Boolean,
onFocusChange: (Boolean) -> Unit onFocusChange: (Boolean) -> Unit,
reverse: Boolean = false,
) { ) {
val searchViewModel: SearchVM = viewModel() val searchViewModel: SearchVM = viewModel()
val activityViewModel: LauncherActivityVM = viewModel() val activityViewModel: LauncherActivityVM = viewModel()
@ -150,7 +152,8 @@ fun SearchBar(
}, },
onUnfocus = { onUnfocus = {
onFocusChange(false) onFocusChange(false)
} },
reverse = reverse
) )
} }
@ -166,7 +169,8 @@ fun SearchBar(
onValueChange: (String) -> Unit, onValueChange: (String) -> Unit,
onFocus: () -> Unit = {}, onFocus: () -> Unit = {},
onUnfocus: () -> Unit = {}, onUnfocus: () -> Unit = {},
focusRequester: FocusRequester = remember { FocusRequester() } focusRequester: FocusRequester = remember { FocusRequester() },
reverse: Boolean = false,
) { ) {
val context = LocalContext.current val context = LocalContext.current
@ -241,14 +245,13 @@ fun SearchBar(
LauncherCard( LauncherCard(
modifier = modifier modifier = modifier
.fillMaxWidth() .alpha(opacity),
.wrapContentHeight()
.alpha(opacity)
.padding(8.dp),
backgroundOpacity = backgroundOpacity, backgroundOpacity = backgroundOpacity,
elevation = elevation elevation = elevation
) { ) {
Column { Column(
verticalArrangement = if (reverse) Arrangement.BottomReversed else Arrangement.Top
) {
Row( Row(
modifier = Modifier.height(48.dp), modifier = Modifier.height(48.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically

View File

@ -1,9 +1,6 @@
package de.mm20.launcher2.ui.launcher.search package de.mm20.launcher2.ui.launcher.search
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
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.dp import androidx.compose.ui.unit.dp
@ -17,23 +14,26 @@ import de.mm20.launcher2.ui.launcher.search.files.FileResults
import de.mm20.launcher2.ui.launcher.search.unitconverter.UnitConverterResults import de.mm20.launcher2.ui.launcher.search.unitconverter.UnitConverterResults
import de.mm20.launcher2.ui.launcher.search.website.WebsiteResults import de.mm20.launcher2.ui.launcher.search.website.WebsiteResults
import de.mm20.launcher2.ui.launcher.search.wikipedia.WikipediaResults import de.mm20.launcher2.ui.launcher.search.wikipedia.WikipediaResults
import de.mm20.launcher2.ui.layout.BottomReversed
@Composable @Composable
fun SearchColumn( fun SearchColumn(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
reverse: Boolean = false,
) { ) {
Column( Column(
modifier = modifier modifier = modifier,
verticalArrangement = if (reverse) Arrangement.Top else Arrangement.BottomReversed
) { ) {
FavoritesResults() FavoritesResults(reverse)
AppResults() AppResults(reverse)
AppShortcutResults() AppShortcutResults(reverse)
UnitConverterResults() UnitConverterResults(reverse)
CalculatorResults() CalculatorResults(reverse)
CalendarResults() CalendarResults(reverse)
ContactResults() ContactResults(reverse)
WikipediaResults() WikipediaResults(reverse)
WebsiteResults() WebsiteResults(reverse)
FileResults() FileResults(reverse)
} }
} }

View File

@ -14,15 +14,16 @@ import de.mm20.launcher2.ui.launcher.search.SearchVM
import de.mm20.launcher2.ui.launcher.search.common.grid.SearchResultGrid import de.mm20.launcher2.ui.launcher.search.common.grid.SearchResultGrid
@Composable @Composable
fun ColumnScope.AppResults() { fun ColumnScope.AppResults(reverse: Boolean = false) {
val viewModel: SearchVM = viewModel() val viewModel: SearchVM = viewModel()
val apps by viewModel.appResults.observeAsState(emptyList()) val apps by viewModel.appResults.observeAsState(emptyList())
AnimatedVisibility(apps.isNotEmpty()) { AnimatedVisibility(apps.isNotEmpty()) {
LauncherCard( LauncherCard(
modifier = Modifier.padding(bottom = 8.dp) modifier = Modifier
.padding(bottom = if (reverse) 0.dp else 8.dp, top = if (reverse) 8.dp else 0.dp)
) { ) {
SearchResultGrid(items = apps) SearchResultGrid(items = apps, reverse = reverse)
} }
} }

View File

@ -24,7 +24,7 @@ import de.mm20.launcher2.ui.launcher.search.SearchVM
import de.mm20.launcher2.ui.launcher.search.common.list.SearchResultList import de.mm20.launcher2.ui.launcher.search.common.list.SearchResultList
@Composable @Composable
fun ColumnScope.AppShortcutResults() { fun ColumnScope.AppShortcutResults(reverse: Boolean = false) {
val viewModel: SearchVM = viewModel() val viewModel: SearchVM = viewModel()
val shortcuts by viewModel.appShortcutResults.observeAsState(emptyList()) val shortcuts by viewModel.appShortcutResults.observeAsState(emptyList())
val context = LocalContext.current val context = LocalContext.current
@ -34,7 +34,8 @@ fun ColumnScope.AppShortcutResults() {
AnimatedVisibility(shortcuts.isNotEmpty() || (!isSearchEmpty && missingPermission)) { AnimatedVisibility(shortcuts.isNotEmpty() || (!isSearchEmpty && missingPermission)) {
LauncherCard( LauncherCard(
modifier = Modifier.padding(bottom = 8.dp) modifier = Modifier
.padding(bottom = if (reverse) 0.dp else 8.dp, top = if (reverse) 8.dp else 0.dp)
) { ) {
Column { Column {
AnimatedVisibility(!isSearchEmpty && missingPermission) { AnimatedVisibility(!isSearchEmpty && missingPermission) {
@ -58,7 +59,8 @@ fun ColumnScope.AppShortcutResults() {
items = shortcuts, items = shortcuts,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(12.dp) .padding(12.dp),
reverse = reverse
) )
} }
} }

View File

@ -14,13 +14,14 @@ import de.mm20.launcher2.ui.launcher.search.SearchVM
import de.mm20.launcher2.ui.search.CalculatorItem import de.mm20.launcher2.ui.search.CalculatorItem
@Composable @Composable
fun ColumnScope.CalculatorResults() { fun ColumnScope.CalculatorResults(reverse: Boolean = false) {
val viewModel: SearchVM = viewModel() val viewModel: SearchVM = viewModel()
val calculator by viewModel.calculatorResult.observeAsState(null) val calculator by viewModel.calculatorResult.observeAsState(null)
AnimatedVisibility(calculator != null) { AnimatedVisibility(calculator != null) {
LauncherCard( LauncherCard(
modifier = Modifier.padding(bottom = 8.dp) modifier = Modifier
.padding(bottom = if (reverse) 0.dp else 8.dp, top = if (reverse) 8.dp else 0.dp)
) { ) {
calculator?.let { CalculatorItem(calculator = it) } calculator?.let { CalculatorItem(calculator = it) }
} }

View File

@ -24,7 +24,7 @@ import de.mm20.launcher2.ui.launcher.search.SearchVM
import de.mm20.launcher2.ui.launcher.search.common.list.SearchResultList import de.mm20.launcher2.ui.launcher.search.common.list.SearchResultList
@Composable @Composable
fun ColumnScope.CalendarResults() { fun ColumnScope.CalendarResults(reverse: Boolean = false) {
val viewModel: SearchVM = viewModel() val viewModel: SearchVM = viewModel()
val calendarEvents by viewModel.calendarResults.observeAsState(emptyList()) val calendarEvents by viewModel.calendarResults.observeAsState(emptyList())
val context = LocalContext.current val context = LocalContext.current
@ -34,7 +34,7 @@ fun ColumnScope.CalendarResults() {
AnimatedVisibility(calendarEvents.isNotEmpty() || (!isSearchEmpty && missingPermission)) { AnimatedVisibility(calendarEvents.isNotEmpty() || (!isSearchEmpty && missingPermission)) {
LauncherCard( LauncherCard(
modifier = Modifier modifier = Modifier
.padding(bottom = 8.dp) .padding(bottom = if (reverse) 0.dp else 8.dp, top = if (reverse) 8.dp else 0.dp)
.fillMaxWidth() .fillMaxWidth()
) { ) {
Column { Column {
@ -59,7 +59,8 @@ fun ColumnScope.CalendarResults() {
items = calendarEvents, items = calendarEvents,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(12.dp) .padding(12.dp),
reverse = reverse
) )
} }
} }

View File

@ -7,6 +7,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import de.mm20.launcher2.search.data.Searchable import de.mm20.launcher2.search.data.Searchable
import de.mm20.launcher2.ui.launcher.search.common.GridItem import de.mm20.launcher2.ui.launcher.search.common.GridItem
import de.mm20.launcher2.ui.layout.BottomReversed
import de.mm20.launcher2.ui.locals.LocalGridColumns import de.mm20.launcher2.ui.locals.LocalGridColumns
import kotlin.math.ceil import kotlin.math.ceil
@ -16,12 +17,14 @@ fun SearchResultGrid(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
showLabels: Boolean = true, showLabels: Boolean = true,
columns: Int = LocalGridColumns.current, columns: Int = LocalGridColumns.current,
reverse: Boolean = false
) { ) {
Column( Column(
modifier = modifier modifier = modifier
.animateContentSize() .animateContentSize()
.fillMaxWidth() .fillMaxWidth()
.padding(4.dp) .padding(4.dp),
verticalArrangement = if (reverse) Arrangement.Top else Arrangement.BottomReversed
) { ) {
for (i in 0 until ceil(items.size / columns.toFloat()).toInt()) { for (i in 0 until ceil(items.size / columns.toFloat()).toInt()) {
Row { Row {

View File

@ -1,6 +1,6 @@
package de.mm20.launcher2.ui.launcher.search.common.list package de.mm20.launcher2.ui.launcher.search.common.list
import androidx.compose.animation.animateContentSize import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@ -9,14 +9,17 @@ import androidx.compose.runtime.key
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import de.mm20.launcher2.search.data.Searchable import de.mm20.launcher2.search.data.Searchable
import de.mm20.launcher2.ui.layout.BottomReversed
@Composable @Composable
fun SearchResultList( fun SearchResultList(
items: List<Searchable>, items: List<Searchable>,
modifier: Modifier = Modifier modifier: Modifier = Modifier,
reverse: Boolean = false
) { ) {
Column( Column(
modifier = modifier modifier = modifier,
verticalArrangement = if (reverse) Arrangement.Top else Arrangement.BottomReversed
) { ) {
for (item in items) { for (item in items) {
key(item.key) { key(item.key) {

View File

@ -24,7 +24,7 @@ import de.mm20.launcher2.ui.launcher.search.SearchVM
import de.mm20.launcher2.ui.launcher.search.common.list.SearchResultList import de.mm20.launcher2.ui.launcher.search.common.list.SearchResultList
@Composable @Composable
fun ColumnScope.ContactResults() { fun ColumnScope.ContactResults(reverse: Boolean = false) {
val viewModel: SearchVM = viewModel() val viewModel: SearchVM = viewModel()
val context = LocalContext.current val context = LocalContext.current
val contacts by viewModel.contactResults.observeAsState(emptyList()) val contacts by viewModel.contactResults.observeAsState(emptyList())
@ -34,7 +34,7 @@ fun ColumnScope.ContactResults() {
AnimatedVisibility(contacts.isNotEmpty() || (!isSearchEmpty && missingPermission)) { AnimatedVisibility(contacts.isNotEmpty() || (!isSearchEmpty && missingPermission)) {
LauncherCard( LauncherCard(
modifier = Modifier modifier = Modifier
.padding(bottom = 8.dp) .padding(bottom = if (reverse) 0.dp else 8.dp, top = if (reverse) 8.dp else 0.dp)
.fillMaxWidth() .fillMaxWidth()
) { ) {
Column { Column {
@ -58,7 +58,8 @@ fun ColumnScope.ContactResults() {
items = contacts, items = contacts,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(12.dp) .padding(12.dp),
reverse = reverse
) )
} }
} }

View File

@ -14,7 +14,9 @@ import de.mm20.launcher2.ui.launcher.search.SearchVM
import de.mm20.launcher2.ui.launcher.search.common.grid.SearchResultGrid import de.mm20.launcher2.ui.launcher.search.common.grid.SearchResultGrid
@Composable @Composable
fun ColumnScope.FavoritesResults() { fun ColumnScope.FavoritesResults(
reverse: Boolean = false,
) {
val viewModel: SearchVM = viewModel() val viewModel: SearchVM = viewModel()
val favorites by viewModel.favorites.observeAsState(emptyList()) val favorites by viewModel.favorites.observeAsState(emptyList())
@ -22,9 +24,10 @@ fun ColumnScope.FavoritesResults() {
AnimatedVisibility(!hide && favorites.isNotEmpty()) { AnimatedVisibility(!hide && favorites.isNotEmpty()) {
LauncherCard( LauncherCard(
modifier = Modifier.padding(bottom = 8.dp) modifier = Modifier
.padding(bottom = if (reverse) 0.dp else 8.dp, top = if (reverse) 8.dp else 0.dp)
) { ) {
SearchResultGrid(items = favorites) SearchResultGrid(items = favorites, reverse = reverse)
} }
} }
} }

View File

@ -24,7 +24,7 @@ import de.mm20.launcher2.ui.launcher.search.SearchVM
import de.mm20.launcher2.ui.launcher.search.common.list.SearchResultList import de.mm20.launcher2.ui.launcher.search.common.list.SearchResultList
@Composable @Composable
fun ColumnScope.FileResults() { fun ColumnScope.FileResults(reverse: Boolean = false) {
val viewModel: SearchVM = viewModel() val viewModel: SearchVM = viewModel()
val files by viewModel.fileResults.observeAsState(emptyList()) val files by viewModel.fileResults.observeAsState(emptyList())
val context = LocalContext.current val context = LocalContext.current
@ -34,7 +34,7 @@ fun ColumnScope.FileResults() {
AnimatedVisibility(files.isNotEmpty() || (!isSearchEmpty && missingPermission)) { AnimatedVisibility(files.isNotEmpty() || (!isSearchEmpty && missingPermission)) {
LauncherCard( LauncherCard(
modifier = Modifier modifier = Modifier
.padding(bottom = 8.dp) .padding(bottom = if (reverse) 0.dp else 8.dp, top = if (reverse) 8.dp else 0.dp)
.fillMaxWidth() .fillMaxWidth()
) { ) {
Column { Column {
@ -58,7 +58,8 @@ fun ColumnScope.FileResults() {
items = files, items = files,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(12.dp) .padding(12.dp),
reverse = reverse
)} )}
} }
} }

View File

@ -14,13 +14,14 @@ import de.mm20.launcher2.ui.launcher.search.SearchVM
import de.mm20.launcher2.ui.search.UnitConverterItem import de.mm20.launcher2.ui.search.UnitConverterItem
@Composable @Composable
fun ColumnScope.UnitConverterResults() { fun ColumnScope.UnitConverterResults(reverse: Boolean = false) {
val viewModel: SearchVM = viewModel() val viewModel: SearchVM = viewModel()
val unitConverter by viewModel.unitConverterResult.observeAsState(null) val unitConverter by viewModel.unitConverterResult.observeAsState(null)
AnimatedVisibility(unitConverter != null) { AnimatedVisibility(unitConverter != null) {
LauncherCard( LauncherCard(
modifier = Modifier.padding(bottom = 8.dp) modifier = Modifier
.padding(bottom = if (reverse) 0.dp else 8.dp, top = if (reverse) 8.dp else 0.dp)
) { ) {
unitConverter?.let { UnitConverterItem(unitConverter = it) } unitConverter?.let { UnitConverterItem(unitConverter = it) }
} }

View File

@ -13,13 +13,14 @@ import de.mm20.launcher2.ui.component.LauncherCard
import de.mm20.launcher2.ui.launcher.search.SearchVM import de.mm20.launcher2.ui.launcher.search.SearchVM
@Composable @Composable
fun ColumnScope.WebsiteResults() { fun ColumnScope.WebsiteResults(reverse: Boolean = false) {
val viewModel: SearchVM = viewModel() val viewModel: SearchVM = viewModel()
val website by viewModel.websiteResult.observeAsState(null) val website by viewModel.websiteResult.observeAsState(null)
AnimatedVisibility(website != null) { AnimatedVisibility(website != null) {
LauncherCard( LauncherCard(
modifier = Modifier.padding(bottom = 8.dp) modifier = Modifier
.padding(bottom = if (reverse) 0.dp else 8.dp, top = if (reverse) 8.dp else 0.dp)
) { ) {
website?.let { WebsiteItem(website = it) } website?.let { WebsiteItem(website = it) }
} }

View File

@ -13,13 +13,14 @@ import de.mm20.launcher2.ui.component.LauncherCard
import de.mm20.launcher2.ui.launcher.search.SearchVM import de.mm20.launcher2.ui.launcher.search.SearchVM
@Composable @Composable
fun ColumnScope.WikipediaResults() { fun ColumnScope.WikipediaResults(reverse: Boolean = false) {
val viewModel: SearchVM = viewModel() val viewModel: SearchVM = viewModel()
val wikipedia by viewModel.wikipediaResult.observeAsState(null) val wikipedia by viewModel.wikipediaResult.observeAsState(null)
AnimatedVisibility(wikipedia != null) { AnimatedVisibility(wikipedia != null) {
LauncherCard( LauncherCard(
modifier = Modifier.padding(bottom = 8.dp) modifier = Modifier
.padding(bottom = if (reverse) 0.dp else 8.dp, top = if (reverse) 8.dp else 0.dp)
) { ) {
wikipedia?.let { WikipediaItem(wikipedia = it) } wikipedia?.let { WikipediaItem(wikipedia = it) }
} }

View File

@ -49,6 +49,7 @@ import kotlinx.coroutines.launch
fun WidgetColumn( fun WidgetColumn(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
clockHeight: Dp = 0.dp, clockHeight: Dp = 0.dp,
clockBottomPadding: Dp = 0.dp,
editMode: Boolean = false, editMode: Boolean = false,
onEditModeChange: (Boolean) -> Unit, onEditModeChange: (Boolean) -> Unit,
) { ) {
@ -91,7 +92,8 @@ fun WidgetColumn(
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.height(clockHeight), .height(clockHeight)
.padding(bottom = clockBottomPadding),
contentAlignment = Alignment.BottomCenter contentAlignment = Alignment.BottomCenter
) { ) {
ClockWidget( ClockWidget(