Resolve conflicts

This commit is contained in:
Zakhar Timoshenko
2022-08-07 03:04:00 +03:00
12 changed files with 124 additions and 85 deletions

View File

@@ -84,19 +84,19 @@ afterEvaluate {
} }
} }
dependencies { dependencies {
implementation('com.github.KotatsuApp:kotatsu-parsers:85bfe42ddf') { implementation('com.github.KotatsuApp:kotatsu-parsers:e2308214a7') {
exclude group: 'org.json', module: 'json' exclude group: 'org.json', module: 'json'
} }
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
implementation 'androidx.core:core-ktx:1.8.0' implementation 'androidx.core:core-ktx:1.8.0'
implementation 'androidx.activity:activity-ktx:1.5.0' implementation 'androidx.activity:activity-ktx:1.5.1'
implementation 'androidx.fragment:fragment-ktx:1.5.0' implementation 'androidx.fragment:fragment-ktx:1.5.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.0' implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1'
implementation 'androidx.lifecycle:lifecycle-service:2.5.0' implementation 'androidx.lifecycle:lifecycle-service:2.5.1'
implementation 'androidx.lifecycle:lifecycle-process:2.5.0' implementation 'androidx.lifecycle:lifecycle-process:2.5.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1' implementation 'androidx.recyclerview:recyclerview:1.2.1'
@@ -106,11 +106,11 @@ dependencies {
implementation 'androidx.biometric:biometric-ktx:1.2.0-alpha04' implementation 'androidx.biometric:biometric-ktx:1.2.0-alpha04'
implementation 'com.google.android.material:material:1.7.0-alpha03' implementation 'com.google.android.material:material:1.7.0-alpha03'
//noinspection LifecycleAnnotationProcessorWithJava8 //noinspection LifecycleAnnotationProcessorWithJava8
kapt 'androidx.lifecycle:lifecycle-compiler:2.5.0' kapt 'androidx.lifecycle:lifecycle-compiler:2.5.1'
implementation 'androidx.room:room-runtime:2.4.2' implementation 'androidx.room:room-runtime:2.4.3'
implementation 'androidx.room:room-ktx:2.4.2' implementation 'androidx.room:room-ktx:2.4.3'
kapt 'androidx.room:room-compiler:2.4.2' kapt 'androidx.room:room-compiler:2.4.3'
implementation 'com.squareup.okhttp3:okhttp:4.10.0' implementation 'com.squareup.okhttp3:okhttp:4.10.0'
implementation 'com.squareup.okhttp3:okhttp-dnsoverhttps:4.9.3' implementation 'com.squareup.okhttp3:okhttp-dnsoverhttps:4.9.3'
@@ -145,7 +145,7 @@ dependencies {
androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4' androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4'
androidTestImplementation 'androidx.room:room-testing:2.4.2' androidTestImplementation 'androidx.room:room-testing:2.4.3'
androidTestImplementation 'com.squareup.moshi:moshi-kotlin:1.13.0' androidTestImplementation 'com.squareup.moshi:moshi-kotlin:1.13.0'
androidTestImplementation 'com.google.dagger:hilt-android-testing:2.42' androidTestImplementation 'com.google.dagger:hilt-android-testing:2.42'

View File

@@ -10,6 +10,7 @@ import android.widget.Checkable
import androidx.annotation.AttrRes import androidx.annotation.AttrRes
import androidx.appcompat.widget.AppCompatImageView import androidx.appcompat.widget.AppCompatImageView
import androidx.core.os.ParcelCompat import androidx.core.os.ParcelCompat
import androidx.customview.view.AbsSavedState
class CheckableImageView @JvmOverloads constructor( class CheckableImageView @JvmOverloads constructor(
context: Context, context: Context,
@@ -73,7 +74,7 @@ class CheckableImageView @JvmOverloads constructor(
fun onCheckedChanged(view: CheckableImageView, isChecked: Boolean) fun onCheckedChanged(view: CheckableImageView, isChecked: Boolean)
} }
private class SavedState : BaseSavedState { private class SavedState : AbsSavedState {
val isChecked: Boolean val isChecked: Boolean
@@ -81,7 +82,7 @@ class CheckableImageView @JvmOverloads constructor(
isChecked = checked isChecked = checked
} }
constructor(source: Parcel) : super(source) { constructor(source: Parcel, classLoader: ClassLoader?) : super(source, classLoader) {
isChecked = ParcelCompat.readBoolean(source) isChecked = ParcelCompat.readBoolean(source)
} }
@@ -91,9 +92,10 @@ class CheckableImageView @JvmOverloads constructor(
} }
companion object { companion object {
@Suppress("unused")
@JvmField @JvmField
val CREATOR: Creator<SavedState> = object : Creator<SavedState> { val CREATOR: Creator<SavedState> = object : Creator<SavedState> {
override fun createFromParcel(`in`: Parcel) = SavedState(`in`) override fun createFromParcel(`in`: Parcel) = SavedState(`in`, SavedState::class.java.classLoader)
override fun newArray(size: Int): Array<SavedState?> = arrayOfNulls(size) override fun newArray(size: Int): Array<SavedState?> = arrayOfNulls(size)
} }

View File

@@ -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
}

View File

@@ -29,6 +29,7 @@ import org.koitharu.kotatsu.bookmarks.domain.Bookmark
import org.koitharu.kotatsu.bookmarks.ui.adapter.BookmarksAdapter import org.koitharu.kotatsu.bookmarks.ui.adapter.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.history.domain.PROGRESS_NONE import org.koitharu.kotatsu.history.domain.PROGRESS_NONE
import org.koitharu.kotatsu.image.ui.ImageActivity import org.koitharu.kotatsu.image.ui.ImageActivity
@@ -75,6 +76,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)
} }
override fun onItemClick(item: Bookmark, view: View) { override fun onItemClick(item: Bookmark, view: View) {
@@ -111,18 +113,6 @@ class DetailsFragment :
ratingBar.isVisible = false ratingBar.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,
)
}
when (manga.state) { when (manga.state) {
MangaState.FINISHED -> { MangaState.FINISHED -> {
infoLayout.textViewState.apply { infoLayout.textViewState.apply {
@@ -163,6 +153,20 @@ class DetailsFragment :
} }
} }
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,
)
}
}
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)

View File

@@ -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
@@ -16,9 +16,6 @@ import org.koitharu.kotatsu.parsers.exception.NotFoundException
import org.koitharu.kotatsu.parsers.model.Manga 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.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(
@@ -46,12 +43,7 @@ class MangaDetailsDelegate(
manga = mangaRepositoryFactory.create(manga.source).getDetails(manga) manga = mangaRepositoryFactory.create(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) {
@@ -92,7 +84,7 @@ class MangaDetailsDelegate(
val dateFormat = settings.getDateFormat() val dateFormat = settings.getDateFormat()
val currentIndex = chapters.indexOfFirst { it.id == currentId } val currentIndex = chapters.indexOfFirst { it.id == currentId }
val firstNewIndex = chapters.size - newCount val firstNewIndex = chapters.size - newCount
val downloadedIds = downloadedChapters?.mapToSet { it.id } val downloadedIds = downloadedChapters?.mapTo(HashSet(downloadedChapters.size)) { it.id }
for (i in chapters.indices) { for (i in chapters.indices) {
val chapter = chapters[i] val chapter = chapters[i]
if (chapter.branch != branch) { if (chapter.branch != branch) {
@@ -107,6 +99,9 @@ class MangaDetailsDelegate(
dateFormat = dateFormat, dateFormat = dateFormat,
) )
} }
if (result.size < chapters.size / 2) {
result.trimToSize()
}
return result return result
} }
@@ -162,24 +157,9 @@ class MangaDetailsDelegate(
} }
result.sortBy { it.chapter.number } result.sortBy { it.chapter.number }
} }
if (result.size < sourceChapters.size / 2) {
result.trimToSize()
}
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
}
} }

View File

@@ -1,13 +1,24 @@
package org.koitharu.kotatsu.details.ui.model package org.koitharu.kotatsu.details.ui.model
import java.text.DateFormat
import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaChapter
class ChapterListItem( class ChapterListItem(
val chapter: MangaChapter, val chapter: MangaChapter,
val flags: Int, val flags: Int,
val uploadDate: String?, private val uploadDateMs: Long,
private val dateFormat: DateFormat,
) { ) {
var uploadDate: String? = null
private set
get() {
if (field != null) return field
if (uploadDateMs == 0L) return null
field = dateFormat.format(uploadDateMs)
return field
}
val status: Int val status: Int
get() = flags and MASK_STATUS get() = flags and MASK_STATUS
@@ -32,7 +43,8 @@ class ChapterListItem(
if (chapter != other.chapter) return false if (chapter != other.chapter) return false
if (flags != other.flags) return false if (flags != other.flags) return false
if (uploadDate != other.uploadDate) return false if (uploadDateMs != other.uploadDateMs) return false
if (dateFormat != other.dateFormat) return false
return true return true
} }
@@ -40,7 +52,8 @@ class ChapterListItem(
override fun hashCode(): Int { override fun hashCode(): Int {
var result = chapter.hashCode() var result = chapter.hashCode()
result = 31 * result + flags result = 31 * result + flags
result = 31 * result + (uploadDate?.hashCode() ?: 0) result = 31 * result + uploadDateMs.hashCode()
result = 31 * result + dateFormat.hashCode()
return result return result
} }

View File

@@ -1,12 +1,12 @@
package org.koitharu.kotatsu.details.ui.model package org.koitharu.kotatsu.details.ui.model
import java.text.DateFormat
import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_CURRENT import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_CURRENT
import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_DOWNLOADED import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_DOWNLOADED
import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_MISSING import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_MISSING
import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_NEW import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_NEW
import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_UNREAD import org.koitharu.kotatsu.details.ui.model.ChapterListItem.Companion.FLAG_UNREAD
import org.koitharu.kotatsu.parsers.model.MangaChapter import org.koitharu.kotatsu.parsers.model.MangaChapter
import java.text.DateFormat
fun MangaChapter.toListItem( fun MangaChapter.toListItem(
isCurrent: Boolean, isCurrent: Boolean,
@@ -25,6 +25,7 @@ fun MangaChapter.toListItem(
return ChapterListItem( return ChapterListItem(
chapter = this, chapter = this,
flags = flags, flags = flags,
uploadDate = if (uploadDate != 0L) dateFormat.format(uploadDate) else null uploadDateMs = uploadDate,
dateFormat = dateFormat,
) )
} }

View File

@@ -5,8 +5,8 @@ import android.content.res.TypedArray
import android.os.Parcel import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View
import androidx.core.content.withStyledAttributes import androidx.core.content.withStyledAttributes
import androidx.customview.view.AbsSavedState
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceViewHolder import androidx.preference.PreferenceViewHolder
import com.google.android.material.slider.Slider import com.google.android.material.slider.Slider
@@ -40,11 +40,11 @@ class SliderPreference @JvmOverloads constructor(
attrs, attrs,
R.styleable.SliderPreference, R.styleable.SliderPreference,
defStyleAttr, defStyleAttr,
defStyleRes defStyleRes,
) { ) {
valueFrom = getFloat( valueFrom = getFloat(
R.styleable.SliderPreference_android_valueFrom, R.styleable.SliderPreference_android_valueFrom,
valueFrom.toFloat() valueFrom.toFloat(),
).toInt() ).toInt()
valueTo = valueTo =
getFloat(R.styleable.SliderPreference_android_valueTo, valueTo.toFloat()).toInt() getFloat(R.styleable.SliderPreference_android_valueTo, valueTo.toFloat()).toInt()
@@ -117,7 +117,7 @@ class SliderPreference @JvmOverloads constructor(
} }
} }
private class SavedState : View.BaseSavedState { private class SavedState : AbsSavedState {
val valueFrom: Int val valueFrom: Int
val valueTo: Int val valueTo: Int
@@ -134,7 +134,7 @@ class SliderPreference @JvmOverloads constructor(
this.currentValue = currentValue this.currentValue = currentValue
} }
constructor(source: Parcel) : super(source) { constructor(source: Parcel, classLoader: ClassLoader?) : super(source, classLoader) {
valueFrom = source.readInt() valueFrom = source.readInt()
valueTo = source.readInt() valueTo = source.readInt()
currentValue = source.readInt() currentValue = source.readInt()
@@ -148,12 +148,13 @@ class SliderPreference @JvmOverloads constructor(
} }
companion object { companion object {
@Suppress("unused")
@JvmField @JvmField
val CREATOR: Parcelable.Creator<SavedState> = object : Parcelable.Creator<SavedState> { val CREATOR: Parcelable.Creator<SavedState> = object : Parcelable.Creator<SavedState> {
override fun createFromParcel(`in`: Parcel) = SavedState(`in`) override fun createFromParcel(`in`: Parcel) = SavedState(`in`, SavedState::class.java.classLoader)
override fun newArray(size: Int): Array<SavedState?> = arrayOfNulls(size) override fun newArray(size: Int): Array<SavedState?> = arrayOfNulls(size)
} }
} }
} }
} }

View File

@@ -2,8 +2,10 @@ package org.koitharu.kotatsu.tracker.domain
import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import javax.inject.Inject import javax.inject.Inject
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
@@ -13,6 +15,7 @@ import org.koitharu.kotatsu.tracker.work.TrackingItem
class Tracker @Inject constructor( class Tracker @Inject constructor(
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,
private val mangaRepositoryFactory: MangaRepository.Factory, private val mangaRepositoryFactory: MangaRepository.Factory,
) { ) {
@@ -70,7 +73,7 @@ class Tracker @Inject constructor(
suspend fun fetchUpdates(track: MangaTracking, commit: Boolean): MangaUpdates { suspend fun fetchUpdates(track: MangaTracking, commit: Boolean): MangaUpdates {
val manga = mangaRepositoryFactory.create(track.manga.source).getDetails(track.manga) val manga = mangaRepositoryFactory.create(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)
} }
@@ -80,7 +83,7 @@ class Tracker @Inject constructor(
@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)
} }
@@ -92,15 +95,20 @@ class Tracker @Inject constructor(
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() -> {

View File

@@ -17,7 +17,8 @@ fun Throwable.getDisplayMessage(resources: Resources): String = when (this) {
is AuthRequiredException -> resources.getString(R.string.auth_required) is AuthRequiredException -> resources.getString(R.string.auth_required)
is CloudFlareProtectedException -> resources.getString(R.string.captcha_required) is CloudFlareProtectedException -> resources.getString(R.string.captcha_required)
is ActivityNotFoundException, is ActivityNotFoundException,
is UnsupportedOperationException, -> resources.getString(R.string.operation_not_supported) is UnsupportedOperationException,
-> resources.getString(R.string.operation_not_supported)
is UnsupportedFileException -> resources.getString(R.string.text_file_not_supported) is UnsupportedFileException -> resources.getString(R.string.text_file_not_supported)
is FileNotFoundException -> resources.getString(R.string.file_not_found) is FileNotFoundException -> resources.getString(R.string.file_not_found)
is EmptyHistoryException -> resources.getString(R.string.history_is_empty) is EmptyHistoryException -> resources.getString(R.string.history_is_empty)
@@ -40,5 +41,6 @@ fun Throwable.isReportable(): Boolean {
} }
fun Throwable.report(message: String?) { fun Throwable.report(message: String?) {
CaughtException(this, message).sendWithAcra() val exception = CaughtException(this, message)
exception.sendWithAcra()
} }

View File

@@ -14,17 +14,18 @@ import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.domain.MangaIntent import org.koitharu.kotatsu.base.domain.MangaIntent
import org.koitharu.kotatsu.history.domain.HistoryRepository 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.parsers.util.replaceWith
import org.koitharu.kotatsu.utils.ext.requireBitmap import org.koitharu.kotatsu.utils.ext.requireBitmap
class RecentListFactory( class RecentListFactory(
private val context: Context, private val context: Context,
private val historyRepository: HistoryRepository, private val historyRepository: HistoryRepository,
private val coil: ImageLoader private val coil: ImageLoader,
) : RemoteViewsService.RemoteViewsFactory { ) : RemoteViewsService.RemoteViewsFactory {
private val dataSet = ArrayList<Manga>() private val dataSet = ArrayList<Manga>()
private val transformation = RoundedCornersTransformation( private val transformation = RoundedCornersTransformation(
context.resources.getDimension(R.dimen.appwidget_corner_radius_inner) context.resources.getDimension(R.dimen.appwidget_corner_radius_inner),
) )
private val coverSize = Size( private val coverSize = Size(
context.resources.getDimensionPixelSize(R.dimen.widget_cover_width), context.resources.getDimensionPixelSize(R.dimen.widget_cover_width),
@@ -38,9 +39,8 @@ class RecentListFactory(
override fun getItemId(position: Int) = dataSet[position].id override fun getItemId(position: Int) = dataSet[position].id
override fun onDataSetChanged() { override fun onDataSetChanged() {
dataSet.clear()
val data = runBlocking { historyRepository.getList(0, 10) } val data = runBlocking { historyRepository.getList(0, 10) }
dataSet.addAll(data) dataSet.replaceWith(data)
} }
override fun hasStableIds() = true override fun hasStableIds() = true
@@ -54,7 +54,7 @@ class RecentListFactory(
.data(item.coverUrl) .data(item.coverUrl)
.size(coverSize) .size(coverSize)
.transformations(transformation) .transformations(transformation)
.build() .build(),
).requireBitmap() ).requireBitmap()
}.onSuccess { cover -> }.onSuccess { cover ->
views.setImageViewBitmap(R.id.imageView_cover, cover) views.setImageViewBitmap(R.id.imageView_cover, cover)
@@ -72,4 +72,4 @@ class RecentListFactory(
override fun getViewTypeCount() = 1 override fun getViewTypeCount() = 1
override fun onDestroy() = Unit override fun onDestroy() = Unit
} }

View File

@@ -15,6 +15,7 @@ import org.koitharu.kotatsu.base.domain.MangaIntent
import org.koitharu.kotatsu.core.prefs.AppWidgetConfig import org.koitharu.kotatsu.core.prefs.AppWidgetConfig
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.util.replaceWith
import org.koitharu.kotatsu.utils.ext.requireBitmap import org.koitharu.kotatsu.utils.ext.requireBitmap
class ShelfListFactory( class ShelfListFactory(
@@ -27,7 +28,7 @@ class ShelfListFactory(
private val dataSet = ArrayList<Manga>() private val dataSet = ArrayList<Manga>()
private val config = AppWidgetConfig(context, widgetId) private val config = AppWidgetConfig(context, widgetId)
private val transformation = RoundedCornersTransformation( private val transformation = RoundedCornersTransformation(
context.resources.getDimension(R.dimen.appwidget_corner_radius_inner) context.resources.getDimension(R.dimen.appwidget_corner_radius_inner),
) )
private val coverSize = Size( private val coverSize = Size(
context.resources.getDimensionPixelSize(R.dimen.widget_cover_width), context.resources.getDimensionPixelSize(R.dimen.widget_cover_width),
@@ -41,7 +42,6 @@ class ShelfListFactory(
override fun getItemId(position: Int) = dataSet[position].id override fun getItemId(position: Int) = dataSet[position].id
override fun onDataSetChanged() { override fun onDataSetChanged() {
dataSet.clear()
val data = runBlocking { val data = runBlocking {
val category = config.categoryId val category = config.categoryId
if (category == 0L) { if (category == 0L) {
@@ -50,7 +50,7 @@ class ShelfListFactory(
favouritesRepository.getManga(category) favouritesRepository.getManga(category)
} }
} }
dataSet.addAll(data) dataSet.replaceWith(data)
} }
override fun hasStableIds() = true override fun hasStableIds() = true
@@ -65,7 +65,7 @@ class ShelfListFactory(
.data(item.coverUrl) .data(item.coverUrl)
.size(coverSize) .size(coverSize)
.transformations(transformation) .transformations(transformation)
.build() .build(),
).requireBitmap() ).requireBitmap()
}.onSuccess { cover -> }.onSuccess { cover ->
views.setImageViewBitmap(R.id.imageView_cover, cover) views.setImageViewBitmap(R.id.imageView_cover, cover)