Add alternative layout
This commit is contained in:
parent
78593e0391
commit
7fda28aedd
@ -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" />
|
||||||
|
|
||||||
|
|||||||
@ -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()
|
||||||
|
|||||||
180
ui/src/main/java/de/mm20/launcher2/ui/launcher/PagerScaffold.kt
Normal file
180
ui/src/main/java/de/mm20/launcher2/ui/launcher/PagerScaffold.kt
Normal 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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -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,
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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) }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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
|
||||||
)}
|
)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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) }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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) }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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) }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user