fix floating bar for 3-button nav + start work for displaying recent searches

This commit is contained in:
Owen LeJeune
2023-07-30 12:21:05 -04:00
parent fdccd0b9bf
commit a688d043ff
6 changed files with 143 additions and 9 deletions

View File

@@ -6,6 +6,7 @@ import android.os.Bundle
import android.widget.Toast
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
@@ -96,7 +97,10 @@ class MainActivity : MonetCompatActivity() {
) { innerPadding ->
val windowSize = rememberWindowSizeClass()
val appNavController = rememberNavController()
Box(modifier = Modifier.padding(innerPadding.copy(bottom = 0.dp, top = 0.dp))) {
Box(modifier = Modifier
.padding(innerPadding.copy(bottom = 0.dp, top = 0.dp))
.fillMaxSize()
) {
AppNavigationHost(
appNavController = appNavController,
mainNavStartRoute = mainNavStartRoute,

View File

@@ -37,6 +37,7 @@ class AppPreferences(context: Context) {
private val SHOW_NEXT_MCU = "show_next_mcu"
private val STORED_TEST_ROUTE = "stored_test_route"
private val FLOATING_BOTTOM_BAR = "floating_bottom_bar"
private val RECENT_SEARCHES = "recent_searches"
}
private val preferences: SharedPreferences = context.getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE)
@@ -147,6 +148,11 @@ class AppPreferences(context: Context) {
get() = preferences.getString(STORED_TEST_ROUTE, storedTestRouteDefault) ?: storedTestRouteDefault
set(value) { preferences.put(STORED_TEST_ROUTE, value) }
/******** General Storage ********/
var recentSearches: Set<String>
get() = preferences.getStringSet(RECENT_SEARCHES, emptySet()) ?: emptySet()
set(value) { preferences.put(RECENT_SEARCHES, value) }
/********* Helpers ********/
private fun SharedPreferences.put(key: String, value: Any?) {
edit().apply {
@@ -157,6 +163,7 @@ class AppPreferences(context: Context) {
is Float -> putFloat(key, value)
is Double -> putFloat(key, value.toFloat())
is String -> putString(key, value)
is Set<*> -> putStringSet(key, value as Set<String>)
else -> throw UnsupportedTypeError()
}
apply()

View File

@@ -231,7 +231,11 @@ fun SearchView(
onClick = {
appNavController.navigate(route)
},
modifier = Modifier.offset(y = if (preferences.floatingBottomBar) -(HomeScreen.FLOATING_NAV_BAR_HEIGHT - HomeScreen.FLOATING_NAV_BAR_OFFSET) else 0.dp)
modifier = Modifier
.navigationBarsPadding()
.offset(
y = if (preferences.floatingBottomBar) -(HomeScreen.FLOATING_NAV_BAR_HEIGHT - HomeScreen.FLOATING_NAV_BAR_OFFSET) else 0.dp
)
) {
Icon(Icons.Filled.Search, stringResource(id = R.string.preference_heading_search))
}

View File

@@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
@@ -37,6 +38,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.compositeOver
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
@@ -62,7 +64,7 @@ import org.koin.java.KoinJavaComponent.get
object HomeScreen {
val FLOATING_NAV_BAR_HEIGHT = 80.dp
val FLOATING_NAV_BAR_OFFSET = (-24).dp
val FLOATING_NAV_BAR_OFFSET = (-12).dp
}
@OptIn(ExperimentalMaterial3Api::class)
@@ -116,7 +118,10 @@ fun HomeScreen(
}
}
) { innerPadding ->
Box(modifier = Modifier.padding(innerPadding)) {
Box(modifier = Modifier
.padding(innerPadding)
.fillMaxSize()
) {
MainContent(
windowSize = windowSize,
appNavController = appNavController,
@@ -167,9 +172,11 @@ private fun FloatingBottomNavBar(
modifier = modifier.then(
Modifier
.fillMaxWidth()
.height(HomeScreen.FLOATING_NAV_BAR_HEIGHT)
.navigationBarsPadding()
.padding(horizontal = 24.dp)
.offset(y = HomeScreen.FLOATING_NAV_BAR_OFFSET)
.padding(bottom = 12.dp)
.height(HomeScreen.FLOATING_NAV_BAR_HEIGHT)
// .offset(y = HomeScreen.FLOATING_NAV_BAR_OFFSET)
.clip(RoundedCornerShape(50))
.background(MaterialTheme.colorScheme.defaultNavBarColor())
)
@@ -181,7 +188,9 @@ private fun FloatingBottomNavBar(
HomeScreenNavItem.SortedItems.forEach { item ->
val isSelected = currentRoute == item.route
NavigationBarItem(
modifier = Modifier.clip(RoundedCornerShape(25.dp)),
modifier = Modifier
.clip(RoundedCornerShape(25.dp))
.padding(top = 4.dp),
icon = { Icon(imageVector = item.icon, contentDescription = null) },
label = {
if (preferences.showBottomTabLabels) {

View File

@@ -1,13 +1,17 @@
@file:Suppress("UNCHECKED_CAST")
package com.owenlejeune.tvtime.ui.screens
import android.content.Context
import android.widget.Toast
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Clear
import androidx.compose.material.icons.outlined.Restore
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
@@ -17,11 +21,13 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.paging.LoadState
import androidx.paging.PagingData
import androidx.paging.compose.collectAsLazyPagingItems
import com.owenlejeune.tvtime.R
import com.owenlejeune.tvtime.api.tmdb.api.v3.MoviesService
@@ -29,6 +35,7 @@ import com.owenlejeune.tvtime.api.tmdb.api.v3.TvService
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.*
import com.owenlejeune.tvtime.extensions.getCalendarYear
import com.owenlejeune.tvtime.extensions.lazyPagingItems
import com.owenlejeune.tvtime.preferences.AppPreferences
import com.owenlejeune.tvtime.ui.components.BackButton
import com.owenlejeune.tvtime.ui.components.MediaResultCard
import com.owenlejeune.tvtime.ui.components.PillSegmentedControl
@@ -38,6 +45,8 @@ import com.owenlejeune.tvtime.ui.viewmodel.MainViewModel
import com.owenlejeune.tvtime.ui.viewmodel.SearchViewModel
import com.owenlejeune.tvtime.utils.TmdbUtils
import com.owenlejeune.tvtime.utils.types.MediaViewType
import com.owenlejeune.tvtime.utils.types.ViewableMediaTypeException
import kotlinx.coroutines.flow.Flow
import org.koin.java.KoinJavaComponent.get
@OptIn(ExperimentalMaterial3Api::class)
@@ -45,7 +54,8 @@ import org.koin.java.KoinJavaComponent.get
fun SearchScreen(
appNavController: NavHostController,
title: String,
mediaViewType: MediaViewType
mediaViewType: MediaViewType,
preferences: AppPreferences = get(AppPreferences::class.java)
) {
val searchViewModel = viewModel<SearchViewModel>()
val applicationViewModel = viewModel<ApplicationViewModel>()
@@ -104,7 +114,15 @@ fun SearchScreen(
Divider(thickness = 2.dp, color = MaterialTheme.colorScheme.surfaceVariant)
val searchTypes = listOf(MediaViewType.MOVIE, MediaViewType.TV, MediaViewType.PERSON, MediaViewType.MIXED)
val selected = remember { mutableStateOf(searchTypes[0]) }
val selected = remember {
mutableStateOf(
if (preferences.multiSearch) {
MediaViewType.MIXED
} else {
mediaViewType
}
)
}
val context = LocalContext.current
PillSegmentedControl(
@@ -121,9 +139,90 @@ fun SearchScreen(
onItemSelected = { _, i ->
selected.value = i
},
defaultSelectedItemIndex = searchTypes.indexOf(selected.value),
modifier = Modifier.padding(start = 12.dp, top = 12.dp, end = 12.dp)
)
Spacer(modifier = Modifier.height(12.dp))
val results = remember { searchViewModel.produceSearchResultsFor(viewType.value) }
results.value?.let {
val pagingItems = (results.value as Flow<PagingData<SortableSearchResult>>).collectAsLazyPagingItems()
LazyColumn(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 12.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
handleLoadState(context, pagingItems.loadState.refresh)
item {
if (pagingItems.itemCount == 0) {
Column(
modifier = Modifier.fillMaxSize()
) {
Spacer(modifier = Modifier.weight(1f))
Text(
text = stringResource(R.string.no_search_results),
color = MaterialTheme.colorScheme.onBackground,
modifier = Modifier.align(Alignment.CenterHorizontally),
fontSize = 18.sp
)
Spacer(modifier = Modifier.weight(1f))
}
}
}
lazyPagingItems(
lazyPagingItems = pagingItems,
key = { i -> pagingItems[i]?.id ?: -1 }
) { item ->
when (item?.mediaType) {
MediaViewType.MOVIE -> {
MovieSearchResultView(
appNavController = appNavController,
result = item as SearchResultMovie
)
}
MediaViewType.TV -> {
TvSearchResultView(
appNavController = appNavController,
result = item as SearchResultTv
)
}
MediaViewType.PERSON -> {
PeopleSearchResultView(
appNavController = appNavController,
result = item as SearchResultPerson
)
}
else -> {}
}
}
item { Spacer(modifier = Modifier.height(12.dp)) }
handleLoadState(context, pagingItems.loadState.refresh)
}
} ?: run {
listOf("Michael Meyers", "Mutant", "Deadpool", "Ryan Reynolds", "Boardwalk Empire")//preferences.recentSearches
.forEach {
Row(
modifier = Modifier
.padding(vertical = 12.dp, horizontal = 16.dp)
.clickable {
searchValue.value = it
},
horizontalArrangement = Arrangement.spacedBy(12.dp)
) {
Icon(
imageVector = Icons.Outlined.Restore,
contentDescription = null
)
Text(
text = it,
fontStyle = FontStyle.Italic
)
}
}
}
when (viewType.value) {
MediaViewType.TV -> {
TvResultsView(appNavController = appNavController, searchViewModel = searchViewModel)

View File

@@ -9,6 +9,7 @@ import com.owenlejeune.tvtime.api.tmdb.api.v3.SearchResultProvider
import com.owenlejeune.tvtime.api.tmdb.api.v3.SearchService
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.Searchable
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.SortableSearchResult
import com.owenlejeune.tvtime.api.tmdb.api.v3.model.TmdbItem
import com.owenlejeune.tvtime.utils.types.MediaViewType
import com.owenlejeune.tvtime.utils.types.ViewableMediaTypeException
import kotlinx.coroutines.flow.Flow
@@ -41,6 +42,16 @@ class SearchViewModel: ViewModel(), KoinComponent {
}
}
fun produceSearchResultsFor(type: MediaViewType): MutableState<out Flow<PagingData<out SortableSearchResult>>?> {
return when (type) {
MediaViewType.MOVIE -> movieResults
MediaViewType.TV -> tvResults
MediaViewType.PERSON -> peopleResults
MediaViewType.MIXED -> multiResults
else -> throw ViewableMediaTypeException(type)
}
}
fun searchForMovies(query: String) {
movieResults.value = createPagingSource { service.searchMovies(query, it) }
}