Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix duplicate copies of homescreen in backstack #158

Merged
merged 1 commit into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class EpubXMLFileParser(
"EpubXMLFileParser",
"Fragment ID: $fragmentId doesn't represent a <div> tag. Using the fragment and next fragment logic."
)
// If the fragment ID doesn't represent a <body> tag, use the fragment and next fragment logic
// If the fragment ID doesn't represent a <div> tag, use the fragment and next fragment logic
val fragmentElement = document.selectFirst("#$fragmentId")
title = fragmentElement?.selectFirst("h1, h2, h3, h4, h5, h6")?.text() ?: ""
val bodyBuilder = StringBuilder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
Expand All @@ -82,6 +83,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import coil.annotation.ExperimentalCoilApi
import com.starry.myne.R
Expand All @@ -92,8 +94,11 @@ import com.starry.myne.ui.common.BookItemCard
import com.starry.myne.ui.common.BookLanguageButton
import com.starry.myne.ui.common.NetworkError
import com.starry.myne.ui.common.ProgressDots
import com.starry.myne.ui.navigation.BottomBarScreen
import com.starry.myne.ui.navigation.Screens
import com.starry.myne.ui.screens.home.viewmodels.AllBooksState
import com.starry.myne.ui.screens.home.viewmodels.HomeViewModel
import com.starry.myne.ui.screens.home.viewmodels.SearchBarState
import com.starry.myne.ui.screens.home.viewmodels.UserAction
import com.starry.myne.ui.theme.figeronaFont
import com.starry.myne.ui.theme.pacificoFont
Expand All @@ -117,8 +122,8 @@ fun HomeScreen(navController: NavController, networkStatus: NetworkObserver.Stat
*/
val sysBackButtonState = remember { mutableStateOf(false) }
BackHandler(enabled = sysBackButtonState.value) {
if (viewModel.topBarState.isSearchBarVisible) {
if (viewModel.topBarState.searchText.isNotEmpty()) {
if (viewModel.searchBarState.isSearchBarVisible) {
if (viewModel.searchBarState.searchText.isNotEmpty()) {
viewModel.onAction(UserAction.TextFieldInput("", networkStatus))
} else {
viewModel.onAction(UserAction.CloseIconClicked)
Expand All @@ -131,6 +136,18 @@ fun HomeScreen(navController: NavController, networkStatus: NetworkObserver.Stat
val modalBottomSheetState = rememberModalBottomSheetState(
initialValue = ModalBottomSheetValue.Hidden
)

// Close search bar when navigating to other screens.
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
LaunchedEffect(currentDestination) {
if (currentDestination?.route != BottomBarScreen.Home.route) {
viewModel.onAction(UserAction.TextFieldInput("", networkStatus))
viewModel.onAction(UserAction.CloseIconClicked)
}
}


ModalBottomSheetLayout(
sheetState = modalBottomSheetState,
sheetShape = RoundedCornerShape(topStart = 24.dp, topEnd = 24.dp),
Expand Down Expand Up @@ -206,7 +223,7 @@ private fun HomeScreenScaffold(
) {
val keyboardController = LocalSoftwareKeyboardController.current
val focusManager = LocalFocusManager.current
val topBarState = viewModel.topBarState
val topBarState = viewModel.searchBarState

Scaffold(
modifier = Modifier
Expand Down Expand Up @@ -275,7 +292,7 @@ fun HomeScreenContents(
navController: NavController,
paddingValues: PaddingValues
) {
val topBarState = viewModel.topBarState
val topBarState = viewModel.searchBarState
val allBooksState = viewModel.allBooksState


Expand All @@ -288,119 +305,15 @@ fun HomeScreenContents(

// If search text is empty show list of all books.
if (topBarState.searchText.isBlank()) {
// show fullscreen progress indicator when loading the first page.
if (allBooksState.page == 1L && allBooksState.isLoading) {
Box(
modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center
) {
CircularProgressIndicator(color = MaterialTheme.colorScheme.primary)
}
} else if (!allBooksState.isLoading && allBooksState.error != null) {
NetworkError(onRetryClicked = { viewModel.reloadItems() })
} else {
LazyVerticalGrid(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.padding(start = 8.dp, end = 8.dp),
columns = GridCells.Adaptive(295.dp)
) {
items(allBooksState.items.size) { i ->
val item = allBooksState.items[i]
if (networkStatus == NetworkObserver.Status.Available
&& i >= allBooksState.items.size - 1
&& !allBooksState.endReached
&& !allBooksState.isLoading
) {
viewModel.loadNextItems()
}
Box(
modifier = Modifier
.padding(4.dp)
.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
BookItemCard(
title = item.title,
author = BookUtils.getAuthorsAsString(item.authors),
language = BookUtils.getLanguagesAsString(item.languages),
subjects = BookUtils.getSubjectsAsString(
item.subjects, 3
),
coverImageUrl = item.formats.imagejpeg
) {
navController.navigate(
Screens.BookDetailScreen.withBookId(
item.id.toString()
)
)
}
}

}
item {
if (allBooksState.isLoading) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
horizontalArrangement = Arrangement.Center
) {
ProgressDots()
}
}
}
}
}

// Else show the search results.
AllBooksList(
allBooksState = allBooksState,
networkStatus = networkStatus,
navController = navController,
onRetryClicked = { viewModel.reloadItems() },
onLoadNextItems = { viewModel.loadNextItems() }
)
} else {
LazyVerticalGrid(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.padding(start = 8.dp, end = 8.dp),
columns = GridCells.Adaptive(295.dp)
) {
if (topBarState.isSearching) {
item {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
horizontalArrangement = Arrangement.Center
) {
ProgressDots()
}
}
}

items(topBarState.searchResults.size) { i ->
val item = topBarState.searchResults[i]
Box(
modifier = Modifier
.padding(4.dp)
.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
BookItemCard(
title = item.title,
author = BookUtils.getAuthorsAsString(item.authors),
language = BookUtils.getLanguagesAsString(item.languages),
subjects = BookUtils.getSubjectsAsString(
item.subjects, 3
),
coverImageUrl = item.formats.imagejpeg
) {
navController.navigate(
Screens.BookDetailScreen.withBookId(
item.id.toString()
)
)
}
}
}
}
SearchBookList(searchBarState = topBarState, navController = navController)
}
}

Expand Down Expand Up @@ -446,6 +359,130 @@ private fun HomeTopAppBar(
}
}

@Composable
private fun AllBooksList(
allBooksState: AllBooksState,
networkStatus: NetworkObserver.Status,
navController: NavController,
onRetryClicked: () -> Unit,
onLoadNextItems: () -> Unit
) {
// show fullscreen progress indicator when loading the first page.
if (allBooksState.page == 1L && allBooksState.isLoading) {
Box(
modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center
) {
CircularProgressIndicator(color = MaterialTheme.colorScheme.primary)
}
} else if (!allBooksState.isLoading && allBooksState.error != null) {
NetworkError(onRetryClicked = { onRetryClicked() })
} else {
LazyVerticalGrid(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.padding(start = 8.dp, end = 8.dp),
columns = GridCells.Adaptive(295.dp)
) {
items(allBooksState.items.size) { i ->
val item = allBooksState.items[i]
if (networkStatus == NetworkObserver.Status.Available
&& i >= allBooksState.items.size - 1
&& !allBooksState.endReached
&& !allBooksState.isLoading
) {
onLoadNextItems()
}
Box(
modifier = Modifier
.padding(4.dp)
.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
BookItemCard(
title = item.title,
author = BookUtils.getAuthorsAsString(item.authors),
language = BookUtils.getLanguagesAsString(item.languages),
subjects = BookUtils.getSubjectsAsString(
item.subjects, 3
),
coverImageUrl = item.formats.imagejpeg
) {
navController.navigate(
Screens.BookDetailScreen.withBookId(
item.id.toString()
)
)
}
}

}
item {
if (allBooksState.isLoading) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
horizontalArrangement = Arrangement.Center
) {
ProgressDots()
}
}
}
}
}
}

@Composable
private fun SearchBookList(searchBarState: SearchBarState, navController: NavController) {
LazyVerticalGrid(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.padding(start = 8.dp, end = 8.dp),
columns = GridCells.Adaptive(295.dp)
) {
if (searchBarState.isSearching) {
item {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
horizontalArrangement = Arrangement.Center
) {
ProgressDots()
}
}
}

items(searchBarState.searchResults.size) { i ->
val item = searchBarState.searchResults[i]
Box(
modifier = Modifier
.padding(4.dp)
.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
BookItemCard(
title = item.title,
author = BookUtils.getAuthorsAsString(item.authors),
language = BookUtils.getLanguagesAsString(item.languages),
subjects = BookUtils.getSubjectsAsString(
item.subjects, 3
),
coverImageUrl = item.formats.imagejpeg
) {
navController.navigate(
Screens.BookDetailScreen.withBookId(
item.id.toString()
)
)
}
}
}
}
}

@ExperimentalMaterial3Api
@Composable
private fun SearchAppBar(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ data class AllBooksState(
val page: Long = 1L
)

data class TopBarState(
data class SearchBarState(
val searchText: String = "",
val isSearchBarVisible: Boolean = false,
val isSortMenuVisible: Boolean = false,
Expand All @@ -70,7 +70,7 @@ class HomeViewModel @Inject constructor(
private val preferenceUtil: PreferenceUtil
) : ViewModel() {
var allBooksState by mutableStateOf(AllBooksState())
var topBarState by mutableStateOf(TopBarState())
var searchBarState by mutableStateOf(SearchBarState())

private val _language: MutableState<BookLanguage> = mutableStateOf(getPreferredLanguage())
val language: State<BookLanguage> = _language
Expand Down Expand Up @@ -129,20 +129,20 @@ class HomeViewModel @Inject constructor(
fun onAction(userAction: UserAction) {
when (userAction) {
UserAction.CloseIconClicked -> {
topBarState = topBarState.copy(isSearchBarVisible = false)
searchBarState = searchBarState.copy(isSearchBarVisible = false)
}

UserAction.SearchIconClicked -> {
topBarState = topBarState.copy(isSearchBarVisible = true)
searchBarState = searchBarState.copy(isSearchBarVisible = true)
}

is UserAction.TextFieldInput -> {
topBarState = topBarState.copy(searchText = userAction.text)
searchBarState = searchBarState.copy(searchText = userAction.text)
if (userAction.networkStatus == NetworkObserver.Status.Available) {
searchJob?.cancel()
searchJob = viewModelScope.launch {
if (userAction.text.isNotBlank()) {
topBarState = topBarState.copy(isSearching = true)
searchBarState = searchBarState.copy(isSearching = true)
}
delay(500L)
searchBooks(userAction.text)
Expand All @@ -159,7 +159,7 @@ class HomeViewModel @Inject constructor(
private suspend fun searchBooks(query: String) {
val bookSet = bookAPI.searchBooks(query)
val books = bookSet.getOrNull()!!.books.filter { it.formats.applicationepubzip != null }
topBarState = topBarState.copy(searchResults = books, isSearching = false)
searchBarState = searchBarState.copy(searchResults = books, isSearching = false)
}

private fun changeLanguage(language: BookLanguage) {
Expand Down
Loading
Loading