Fix tracker for multiple branches
This commit is contained in:
@@ -15,5 +15,6 @@ disabled_rules=no-wildcard-imports,no-unused-imports
|
|||||||
ij_continuation_indent_size = 4
|
ij_continuation_indent_size = 4
|
||||||
|
|
||||||
[{*.kt,*.kts}]
|
[{*.kt,*.kts}]
|
||||||
|
ij_kotlin_allow_trailing_comma_on_call_site = true
|
||||||
ij_kotlin_allow_trailing_comma = true
|
ij_kotlin_allow_trailing_comma = true
|
||||||
ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL
|
ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL
|
||||||
|
|||||||
@@ -1,6 +1,34 @@
|
|||||||
package org.koitharu.kotatsu.core.model
|
package org.koitharu.kotatsu.core.model
|
||||||
|
|
||||||
|
import androidx.core.os.LocaleListCompat
|
||||||
import org.koitharu.kotatsu.parsers.model.Manga
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
import org.koitharu.kotatsu.parsers.util.mapToSet
|
import org.koitharu.kotatsu.parsers.util.mapToSet
|
||||||
|
import org.koitharu.kotatsu.parsers.util.toTitleCase
|
||||||
|
import org.koitharu.kotatsu.utils.ext.iterator
|
||||||
|
|
||||||
fun Collection<Manga>.ids() = mapToSet { it.id }
|
fun Collection<Manga>.ids() = mapToSet { it.id }
|
||||||
|
|
||||||
|
fun Manga.getPreferredBranch(history: MangaHistory?): String? {
|
||||||
|
val ch = chapters
|
||||||
|
if (ch.isNullOrEmpty()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (history != null) {
|
||||||
|
val currentChapter = ch.find { it.id == history.chapterId }
|
||||||
|
if (currentChapter != null) {
|
||||||
|
return currentChapter.branch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val groups = ch.groupBy { it.branch }
|
||||||
|
for (locale in LocaleListCompat.getAdjustedDefault()) {
|
||||||
|
var language = locale.getDisplayLanguage(locale).toTitleCase(locale)
|
||||||
|
if (groups.containsKey(language)) {
|
||||||
|
return language
|
||||||
|
}
|
||||||
|
language = locale.getDisplayName(locale).toTitleCase(locale)
|
||||||
|
if (groups.containsKey(language)) {
|
||||||
|
return language
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return groups.maxByOrNull { it.value.size }?.key
|
||||||
|
}
|
||||||
@@ -105,7 +105,7 @@ class DetailsActivity :
|
|||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
this,
|
this,
|
||||||
getString(R.string._s_deleted_from_local_storage, manga.title),
|
getString(R.string._s_deleted_from_local_storage, manga.title),
|
||||||
Toast.LENGTH_SHORT
|
Toast.LENGTH_SHORT,
|
||||||
).show()
|
).show()
|
||||||
finishAfterTransition()
|
finishAfterTransition()
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,7 @@ class DetailsActivity :
|
|||||||
onActionClick = {
|
onActionClick = {
|
||||||
e.report("DetailsActivity::onError")
|
e.report("DetailsActivity::onError")
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
@@ -142,14 +142,14 @@ class DetailsActivity :
|
|||||||
|
|
||||||
override fun onWindowInsetsChanged(insets: Insets) {
|
override fun onWindowInsetsChanged(insets: Insets) {
|
||||||
binding.snackbar.updatePadding(
|
binding.snackbar.updatePadding(
|
||||||
bottom = insets.bottom
|
bottom = insets.bottom,
|
||||||
)
|
)
|
||||||
binding.toolbar.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
binding.toolbar.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
topMargin = insets.top
|
topMargin = insets.top
|
||||||
}
|
}
|
||||||
binding.root.updatePadding(
|
binding.root.updatePadding(
|
||||||
left = insets.left,
|
left = insets.left,
|
||||||
right = insets.right
|
right = insets.right,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,6 +159,7 @@ class DetailsActivity :
|
|||||||
tab.removeBadge()
|
tab.removeBadge()
|
||||||
} else {
|
} else {
|
||||||
val badge = tab.orCreateBadge
|
val badge = tab.orCreateBadge
|
||||||
|
badge.maxCharacterCount = 3
|
||||||
badge.number = newChapters
|
badge.number = newChapters
|
||||||
badge.isVisible = true
|
badge.isVisible = true
|
||||||
}
|
}
|
||||||
@@ -275,8 +276,8 @@ class DetailsActivity :
|
|||||||
ReaderActivity.newIntent(
|
ReaderActivity.newIntent(
|
||||||
context = this@DetailsActivity,
|
context = this@DetailsActivity,
|
||||||
manga = remoteManga,
|
manga = remoteManga,
|
||||||
state = ReaderState(chapterId, 0, 0)
|
state = ReaderState(chapterId, 0, 0),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
setNeutralButton(R.string.download) { _, _ ->
|
setNeutralButton(R.string.download) { _, _ ->
|
||||||
@@ -350,8 +351,8 @@ class DetailsActivity :
|
|||||||
dialogBuilder.setMessage(
|
dialogBuilder.setMessage(
|
||||||
getString(
|
getString(
|
||||||
R.string.large_manga_save_confirm,
|
R.string.large_manga_save_confirm,
|
||||||
resources.getQuantityString(R.plurals.chapters, chaptersCount, chaptersCount)
|
resources.getQuantityString(R.plurals.chapters, chaptersCount, chaptersCount),
|
||||||
)
|
),
|
||||||
).setPositiveButton(R.string.save) { _, _ ->
|
).setPositiveButton(R.string.save) { _, _ ->
|
||||||
DownloadService.start(this, manga)
|
DownloadService.start(this, manga)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.koitharu.kotatsu.details.ui
|
|||||||
|
|
||||||
import android.app.ActivityOptions
|
import android.app.ActivityOptions
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Spanned
|
|
||||||
import android.text.method.LinkMovementMethod
|
import android.text.method.LinkMovementMethod
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.appcompat.widget.PopupMenu
|
||||||
@@ -10,18 +9,15 @@ import androidx.core.content.ContextCompat
|
|||||||
import androidx.core.graphics.Insets
|
import androidx.core.graphics.Insets
|
||||||
import androidx.core.net.toFile
|
import androidx.core.net.toFile
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.core.text.parseAsHtml
|
|
||||||
import androidx.core.view.MenuProvider
|
import androidx.core.view.MenuProvider
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import coil.size.Scale
|
|
||||||
import coil.util.CoilUtils
|
import coil.util.CoilUtils
|
||||||
import com.google.android.material.chip.Chip
|
import com.google.android.material.chip.Chip
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.android.ext.android.get
|
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
@@ -33,6 +29,7 @@ import org.koitharu.kotatsu.bookmarks.domain.Bookmark
|
|||||||
import org.koitharu.kotatsu.bookmarks.ui.BookmarksAdapter
|
import org.koitharu.kotatsu.bookmarks.ui.BookmarksAdapter
|
||||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||||
import org.koitharu.kotatsu.databinding.FragmentDetailsBinding
|
import org.koitharu.kotatsu.databinding.FragmentDetailsBinding
|
||||||
|
import org.koitharu.kotatsu.details.ui.model.ChapterListItem
|
||||||
import org.koitharu.kotatsu.details.ui.scrobbling.ScrobblingInfoBottomSheet
|
import org.koitharu.kotatsu.details.ui.scrobbling.ScrobblingInfoBottomSheet
|
||||||
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesBottomSheet
|
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesBottomSheet
|
||||||
import org.koitharu.kotatsu.history.domain.PROGRESS_NONE
|
import org.koitharu.kotatsu.history.domain.PROGRESS_NONE
|
||||||
@@ -82,6 +79,7 @@ class DetailsFragment :
|
|||||||
viewModel.bookmarks.observe(viewLifecycleOwner, ::onBookmarksChanged)
|
viewModel.bookmarks.observe(viewLifecycleOwner, ::onBookmarksChanged)
|
||||||
viewModel.scrobblingInfo.observe(viewLifecycleOwner, ::onScrobblingInfoChanged)
|
viewModel.scrobblingInfo.observe(viewLifecycleOwner, ::onScrobblingInfoChanged)
|
||||||
viewModel.description.observe(viewLifecycleOwner, ::onDescriptionChanged)
|
viewModel.description.observe(viewLifecycleOwner, ::onDescriptionChanged)
|
||||||
|
viewModel.chapters.observe(viewLifecycleOwner, ::onChaptersChanged)
|
||||||
addMenuProvider(DetailsMenuProvider())
|
addMenuProvider(DetailsMenuProvider())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,18 +124,6 @@ class DetailsFragment :
|
|||||||
else -> textViewState.isVisible = false
|
else -> textViewState.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info containers
|
|
||||||
val chapters = manga.chapters
|
|
||||||
if (chapters.isNullOrEmpty()) {
|
|
||||||
infoLayout.textViewChapters.isVisible = false
|
|
||||||
} else {
|
|
||||||
infoLayout.textViewChapters.isVisible = true
|
|
||||||
infoLayout.textViewChapters.text = resources.getQuantityString(
|
|
||||||
R.plurals.chapters,
|
|
||||||
chapters.size,
|
|
||||||
chapters.size,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (manga.hasRating) {
|
if (manga.hasRating) {
|
||||||
infoLayout.textViewRating.text = String.format("%.1f", manga.rating * 5)
|
infoLayout.textViewRating.text = String.format("%.1f", manga.rating * 5)
|
||||||
infoLayout.ratingContainer.isVisible = true
|
infoLayout.ratingContainer.isVisible = true
|
||||||
@@ -164,14 +150,27 @@ class DetailsFragment :
|
|||||||
|
|
||||||
infoLayout.textViewNsfw.isVisible = manga.isNsfw
|
infoLayout.textViewNsfw.isVisible = manga.isNsfw
|
||||||
|
|
||||||
// Buttons
|
|
||||||
buttonRead.isEnabled = !manga.chapters.isNullOrEmpty()
|
|
||||||
|
|
||||||
// Chips
|
// Chips
|
||||||
bindTags(manga)
|
bindTags(manga)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onChaptersChanged(chapters: List<ChapterListItem>?) {
|
||||||
|
val infoLayout = binding.infoLayout
|
||||||
|
if (chapters.isNullOrEmpty()) {
|
||||||
|
infoLayout.textViewChapters.isVisible = false
|
||||||
|
} else {
|
||||||
|
infoLayout.textViewChapters.isVisible = true
|
||||||
|
infoLayout.textViewChapters.text = resources.getQuantityString(
|
||||||
|
R.plurals.chapters,
|
||||||
|
chapters.size,
|
||||||
|
chapters.size,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// Buttons
|
||||||
|
binding.buttonRead.isEnabled = !chapters.isNullOrEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
private fun onDescriptionChanged(description: CharSequence?) {
|
private fun onDescriptionChanged(description: CharSequence?) {
|
||||||
if (description.isNullOrBlank()) {
|
if (description.isNullOrBlank()) {
|
||||||
binding.textViewDescription.setText(R.string.no_description)
|
binding.textViewDescription.setText(R.string.no_description)
|
||||||
@@ -266,7 +265,7 @@ class DetailsFragment :
|
|||||||
context = context ?: return,
|
context = context ?: return,
|
||||||
manga = manga,
|
manga = manga,
|
||||||
branch = viewModel.selectedBranchValue,
|
branch = viewModel.selectedBranchValue,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -276,14 +275,14 @@ class DetailsFragment :
|
|||||||
context = v.context,
|
context = v.context,
|
||||||
source = manga.source,
|
source = manga.source,
|
||||||
query = manga.author ?: return,
|
query = manga.author ?: return,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
R.id.imageView_cover -> {
|
R.id.imageView_cover -> {
|
||||||
val options = ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.width, v.height)
|
val options = ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.width, v.height)
|
||||||
startActivity(
|
startActivity(
|
||||||
ImageActivity.newIntent(v.context, manga.largeCoverUrl.ifNullOrEmpty { manga.coverUrl }),
|
ImageActivity.newIntent(v.context, manga.largeCoverUrl.ifNullOrEmpty { manga.coverUrl }),
|
||||||
options.toBundle()
|
options.toBundle(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -309,8 +308,8 @@ class DetailsFragment :
|
|||||||
c.chapter.branch == branch
|
c.chapter.branch == branch
|
||||||
}?.let { c ->
|
}?.let { c ->
|
||||||
ReaderState(c.chapter.id, 0, 0)
|
ReaderState(c.chapter.id, 0, 0)
|
||||||
}
|
},
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@@ -343,7 +342,7 @@ class DetailsFragment :
|
|||||||
icon = 0,
|
icon = 0,
|
||||||
data = tag,
|
data = tag,
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package org.koitharu.kotatsu.details.ui
|
package org.koitharu.kotatsu.details.ui
|
||||||
|
|
||||||
import androidx.core.os.LocaleListCompat
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import org.koitharu.kotatsu.base.domain.MangaDataRepository
|
import org.koitharu.kotatsu.base.domain.MangaDataRepository
|
||||||
import org.koitharu.kotatsu.base.domain.MangaIntent
|
import org.koitharu.kotatsu.base.domain.MangaIntent
|
||||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||||
|
import org.koitharu.kotatsu.core.model.getPreferredBranch
|
||||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
import org.koitharu.kotatsu.details.ui.model.ChapterListItem
|
import org.koitharu.kotatsu.details.ui.model.ChapterListItem
|
||||||
@@ -17,8 +17,6 @@ import org.koitharu.kotatsu.parsers.model.Manga
|
|||||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
import org.koitharu.kotatsu.parsers.util.mapToSet
|
import org.koitharu.kotatsu.parsers.util.mapToSet
|
||||||
import org.koitharu.kotatsu.parsers.util.toTitleCase
|
|
||||||
import org.koitharu.kotatsu.utils.ext.iterator
|
|
||||||
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
|
import org.koitharu.kotatsu.utils.ext.printStackTraceDebug
|
||||||
|
|
||||||
class MangaDetailsDelegate(
|
class MangaDetailsDelegate(
|
||||||
@@ -45,12 +43,7 @@ class MangaDetailsDelegate(
|
|||||||
manga = MangaRepository(manga.source).getDetails(manga)
|
manga = MangaRepository(manga.source).getDetails(manga)
|
||||||
// find default branch
|
// find default branch
|
||||||
val hist = historyRepository.getOne(manga)
|
val hist = historyRepository.getOne(manga)
|
||||||
selectedBranch.value = if (hist != null) {
|
selectedBranch.value = manga.getPreferredBranch(hist)
|
||||||
val currentChapter = manga.chapters?.find { it.id == hist.chapterId }
|
|
||||||
if (currentChapter != null) currentChapter.branch else predictBranch(manga.chapters)
|
|
||||||
} else {
|
|
||||||
predictBranch(manga.chapters)
|
|
||||||
}
|
|
||||||
mangaData.value = manga
|
mangaData.value = manga
|
||||||
relatedManga.value = runCatching {
|
relatedManga.value = runCatching {
|
||||||
if (manga.source == MangaSource.LOCAL) {
|
if (manga.source == MangaSource.LOCAL) {
|
||||||
@@ -163,22 +156,4 @@ class MangaDetailsDelegate(
|
|||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun predictBranch(chapters: List<MangaChapter>?): String? {
|
|
||||||
if (chapters.isNullOrEmpty()) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
val groups = chapters.groupBy { it.branch }
|
|
||||||
for (locale in LocaleListCompat.getAdjustedDefault()) {
|
|
||||||
var language = locale.getDisplayLanguage(locale).toTitleCase(locale)
|
|
||||||
if (groups.containsKey(language)) {
|
|
||||||
return language
|
|
||||||
}
|
|
||||||
language = locale.getDisplayName(locale).toTitleCase(locale)
|
|
||||||
if (groups.containsKey(language)) {
|
|
||||||
return language
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return groups.maxByOrNull { it.value.size }?.key
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@ val trackerModule
|
|||||||
factory { TrackingRepository(get()) }
|
factory { TrackingRepository(get()) }
|
||||||
factory { TrackerNotificationChannels(androidContext(), get()) }
|
factory { TrackerNotificationChannels(androidContext(), get()) }
|
||||||
|
|
||||||
factory { Tracker(get(), get(), get()) }
|
factory { Tracker(get(), get(), get(), get()) }
|
||||||
|
|
||||||
viewModel { FeedViewModel(get()) }
|
viewModel { FeedViewModel(get()) }
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
package org.koitharu.kotatsu.tracker.domain
|
package org.koitharu.kotatsu.tracker.domain
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
|
import org.koitharu.kotatsu.core.model.getPreferredBranch
|
||||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
|
import org.koitharu.kotatsu.history.domain.HistoryRepository
|
||||||
import org.koitharu.kotatsu.parsers.model.Manga
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
import org.koitharu.kotatsu.tracker.domain.model.MangaTracking
|
import org.koitharu.kotatsu.tracker.domain.model.MangaTracking
|
||||||
import org.koitharu.kotatsu.tracker.domain.model.MangaUpdates
|
import org.koitharu.kotatsu.tracker.domain.model.MangaUpdates
|
||||||
@@ -12,6 +14,7 @@ import org.koitharu.kotatsu.tracker.work.TrackingItem
|
|||||||
class Tracker(
|
class Tracker(
|
||||||
private val settings: AppSettings,
|
private val settings: AppSettings,
|
||||||
private val repository: TrackingRepository,
|
private val repository: TrackingRepository,
|
||||||
|
private val historyRepository: HistoryRepository,
|
||||||
private val channels: TrackerNotificationChannels,
|
private val channels: TrackerNotificationChannels,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@@ -68,7 +71,7 @@ class Tracker(
|
|||||||
|
|
||||||
suspend fun fetchUpdates(track: MangaTracking, commit: Boolean): MangaUpdates {
|
suspend fun fetchUpdates(track: MangaTracking, commit: Boolean): MangaUpdates {
|
||||||
val manga = MangaRepository(track.manga.source).getDetails(track.manga)
|
val manga = MangaRepository(track.manga.source).getDetails(track.manga)
|
||||||
val updates = compare(track, manga)
|
val updates = compare(track, manga, getBranch(manga))
|
||||||
if (commit) {
|
if (commit) {
|
||||||
repository.saveUpdates(updates)
|
repository.saveUpdates(updates)
|
||||||
}
|
}
|
||||||
@@ -78,7 +81,7 @@ class Tracker(
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
suspend fun checkUpdates(manga: Manga, commit: Boolean): MangaUpdates {
|
suspend fun checkUpdates(manga: Manga, commit: Boolean): MangaUpdates {
|
||||||
val track = repository.getTrack(manga)
|
val track = repository.getTrack(manga)
|
||||||
val updates = compare(track, manga)
|
val updates = compare(track, manga, getBranch(manga))
|
||||||
if (commit) {
|
if (commit) {
|
||||||
repository.saveUpdates(updates)
|
repository.saveUpdates(updates)
|
||||||
}
|
}
|
||||||
@@ -90,25 +93,30 @@ class Tracker(
|
|||||||
repository.deleteTrack(mangaId)
|
repository.deleteTrack(mangaId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun getBranch(manga: Manga): String? {
|
||||||
|
val history = historyRepository.getOne(manga)
|
||||||
|
return manga.getPreferredBranch(history)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The main functionality of tracker: check new chapters in [manga] comparing to the [track]
|
* The main functionality of tracker: check new chapters in [manga] comparing to the [track]
|
||||||
*/
|
*/
|
||||||
private fun compare(track: MangaTracking, manga: Manga): MangaUpdates {
|
private fun compare(track: MangaTracking, manga: Manga, branch: String?): MangaUpdates {
|
||||||
if (track.isEmpty()) {
|
if (track.isEmpty()) {
|
||||||
// first check or manga was empty on last check
|
// first check or manga was empty on last check
|
||||||
return MangaUpdates(manga, emptyList(), isValid = false)
|
return MangaUpdates(manga, emptyList(), isValid = false)
|
||||||
}
|
}
|
||||||
val chapters = requireNotNull(manga.chapters)
|
val chapters = requireNotNull(manga.getChapters(branch))
|
||||||
val newChapters = chapters.takeLastWhile { x -> x.id != track.lastChapterId }
|
val newChapters = chapters.takeLastWhile { x -> x.id != track.lastChapterId }
|
||||||
return when {
|
return when {
|
||||||
newChapters.isEmpty() -> {
|
newChapters.isEmpty() -> {
|
||||||
return MangaUpdates(manga, emptyList(), isValid = chapters.lastOrNull()?.id == track.lastChapterId)
|
MangaUpdates(manga, emptyList(), isValid = chapters.lastOrNull()?.id == track.lastChapterId)
|
||||||
}
|
}
|
||||||
newChapters.size == chapters.size -> {
|
newChapters.size == chapters.size -> {
|
||||||
return MangaUpdates(manga, emptyList(), isValid = false)
|
MangaUpdates(manga, emptyList(), isValid = false)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
return MangaUpdates(manga, newChapters, isValid = true)
|
MangaUpdates(manga, newChapters, isValid = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import org.koitharu.kotatsu.details.ui.DetailsActivity
|
|||||||
import org.koitharu.kotatsu.list.ui.adapter.MangaListListener
|
import org.koitharu.kotatsu.list.ui.adapter.MangaListListener
|
||||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||||
import org.koitharu.kotatsu.main.ui.AppBarOwner
|
import org.koitharu.kotatsu.main.ui.AppBarOwner
|
||||||
|
import org.koitharu.kotatsu.main.ui.MainActivity
|
||||||
import org.koitharu.kotatsu.parsers.model.Manga
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||||
import org.koitharu.kotatsu.tracker.ui.adapter.FeedAdapter
|
import org.koitharu.kotatsu.tracker.ui.adapter.FeedAdapter
|
||||||
@@ -25,6 +26,7 @@ import org.koitharu.kotatsu.tracker.work.TrackWorker
|
|||||||
import org.koitharu.kotatsu.utils.ext.addMenuProvider
|
import org.koitharu.kotatsu.utils.ext.addMenuProvider
|
||||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||||
import org.koitharu.kotatsu.utils.ext.measureHeight
|
import org.koitharu.kotatsu.utils.ext.measureHeight
|
||||||
|
import org.koitharu.kotatsu.utils.ext.resolveDp
|
||||||
|
|
||||||
class FeedFragment :
|
class FeedFragment :
|
||||||
BaseFragment<FragmentFeedBinding>(),
|
BaseFragment<FragmentFeedBinding>(),
|
||||||
@@ -39,7 +41,7 @@ class FeedFragment :
|
|||||||
|
|
||||||
override fun onInflateView(
|
override fun onInflateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?
|
container: ViewGroup?,
|
||||||
) = FragmentFeedBinding.inflate(inflater, container, false)
|
) = FragmentFeedBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
@@ -54,7 +56,7 @@ class FeedFragment :
|
|||||||
paddingVertical = resources.getDimensionPixelOffset(R.dimen.grid_spacing_outer)
|
paddingVertical = resources.getDimensionPixelOffset(R.dimen.grid_spacing_outer)
|
||||||
val decoration = TypedSpacingItemDecoration(
|
val decoration = TypedSpacingItemDecoration(
|
||||||
FeedAdapter.ITEM_TYPE_FEED to 0,
|
FeedAdapter.ITEM_TYPE_FEED to 0,
|
||||||
fallbackSpacing = spacing
|
fallbackSpacing = spacing,
|
||||||
)
|
)
|
||||||
addItemDecoration(decoration)
|
addItemDecoration(decoration)
|
||||||
}
|
}
|
||||||
@@ -77,12 +79,25 @@ class FeedFragment :
|
|||||||
|
|
||||||
override fun onWindowInsetsChanged(insets: Insets) {
|
override fun onWindowInsetsChanged(insets: Insets) {
|
||||||
val headerHeight = (activity as? AppBarOwner)?.appBar?.measureHeight() ?: insets.top
|
val headerHeight = (activity as? AppBarOwner)?.appBar?.measureHeight() ?: insets.top
|
||||||
binding.recyclerView.updatePadding(
|
binding.root.updatePadding(
|
||||||
top = headerHeight + paddingVertical,
|
left = insets.left,
|
||||||
left = insets.left + paddingHorizontal,
|
right = insets.right,
|
||||||
right = insets.right + paddingHorizontal,
|
|
||||||
bottom = insets.bottom + paddingVertical,
|
|
||||||
)
|
)
|
||||||
|
if (activity is MainActivity) {
|
||||||
|
binding.recyclerView.updatePadding(
|
||||||
|
top = headerHeight,
|
||||||
|
bottom = insets.bottom,
|
||||||
|
)
|
||||||
|
binding.swipeRefreshLayout.setProgressViewOffset(
|
||||||
|
true,
|
||||||
|
headerHeight + resources.resolveDp(-72),
|
||||||
|
headerHeight + resources.resolveDp(10),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
binding.recyclerView.updatePadding(
|
||||||
|
bottom = insets.bottom,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRetryClick(error: Throwable) = Unit
|
override fun onRetryClick(error: Throwable) = Unit
|
||||||
@@ -101,7 +116,7 @@ class FeedFragment :
|
|||||||
Snackbar.make(
|
Snackbar.make(
|
||||||
binding.recyclerView,
|
binding.recyclerView,
|
||||||
R.string.updates_feed_cleared,
|
R.string.updates_feed_cleared,
|
||||||
Snackbar.LENGTH_LONG
|
Snackbar.LENGTH_LONG,
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +124,7 @@ class FeedFragment :
|
|||||||
Snackbar.make(
|
Snackbar.make(
|
||||||
binding.recyclerView,
|
binding.recyclerView,
|
||||||
e.getDisplayMessage(resources),
|
e.getDisplayMessage(resources),
|
||||||
Snackbar.LENGTH_SHORT
|
Snackbar.LENGTH_SHORT,
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,12 +16,13 @@ import org.koitharu.kotatsu.list.ui.model.*
|
|||||||
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
|
import org.koitharu.kotatsu.tracker.domain.TrackingRepository
|
||||||
import org.koitharu.kotatsu.tracker.domain.model.TrackingLogItem
|
import org.koitharu.kotatsu.tracker.domain.model.TrackingLogItem
|
||||||
import org.koitharu.kotatsu.tracker.ui.model.toFeedItem
|
import org.koitharu.kotatsu.tracker.ui.model.toFeedItem
|
||||||
|
import org.koitharu.kotatsu.tracker.work.TrackWorker
|
||||||
import org.koitharu.kotatsu.utils.SingleLiveEvent
|
import org.koitharu.kotatsu.utils.SingleLiveEvent
|
||||||
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
import org.koitharu.kotatsu.utils.ext.asLiveDataDistinct
|
||||||
import org.koitharu.kotatsu.utils.ext.daysDiff
|
import org.koitharu.kotatsu.utils.ext.daysDiff
|
||||||
|
|
||||||
class FeedViewModel(
|
class FeedViewModel(
|
||||||
private val repository: TrackingRepository
|
private val repository: TrackingRepository,
|
||||||
) : BaseViewModel() {
|
) : BaseViewModel() {
|
||||||
|
|
||||||
private val logList = MutableStateFlow<List<TrackingLogItem>?>(null)
|
private val logList = MutableStateFlow<List<TrackingLogItem>?>(null)
|
||||||
@@ -32,7 +33,7 @@ class FeedViewModel(
|
|||||||
val onFeedCleared = SingleLiveEvent<Unit>()
|
val onFeedCleared = SingleLiveEvent<Unit>()
|
||||||
val content = combine(
|
val content = combine(
|
||||||
logList.filterNotNull(),
|
logList.filterNotNull(),
|
||||||
hasNextPage
|
hasNextPage,
|
||||||
) { list, isHasNextPage ->
|
) { list, isHasNextPage ->
|
||||||
buildList(list.size + 2) {
|
buildList(list.size + 2) {
|
||||||
if (list.isEmpty()) {
|
if (list.isEmpty()) {
|
||||||
@@ -43,7 +44,7 @@ class FeedViewModel(
|
|||||||
textPrimary = R.string.text_empty_holder_primary,
|
textPrimary = R.string.text_empty_holder_primary,
|
||||||
textSecondary = R.string.text_feed_holder,
|
textSecondary = R.string.text_feed_holder,
|
||||||
actionStringRes = 0,
|
actionStringRes = 0,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
list.mapListTo(this)
|
list.mapListTo(this)
|
||||||
@@ -54,7 +55,7 @@ class FeedViewModel(
|
|||||||
}
|
}
|
||||||
}.asLiveDataDistinct(
|
}.asLiveDataDistinct(
|
||||||
viewModelScope.coroutineContext + Dispatchers.Default,
|
viewModelScope.coroutineContext + Dispatchers.Default,
|
||||||
listOf(header, LoadingState)
|
listOf(header, LoadingState),
|
||||||
)
|
)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|||||||
@@ -29,6 +29,9 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
android:background="@null"
|
android:background="@null"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:paddingHorizontal="@dimen/margin_normal"
|
||||||
app:tabGravity="center"
|
app:tabGravity="center"
|
||||||
app:tabMode="scrollable" />
|
app:tabMode="scrollable" />
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user