mirror of
https://github.com/owenlejeune/TVTime.git
synced 2025-11-08 12:42:44 -05:00
fix floating bar for 3-button nav + start work for displaying recent searches
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user