Skip to content

Commit

Permalink
- Feat: Add Favorite Prompt in Reader
Browse files Browse the repository at this point in the history
This commit introduces a prompt to encourage users to add a manga to their favorites after reading a few chapters.

- A dialog is displayed asking the user if they want to add the manga to their favorites.
- The dialog is triggered after the user has read a certain number of chapters and the manga is not already in their favorites.
- A favorite counter is added to track the number of chapters read.
- If the user accepts the dialog, the manga is added to their favorites.
- If the user dismisses the dialog, it will not be shown again for that manga.
- Updated shimmer effect in Recent fragment to only pad from the top.
  • Loading branch information
jacobrein committed Nov 20, 2024
1 parent 406cffd commit e83389e
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ fun RecentView(
Box(
Modifier
.fillMaxSize()
.padding(p)
.padding(top = p.calculateTopPadding())
) { info.ComposeShimmerItem() }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.LazyGridState
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.itemsIndexed
Expand Down Expand Up @@ -203,11 +202,9 @@ class GenericManga(
override fun ComposeShimmerItem() {
LazyVerticalGrid(
columns = adaptiveGridCell(),
modifier = Modifier
.fillMaxSize()
.padding(vertical = 4.dp),
verticalArrangement = Arrangement.spacedBy(4.dp),
horizontalArrangement = Arrangement.spacedBy(4.dp)
horizontalArrangement = Arrangement.spacedBy(4.dp),
modifier = Modifier.fillMaxSize(),
) { items(10) { M3PlaceHolderCoverCard(placeHolder = R.drawable.manga_world_round_logo) } }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,19 @@ import androidx.lifecycle.viewModelScope
import androidx.navigation.NavController
import com.programmersbox.favoritesdatabase.ChapterWatched
import com.programmersbox.favoritesdatabase.ItemDao
import com.programmersbox.favoritesdatabase.toDbModel
import com.programmersbox.mangaworld.ChapterHolder
import com.programmersbox.models.ChapterModel
import com.programmersbox.models.Storage
import com.programmersbox.sharedutils.FirebaseDb
import com.programmersbox.uiviews.GenericInfo
import com.programmersbox.uiviews.utils.dispatchIo
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
Expand All @@ -36,6 +40,8 @@ import kotlinx.serialization.Serializable
import org.koin.core.component.KoinComponent
import java.io.File

private const val FAVORITE_CHECK = 2

class ReadViewModel(
mangaReader: MangaReader,
private val dao: ItemDao,
Expand Down Expand Up @@ -73,7 +79,7 @@ class ReadViewModel(
mangaUrl: String? = null,
mangaInfoUrl: String? = null,
downloaded: Boolean = false,
filePath: String? = null
filePath: String? = null,
) {
navController.navigate(
MangaReader(
Expand Down Expand Up @@ -109,12 +115,27 @@ class ReadViewModel(

val currentChapterModel by derivedStateOf { list.getOrNull(currentChapter) }

private val itemListener = FirebaseDb.FirebaseListener()
var addToFavorites by mutableStateOf(FavoriteChecker(false, 0))

data class FavoriteChecker(val hasShown: Boolean, val count: Int, val isFavorite: Boolean = false) {
val shouldShow: Boolean = !hasShown && count > FAVORITE_CHECK && !isFavorite
}

init {
val url = chapterHolder.chapterModel?.url ?: mangaReader.mangaUrl
list = chapterHolder.chapters.orEmpty()
currentChapter = list.indexOfFirst { l -> l.url == url }.coerceIn(0, list.lastIndex)

loadPages(modelPath)

combine(
itemListener.findItemByUrlFlow(mangaUrl),
dao.containsItem(mangaUrl)
) { f, d -> f || d }
.dispatchIo()
.onEach { addToFavorites = addToFavorites.copy(isFavorite = it) }
.launchIn(viewModelScope)
}

var showInfo by mutableStateOf(true)
Expand All @@ -123,6 +144,7 @@ class ReadViewModel(

fun addChapterToWatched(newChapter: Int, chapter: () -> Unit) {
currentChapter = newChapter
addToFavorites = addToFavorites.copy(count = addToFavorites.count + 1)
list.getOrNull(newChapter)?.let { item ->
ChapterWatched(item.url, item.name, mangaUrl)
.let {
Expand All @@ -140,6 +162,21 @@ class ReadViewModel(
}
}

fun addToFavorites() {
addToFavorites = addToFavorites.copy(hasShown = true)
viewModelScope.launch {
currentChapterModel
?.source
?.getSourceByUrlFlow(mangaUrl)
?.firstOrNull()
?.toDbModel()
?.let {
dao.insertFavorite(it)
FirebaseDb.insertShowFlow(it).collect()
}
}
}

private fun loadPages(modelPath: Flow<List<String>>?) {
modelPath
?.onStart {
Expand Down Expand Up @@ -167,5 +204,6 @@ class ReadViewModel(
super.onCleared()
chapterHolder.chapterModel = null
chapterHolder.chapters = null
itemListener.unregister()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,12 @@ fun ReadView(
}
}

AddToFavoritesDialog(
show = readVm.addToFavorites.shouldShow,
onDismiss = { readVm.addToFavorites = readVm.addToFavorites.copy(hasShown = true) },
onAddToFavorites = readVm::addToFavorites
)

var settingsPopup by remember { mutableStateOf(false) }

if (settingsPopup) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
Expand All @@ -22,9 +23,11 @@ import androidx.compose.material.icons.filled.BatteryAlert
import androidx.compose.material.icons.filled.BorderBottom
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.FavoriteBorder
import androidx.compose.material.icons.filled.FormatLineSpacing
import androidx.compose.material.icons.filled.Gesture
import androidx.compose.material.icons.filled.Image
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
Expand All @@ -36,6 +39,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberModalBottomSheetState
Expand Down Expand Up @@ -409,4 +413,35 @@ internal fun SheetView(
}
}
}
}

@Composable
internal fun AddToFavoritesDialog(
show: Boolean,
onDismiss: () -> Unit,
onAddToFavorites: () -> Unit,
) {
if (show) {
AlertDialog(
onDismissRequest = onDismiss,
title = { Text("Add to Favorites?") },
text = {
Text("You have read a few chapters and seem to have some interest in this manga. Would you like to add it to your favorites?")
},
confirmButton = {
TextButton(
onClick = onAddToFavorites
) {
Icon(Icons.Default.FavoriteBorder, null)
Spacer(Modifier.size(4.dp))
Text("Add")
}
},
dismissButton = {
TextButton(
onClick = onDismiss
) { Text("Cancel") }
}
)
}
}

0 comments on commit e83389e

Please sign in to comment.