Add unread field to feed items

This commit is contained in:
Koitharu
2024-04-16 10:03:01 +03:00
parent f685ed6932
commit 846c346a86
20 changed files with 85 additions and 41 deletions

View File

@@ -16,9 +16,15 @@ interface TrackLogsDao {
@Query("SELECT * FROM track_logs ORDER BY created_at DESC LIMIT :limit OFFSET 0") @Query("SELECT * FROM track_logs ORDER BY created_at DESC LIMIT :limit OFFSET 0")
fun observeAll(limit: Int): Flow<List<TrackLogWithManga>> fun observeAll(limit: Int): Flow<List<TrackLogWithManga>>
@Query("SELECT COUNT(*) FROM track_logs WHERE unread = 1")
fun observeUnreadCount(): Flow<Int>
@Query("DELETE FROM track_logs") @Query("DELETE FROM track_logs")
suspend fun clear() suspend fun clear()
@Query("UPDATE track_logs SET unread = 0 WHERE id = :id")
suspend fun markAsRead(id: Long)
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(entity: TrackLogEntity): Long suspend fun insert(entity: TrackLogEntity): Long

View File

@@ -12,5 +12,7 @@ class Migration19To20 : Migration(19, 20) {
db.execSQL("CREATE TABLE tracks (`manga_id` INTEGER NOT NULL, `last_chapter_id` INTEGER NOT NULL, `chapters_new` INTEGER NOT NULL, `last_check_time` INTEGER NOT NULL, `last_chapter_date` INTEGER NOT NULL, `last_result` INTEGER NOT NULL, PRIMARY KEY(`manga_id`), FOREIGN KEY(`manga_id`) REFERENCES `manga`(`manga_id`) ON UPDATE NO ACTION ON DELETE CASCADE )") db.execSQL("CREATE TABLE tracks (`manga_id` INTEGER NOT NULL, `last_chapter_id` INTEGER NOT NULL, `chapters_new` INTEGER NOT NULL, `last_check_time` INTEGER NOT NULL, `last_chapter_date` INTEGER NOT NULL, `last_result` INTEGER NOT NULL, PRIMARY KEY(`manga_id`), FOREIGN KEY(`manga_id`) REFERENCES `manga`(`manga_id`) ON UPDATE NO ACTION ON DELETE CASCADE )")
db.execSQL("INSERT INTO tracks SELECT manga_id, last_chapter_id, chapters_new, last_check AS last_check_time, 0 AS last_chapter_date, 0 AS last_result FROM tracks_bk") db.execSQL("INSERT INTO tracks SELECT manga_id, last_chapter_id, chapters_new, last_check AS last_check_time, 0 AS last_chapter_date, 0 AS last_result FROM tracks_bk")
db.execSQL("DROP TABLE tracks_bk") db.execSQL("DROP TABLE tracks_bk")
db.execSQL("ALTER TABLE track_logs ADD COLUMN `unread` INTEGER NOT NULL DEFAULT 0")
} }
} }

View File

@@ -0,0 +1,16 @@
package org.koitharu.kotatsu.core.util
import kotlinx.coroutines.CoroutineExceptionHandler
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.core.util.ext.report
import kotlin.coroutines.AbstractCoroutineContextElement
import kotlin.coroutines.CoroutineContext
class AcraCoroutineErrorHandler : AbstractCoroutineContextElement(CoroutineExceptionHandler),
CoroutineExceptionHandler {
override fun handleException(context: CoroutineContext, exception: Throwable) {
exception.printStackTraceDebug()
exception.report()
}
}

View File

@@ -1,7 +1,6 @@
package org.koitharu.kotatsu.core.util.ext package org.koitharu.kotatsu.core.util.ext
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.LifecycleDestroyedException import androidx.lifecycle.LifecycleDestroyedException
import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.LifecycleObserver
@@ -10,17 +9,20 @@ import androidx.lifecycle.ProcessLifecycleOwner
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.lifecycle.RetainedLifecycle import dagger.hilt.android.lifecycle.RetainedLifecycle
import kotlinx.coroutines.CancellableContinuation import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.plus
import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.suspendCancellableCoroutine
import org.koitharu.kotatsu.core.util.AcraCoroutineErrorHandler
import org.koitharu.kotatsu.core.util.RetainedLifecycleCoroutineScope import org.koitharu.kotatsu.core.util.RetainedLifecycleCoroutineScope
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import kotlin.coroutines.EmptyCoroutineContext import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.resume import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException import kotlin.coroutines.resumeWithException
val processLifecycleScope: LifecycleCoroutineScope val processLifecycleScope: CoroutineScope
inline get() = ProcessLifecycleOwner.get().lifecycleScope get() = ProcessLifecycleOwner.get().lifecycleScope + AcraCoroutineErrorHandler()
val RetainedLifecycle.lifecycleScope: RetainedLifecycleCoroutineScope val RetainedLifecycle.lifecycleScope: RetainedLifecycleCoroutineScope
inline get() = RetainedLifecycleCoroutineScope(this) inline get() = RetainedLifecycleCoroutineScope(this)

View File

@@ -118,7 +118,7 @@ class ExploreViewModel @Inject constructor(
sourcesRepository.observeNewSources(), sourcesRepository.observeNewSources(),
) { content, suggestions, grid, randomLoading, newSources -> ) { content, suggestions, grid, randomLoading, newSources ->
buildList(content, suggestions, grid, randomLoading, newSources) buildList(content, suggestions, grid, randomLoading, newSources)
} }.withErrorHandling()
private fun buildList( private fun buildList(
sources: List<MangaSource>, sources: List<MangaSource>,

View File

@@ -40,7 +40,8 @@ class FavouritesCategoriesViewModel @Inject constructor(
settings.observeAsFlow(AppSettings.KEY_ALL_FAVOURITES_VISIBLE) { isAllFavouritesVisible }, settings.observeAsFlow(AppSettings.KEY_ALL_FAVOURITES_VISIBLE) { isAllFavouritesVisible },
) { cats, all, showAll -> ) { cats, all, showAll ->
cats.toUiList(all, showAll) cats.toUiList(all, showAll)
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState)) }.withErrorHandling()
.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState))
fun deleteCategories(ids: Set<Long>) { fun deleteCategories(ids: Set<Long>) {
launchJob(Dispatchers.Default) { launchJob(Dispatchers.Default) {

View File

@@ -56,6 +56,7 @@ class FavouritesListViewModel @Inject constructor(
} }
} else { } else {
repository.observeCategory(categoryId) repository.observeCategory(categoryId)
.withErrorHandling()
.map { it?.order } .map { it?.order }
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, null) }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, null)

View File

@@ -277,7 +277,6 @@ class MainActivity : BaseActivity<ActivityMainBinding>(), AppBarOwner, BottomNav
private fun onFeedCounterChanged(counter: Int) { private fun onFeedCounterChanged(counter: Int) {
navigationDelegate.setCounter(NavItem.FEED, counter) navigationDelegate.setCounter(NavItem.FEED, counter)
navigationDelegate.setCounter(NavItem.UPDATED, counter)
} }
private fun onIncognitoModeChanged(isIncognito: Boolean) { private fun onIncognitoModeChanged(isIncognito: Boolean) {

View File

@@ -32,15 +32,18 @@ class MainViewModel @Inject constructor(
val onOpenReader = MutableEventFlow<Manga>() val onOpenReader = MutableEventFlow<Manga>()
val onFirstStart = MutableEventFlow<Unit>() val onFirstStart = MutableEventFlow<Unit>()
val isResumeEnabled = readingResumeEnabledUseCase().stateIn( val isResumeEnabled = readingResumeEnabledUseCase()
scope = viewModelScope + Dispatchers.Default, .withErrorHandling()
started = SharingStarted.WhileSubscribed(5000), .stateIn(
initialValue = false, scope = viewModelScope + Dispatchers.Default,
) started = SharingStarted.WhileSubscribed(5000),
initialValue = false,
)
val appUpdate = appUpdateRepository.observeAvailableUpdate() val appUpdate = appUpdateRepository.observeAvailableUpdate()
val feedCounter = trackingRepository.observeUpdatedMangaCount() val feedCounter = trackingRepository.observeUnreadUpdatesCount()
.withErrorHandling()
.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Lazily, 0) .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Lazily, 0)
init { init {

View File

@@ -106,7 +106,7 @@ class SearchSuggestionViewModel @Inject constructor(
}.distinctUntilChanged() }.distinctUntilChanged()
.onEach { .onEach {
suggestion.value = it suggestion.value = it
}.launchIn(viewModelScope + Dispatchers.Default) }.withErrorHandling().launchIn(viewModelScope + Dispatchers.Default)
} }
private suspend fun buildSearchSuggestion( private suspend fun buildSearchSuggestion(

View File

@@ -18,5 +18,6 @@ class RootSettingsViewModel @Inject constructor(
val totalSourcesCount = sourcesRepository.allMangaSources.size val totalSourcesCount = sourcesRepository.allMangaSources.size
val enabledSourcesCount = sourcesRepository.observeEnabledSourcesCount() val enabledSourcesCount = sourcesRepository.observeEnabledSourcesCount()
.withErrorHandling()
.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, -1) .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, -1)
} }

View File

@@ -16,8 +16,10 @@ class SourcesSettingsViewModel @Inject constructor(
) : BaseViewModel() { ) : BaseViewModel() {
val enabledSourcesCount = sourcesRepository.observeEnabledSourcesCount() val enabledSourcesCount = sourcesRepository.observeEnabledSourcesCount()
.withErrorHandling()
.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, -1) .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, -1)
val availableSourcesCount = sourcesRepository.observeAvailableSourcesCount() val availableSourcesCount = sourcesRepository.observeAvailableSourcesCount()
.withErrorHandling()
.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, -1) .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, -1)
} }

View File

@@ -5,26 +5,13 @@ import org.koitharu.kotatsu.core.db.entity.toMangaTags
import org.koitharu.kotatsu.tracker.domain.model.TrackingLogItem import org.koitharu.kotatsu.tracker.domain.model.TrackingLogItem
import java.time.Instant import java.time.Instant
fun TrackLogWithManga.toTrackingLogItem(counters: MutableMap<Long, Int>): TrackingLogItem { fun TrackLogWithManga.toTrackingLogItem(): TrackingLogItem {
val chaptersList = trackLog.chapters.split('\n').filterNot { x -> x.isEmpty() } val chaptersList = trackLog.chapters.split('\n').filterNot { x -> x.isEmpty() }
return TrackingLogItem( return TrackingLogItem(
id = trackLog.id, id = trackLog.id,
chapters = chaptersList, chapters = chaptersList,
manga = manga.toManga(tags.toMangaTags()), manga = manga.toManga(tags.toMangaTags()),
createdAt = Instant.ofEpochMilli(trackLog.createdAt), createdAt = Instant.ofEpochMilli(trackLog.createdAt),
isNew = counters.decrement(trackLog.mangaId, chaptersList.size), isNew = trackLog.isUnread,
) )
} }
private fun MutableMap<Long, Int>.decrement(key: Long, count: Int): Boolean = synchronized(this) {
val counter = get(key)
if (counter == null || counter <= 0) {
return false
}
if (counter < count) {
remove(key)
} else {
put(key, counter - count)
}
return true
}

View File

@@ -23,4 +23,5 @@ class TrackLogEntity(
@ColumnInfo(name = "manga_id", index = true) val mangaId: Long, @ColumnInfo(name = "manga_id", index = true) val mangaId: Long,
@ColumnInfo(name = "chapters") val chapters: String, @ColumnInfo(name = "chapters") val chapters: String,
@ColumnInfo(name = "created_at") val createdAt: Long, @ColumnInfo(name = "created_at") val createdAt: Long,
@ColumnInfo(name = "unread") val isUnread: Boolean,
) )

View File

@@ -4,7 +4,6 @@ import androidx.annotation.VisibleForTesting
import androidx.room.withTransaction import androidx.room.withTransaction
import dagger.Reusable import dagger.Reusable
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
@@ -55,11 +54,16 @@ class TrackingRepository @Inject constructor(
return db.getTracksDao().observeNewChapters(mangaId).map { it ?: 0 } return db.getTracksDao().observeNewChapters(mangaId).map { it ?: 0 }
} }
@Deprecated("")
fun observeUpdatedMangaCount(): Flow<Int> { fun observeUpdatedMangaCount(): Flow<Int> {
return db.getTracksDao().observeNewChapters().map { list -> list.count { it > 0 } } return db.getTracksDao().observeNewChapters().map { list -> list.count { it > 0 } }
.onStart { gcIfNotCalled() } .onStart { gcIfNotCalled() }
} }
fun observeUnreadUpdatesCount(): Flow<Int> {
return db.getTrackLogsDao().observeUnreadCount()
}
fun observeUpdatedManga(limit: Int = 0): Flow<List<MangaTracking>> { fun observeUpdatedManga(limit: Int = 0): Flow<List<MangaTracking>> {
return if (limit == 0) { return if (limit == 0) {
db.getTracksDao().observeUpdatedManga() db.getTracksDao().observeUpdatedManga()
@@ -112,13 +116,8 @@ class TrackingRepository @Inject constructor(
fun observeTrackingLog(limit: Flow<Int>): Flow<List<TrackingLogItem>> { fun observeTrackingLog(limit: Flow<Int>): Flow<List<TrackingLogItem>> {
return limit.flatMapLatest { limitValue -> return limit.flatMapLatest { limitValue ->
combine( db.getTrackLogsDao().observeAll(limitValue)
db.getTracksDao().observeNewChaptersMap(), .mapItems { it.toTrackingLogItem() }
db.getTrackLogsDao().observeAll(limitValue),
) { counters, entities ->
val countersMap = counters.toMutableMap()
entities.map { x -> x.toTrackingLogItem(countersMap) }
}
}.onStart { }.onStart {
gcIfNotCalled() gcIfNotCalled()
} }
@@ -130,6 +129,8 @@ class TrackingRepository @Inject constructor(
suspend fun clearCounters() = db.getTracksDao().clearCounters() suspend fun clearCounters() = db.getTracksDao().clearCounters()
suspend fun markAsRead(trackLogId: Long) = db.getTrackLogsDao().markAsRead(trackLogId)
suspend fun gc() = db.withTransaction { suspend fun gc() = db.withTransaction {
db.getTracksDao().gc() db.getTracksDao().gc()
db.getTrackLogsDao().run { db.getTrackLogsDao().run {
@@ -148,6 +149,7 @@ class TrackingRepository @Inject constructor(
mangaId = updates.manga.id, mangaId = updates.manga.id,
chapters = updates.newChapters.joinToString("\n") { x -> x.name }, chapters = updates.newChapters.joinToString("\n") { x -> x.name },
createdAt = System.currentTimeMillis(), createdAt = System.currentTimeMillis(),
isUnread = true,
) )
db.getTrackLogsDao().insert(logEntity) db.getTrackLogsDao().insert(logEntity)
} }

View File

@@ -57,7 +57,10 @@ class FeedFragment :
override fun onViewBindingCreated(binding: FragmentFeedBinding, savedInstanceState: Bundle?) { override fun onViewBindingCreated(binding: FragmentFeedBinding, savedInstanceState: Bundle?) {
super.onViewBindingCreated(binding, savedInstanceState) super.onViewBindingCreated(binding, savedInstanceState)
val sizeResolver = StaticItemSizeResolver(resources.getDimensionPixelSize(R.dimen.smaller_grid_width)) val sizeResolver = StaticItemSizeResolver(resources.getDimensionPixelSize(R.dimen.smaller_grid_width))
feedAdapter = FeedAdapter(coil, viewLifecycleOwner, this, sizeResolver) feedAdapter = FeedAdapter(coil, viewLifecycleOwner, this, sizeResolver) { item, v ->
viewModel.onItemClick(item)
onItemClick(item.manga, v)
}
with(binding.recyclerView) { with(binding.recyclerView) {
adapter = feedAdapter adapter = feedAdapter
setHasFixedSize(true) setHasFixedSize(true)

View File

@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.tracker.ui.feed
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
@@ -27,6 +28,7 @@ import org.koitharu.kotatsu.list.ui.model.LoadingState
import org.koitharu.kotatsu.list.ui.model.toGridModel import org.koitharu.kotatsu.list.ui.model.toGridModel
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.feed.model.FeedItem
import org.koitharu.kotatsu.tracker.ui.feed.model.UpdatedMangaHeader import org.koitharu.kotatsu.tracker.ui.feed.model.UpdatedMangaHeader
import org.koitharu.kotatsu.tracker.ui.feed.model.toFeedItem import org.koitharu.kotatsu.tracker.ui.feed.model.toFeedItem
import org.koitharu.kotatsu.tracker.work.TrackWorker import org.koitharu.kotatsu.tracker.work.TrackWorker
@@ -108,6 +110,12 @@ class FeedViewModel @Inject constructor(
settings.isFeedHeaderVisible = value settings.isFeedHeaderVisible = value
} }
fun onItemClick(item: FeedItem) {
launchJob(Dispatchers.Default, CoroutineStart.ATOMIC) {
repository.markAsRead(item.id)
}
}
private fun List<TrackingLogItem>.mapListTo(destination: MutableList<ListModel>) { private fun List<TrackingLogItem>.mapListTo(destination: MutableList<ListModel>) {
var prevDate: DateTimeAgo? = null var prevDate: DateTimeAgo? = null
for (item in this) { for (item in this) {

View File

@@ -4,6 +4,7 @@ import android.content.Context
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader import coil.ImageLoader
import org.koitharu.kotatsu.core.ui.BaseListAdapter import org.koitharu.kotatsu.core.ui.BaseListAdapter
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller
import org.koitharu.kotatsu.list.ui.adapter.ListItemType import org.koitharu.kotatsu.list.ui.adapter.ListItemType
import org.koitharu.kotatsu.list.ui.adapter.MangaListListener import org.koitharu.kotatsu.list.ui.adapter.MangaListListener
@@ -15,16 +16,18 @@ import org.koitharu.kotatsu.list.ui.adapter.loadingFooterAD
import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD
import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.list.ui.size.ItemSizeResolver import org.koitharu.kotatsu.list.ui.size.ItemSizeResolver
import org.koitharu.kotatsu.tracker.ui.feed.model.FeedItem
class FeedAdapter( class FeedAdapter(
coil: ImageLoader, coil: ImageLoader,
lifecycleOwner: LifecycleOwner, lifecycleOwner: LifecycleOwner,
listener: MangaListListener, listener: MangaListListener,
sizeResolver: ItemSizeResolver, sizeResolver: ItemSizeResolver,
feedClickListener: OnListItemClickListener<FeedItem>,
) : BaseListAdapter<ListModel>(), FastScroller.SectionIndexer { ) : BaseListAdapter<ListModel>(), FastScroller.SectionIndexer {
init { init {
addDelegate(ListItemType.FEED, feedItemAD(coil, lifecycleOwner, listener)) addDelegate(ListItemType.FEED, feedItemAD(coil, lifecycleOwner, feedClickListener))
addDelegate( addDelegate(
ListItemType.MANGA_NESTED_GROUP, ListItemType.MANGA_NESTED_GROUP,
updatedMangaAD( updatedMangaAD(

View File

@@ -12,20 +12,19 @@ import org.koitharu.kotatsu.core.util.ext.newImageRequest
import org.koitharu.kotatsu.core.util.ext.source import org.koitharu.kotatsu.core.util.ext.source
import org.koitharu.kotatsu.databinding.ItemFeedBinding import org.koitharu.kotatsu.databinding.ItemFeedBinding
import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.tracker.ui.feed.model.FeedItem import org.koitharu.kotatsu.tracker.ui.feed.model.FeedItem
fun feedItemAD( fun feedItemAD(
coil: ImageLoader, coil: ImageLoader,
lifecycleOwner: LifecycleOwner, lifecycleOwner: LifecycleOwner,
clickListener: OnListItemClickListener<Manga>, clickListener: OnListItemClickListener<FeedItem>,
) = adapterDelegateViewBinding<FeedItem, ListModel, ItemFeedBinding>( ) = adapterDelegateViewBinding<FeedItem, ListModel, ItemFeedBinding>(
{ inflater, parent -> ItemFeedBinding.inflate(inflater, parent, false) }, { inflater, parent -> ItemFeedBinding.inflate(inflater, parent, false) },
) { ) {
val indicatorNew = ContextCompat.getDrawable(context, R.drawable.ic_new) val indicatorNew = ContextCompat.getDrawable(context, R.drawable.ic_new)
itemView.setOnClickListener { itemView.setOnClickListener {
clickListener.onItemClick(item.manga, it) clickListener.onItemClick(item, it)
} }
bind { bind {

View File

@@ -1,5 +1,6 @@
package org.koitharu.kotatsu.tracker.ui.feed.model package org.koitharu.kotatsu.tracker.ui.feed.model
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.Manga
@@ -11,7 +12,14 @@ data class FeedItem(
val count: Int, val count: Int,
val isNew: Boolean, val isNew: Boolean,
) : ListModel { ) : ListModel {
override fun areItemsTheSame(other: ListModel): Boolean { override fun areItemsTheSame(other: ListModel): Boolean {
return other is FeedItem && other.id == id return other is FeedItem && other.id == id
} }
override fun getChangePayload(previousState: ListModel): Any? = when {
previousState !is FeedItem -> null
isNew != previousState.isNew -> ListModelDiffCallback.PAYLOAD_ANYTHING_CHANGED
else -> super.getChangePayload(previousState)
}
} }