Tracker fixes
This commit is contained in:
@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.domain
|
||||
import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import android.util.Size
|
||||
import androidx.annotation.WorkerThread
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.koin.core.KoinComponent
|
||||
@@ -21,6 +22,8 @@ object MangaUtils : KoinComponent {
|
||||
* Automatic determine type of manga by page size
|
||||
* @return ReaderMode.WEBTOON if page is wide
|
||||
*/
|
||||
@WorkerThread
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
suspend fun determineReaderMode(pages: List<MangaPage>): ReaderMode? {
|
||||
try {
|
||||
val page = pages.medianOrNull() ?: return null
|
||||
|
||||
@@ -49,7 +49,7 @@ class TrackingRepository : KoinComponent {
|
||||
knownChaptersCount: Int,
|
||||
lastChapterId: Long,
|
||||
newChapters: List<MangaChapter>,
|
||||
lastNotifiedChapterId: Long
|
||||
previousTrackChapterId: Long
|
||||
) {
|
||||
db.withTransaction {
|
||||
val entity = TrackEntity(
|
||||
@@ -58,13 +58,15 @@ class TrackingRepository : KoinComponent {
|
||||
lastCheck = System.currentTimeMillis(),
|
||||
lastChapterId = lastChapterId,
|
||||
totalChapters = knownChaptersCount,
|
||||
lastNotifiedChapterId = lastNotifiedChapterId
|
||||
lastNotifiedChapterId = newChapters.lastOrNull()?.id ?: previousTrackChapterId
|
||||
)
|
||||
db.tracksDao.upsert(entity)
|
||||
if (newChapters.isNotEmpty()) {
|
||||
val logEntity = TrackLogEntity(
|
||||
mangaId = mangaId,
|
||||
chapters = newChapters.joinToString("\n") { x -> x.name },
|
||||
chapters = newChapters
|
||||
.takeLastWhile { x -> x.id != previousTrackChapterId }
|
||||
.joinToString("\n") { x -> x.name },
|
||||
createdAt = System.currentTimeMillis()
|
||||
)
|
||||
db.trackLogsDao.insert(logEntity)
|
||||
|
||||
@@ -87,16 +87,23 @@ abstract class BaseRecyclerAdapter<T, E>(private val onItemClickListener: OnRecy
|
||||
final override fun getItemCount() = dataSet.size
|
||||
|
||||
final override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<T, E> {
|
||||
return onCreateViewHolder(parent).setOnItemClickListener(onItemClickListener)
|
||||
.also(this::onViewHolderCreated)
|
||||
return onCreateViewHolder(parent)
|
||||
}
|
||||
|
||||
override fun onViewDetachedFromWindow(holder: BaseViewHolder<T, E>) {
|
||||
holder.setOnItemClickListener(null)
|
||||
super.onViewDetachedFromWindow(holder)
|
||||
}
|
||||
|
||||
override fun onViewAttachedToWindow(holder: BaseViewHolder<T, E>) {
|
||||
super.onViewAttachedToWindow(holder)
|
||||
holder.setOnItemClickListener(onItemClickListener)
|
||||
}
|
||||
|
||||
protected open fun onDataSetChanged() = Unit
|
||||
|
||||
protected abstract fun getExtra(item: T, position: Int): E
|
||||
|
||||
protected open fun onViewHolderCreated(holder: BaseViewHolder<T, E>) = Unit
|
||||
|
||||
protected abstract fun onCreateViewHolder(parent: ViewGroup): BaseViewHolder<T, E>
|
||||
|
||||
protected abstract fun onGetItemId(item: T): Long
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.koitharu.kotatsu.ui.common.list
|
||||
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.LayoutRes
|
||||
@@ -27,26 +26,29 @@ abstract class BaseViewHolder<T, E> protected constructor(view: View) :
|
||||
onBind(data, extra)
|
||||
}
|
||||
|
||||
fun requireData() = boundData ?: throw IllegalStateException("Calling requireData() before bind()")
|
||||
fun requireData(): T {
|
||||
return boundData ?: throw IllegalStateException("Calling requireData() before bind()")
|
||||
}
|
||||
|
||||
fun setOnItemClickListener(listener: OnRecyclerItemClickListener<T>?): BaseViewHolder<T, E> {
|
||||
if (listener != null) {
|
||||
itemView.setOnClickListener {
|
||||
listener.onItemClick(boundData ?: return@setOnClickListener, bindingAdapterPosition, it)
|
||||
}
|
||||
itemView.setOnLongClickListener {
|
||||
listener.onItemLongClick(boundData ?: return@setOnLongClickListener false, bindingAdapterPosition, it)
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
itemView.setOnContextClickListener {
|
||||
listener.onItemLongClick(boundData ?: return@setOnContextClickListener false, bindingAdapterPosition, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
return this
|
||||
fun setOnItemClickListener(listener: OnRecyclerItemClickListener<T>?) {
|
||||
val listenersAdapter = listener?.let { HolderListenersAdapter(it) }
|
||||
itemView.setOnClickListener(listenersAdapter)
|
||||
itemView.setOnLongClickListener(listenersAdapter)
|
||||
}
|
||||
|
||||
open fun onRecycled() = Unit
|
||||
|
||||
abstract fun onBind(data: T, extra: E)
|
||||
|
||||
private inner class HolderListenersAdapter(private val listener: OnRecyclerItemClickListener<T>) :
|
||||
View.OnClickListener, View.OnLongClickListener {
|
||||
|
||||
override fun onClick(v: View) {
|
||||
listener.onItemClick(boundData ?: return, bindingAdapterPosition, v)
|
||||
}
|
||||
|
||||
override fun onLongClick(v: View): Boolean {
|
||||
return listener.onItemLongClick(boundData ?: return false, bindingAdapterPosition, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ class CategoriesAdapter(private val onItemClickListener: OnRecyclerItemClickList
|
||||
override fun getExtra(item: FavouriteCategory, position: Int) = Unit
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onViewHolderCreated(holder: BaseViewHolder<FavouriteCategory, Unit>) {
|
||||
override fun onViewAttachedToWindow(holder: BaseViewHolder<FavouriteCategory, Unit>) {
|
||||
holder.imageView_more.setOnClickListener { v ->
|
||||
onItemClickListener.onItemClick(holder.requireData(), holder.bindingAdapterPosition, v)
|
||||
}
|
||||
@@ -32,6 +32,11 @@ class CategoriesAdapter(private val onItemClickListener: OnRecyclerItemClickList
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewDetachedFromWindow(holder: BaseViewHolder<FavouriteCategory, Unit>) {
|
||||
holder.imageView_more.setOnClickListener(null)
|
||||
holder.imageView_handle.setOnTouchListener(null)
|
||||
}
|
||||
|
||||
fun moveItem(oldPos: Int, newPos: Int) {
|
||||
val item = dataSet.removeAt(oldPos)
|
||||
dataSet.add(newPos, item)
|
||||
|
||||
@@ -31,8 +31,11 @@ class CategoriesSelectAdapter(private val listener: OnCategoryCheckListener) :
|
||||
|
||||
override fun onGetItemId(item: FavouriteCategory) = item.id
|
||||
|
||||
override fun onViewHolderCreated(holder: BaseViewHolder<FavouriteCategory, Boolean>) {
|
||||
super.onViewHolderCreated(holder)
|
||||
override fun onViewDetachedFromWindow(holder: BaseViewHolder<FavouriteCategory, Boolean>) {
|
||||
holder.itemView.setOnClickListener(null)
|
||||
}
|
||||
|
||||
override fun onViewAttachedToWindow(holder: BaseViewHolder<FavouriteCategory, Boolean>) {
|
||||
holder.itemView.setOnClickListener {
|
||||
if (it !is Checkable) return@setOnClickListener
|
||||
it.toggle()
|
||||
|
||||
@@ -55,7 +55,7 @@ class TrackWorker(context: Context, workerParams: WorkerParameters) :
|
||||
mangaId = track.manga.id,
|
||||
knownChaptersCount = chapters.size,
|
||||
lastChapterId = chapters.lastOrNull()?.id ?: 0L,
|
||||
lastNotifiedChapterId = 0L,
|
||||
previousTrackChapterId = 0L,
|
||||
newChapters = emptyList()
|
||||
)
|
||||
}
|
||||
@@ -64,7 +64,7 @@ class TrackWorker(context: Context, workerParams: WorkerParameters) :
|
||||
mangaId = track.manga.id,
|
||||
knownChaptersCount = track.knownChaptersCount,
|
||||
lastChapterId = 0L,
|
||||
lastNotifiedChapterId = chapters.lastOrNull()?.id ?: 0L,
|
||||
previousTrackChapterId = track.lastNotifiedChapterId,
|
||||
newChapters = chapters
|
||||
)
|
||||
showNotification(track.manga, chapters)
|
||||
@@ -82,7 +82,7 @@ class TrackWorker(context: Context, workerParams: WorkerParameters) :
|
||||
mangaId = track.manga.id,
|
||||
knownChaptersCount = chapters.size,
|
||||
lastChapterId = chapters.lastOrNull()?.id ?: 0L,
|
||||
lastNotifiedChapterId = chapters.lastOrNull()?.id ?: 0L,
|
||||
previousTrackChapterId = track.lastNotifiedChapterId,
|
||||
newChapters = emptyList()
|
||||
)
|
||||
} else {
|
||||
@@ -91,12 +91,13 @@ class TrackWorker(context: Context, workerParams: WorkerParameters) :
|
||||
mangaId = track.manga.id,
|
||||
knownChaptersCount = knownChapter + 1,
|
||||
lastChapterId = track.lastChapterId,
|
||||
lastNotifiedChapterId = chapters.lastOrNull()?.id ?: 0L,
|
||||
previousTrackChapterId = track.lastNotifiedChapterId,
|
||||
newChapters = newChapters
|
||||
)
|
||||
if (chapters.lastOrNull()?.id != track.lastNotifiedChapterId) {
|
||||
showNotification(track.manga, newChapters)
|
||||
}
|
||||
showNotification(
|
||||
track.manga,
|
||||
newChapters.takeLastWhile { x -> x.id != track.lastNotifiedChapterId }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,12 +107,13 @@ class TrackWorker(context: Context, workerParams: WorkerParameters) :
|
||||
mangaId = track.manga.id,
|
||||
knownChaptersCount = track.knownChaptersCount,
|
||||
lastChapterId = track.lastChapterId,
|
||||
lastNotifiedChapterId = chapters.lastOrNull()?.id ?: 0L,
|
||||
previousTrackChapterId = track.lastNotifiedChapterId,
|
||||
newChapters = newChapters
|
||||
)
|
||||
if (chapters.lastOrNull()?.id != track.lastNotifiedChapterId) {
|
||||
showNotification(track.manga, newChapters)
|
||||
}
|
||||
showNotification(
|
||||
track.manga,
|
||||
newChapters.takeLastWhile { x -> x.id != track.lastNotifiedChapterId }
|
||||
)
|
||||
}
|
||||
}
|
||||
success++
|
||||
@@ -130,15 +132,21 @@ class TrackWorker(context: Context, workerParams: WorkerParameters) :
|
||||
val id = manga.url.hashCode()
|
||||
val colorPrimary = ContextCompat.getColor(applicationContext, R.color.blue_primary)
|
||||
val builder = NotificationCompat.Builder(applicationContext, CHANNEL_ID)
|
||||
val summary = applicationContext.resources.getQuantityString(R.plurals.new_chapters,
|
||||
newChapters.size, newChapters.size)
|
||||
val summary = applicationContext.resources.getQuantityString(
|
||||
R.plurals.new_chapters,
|
||||
newChapters.size, newChapters.size
|
||||
)
|
||||
with(builder) {
|
||||
setContentText(summary)
|
||||
setContentTitle(manga.title)
|
||||
setNumber(newChapters.size)
|
||||
setLargeIcon(Coil.execute(GetRequestBuilder(applicationContext)
|
||||
.data(manga.coverUrl)
|
||||
.build()).toBitmapOrNull())
|
||||
setLargeIcon(
|
||||
Coil.execute(
|
||||
GetRequestBuilder(applicationContext)
|
||||
.data(manga.coverUrl)
|
||||
.build()
|
||||
).toBitmapOrNull()
|
||||
)
|
||||
setSmallIcon(R.drawable.ic_stat_book_plus)
|
||||
val style = NotificationCompat.InboxStyle(this)
|
||||
for (chapter in newChapters) {
|
||||
@@ -148,8 +156,12 @@ class TrackWorker(context: Context, workerParams: WorkerParameters) :
|
||||
style.setBigContentTitle(summary)
|
||||
setStyle(style)
|
||||
val intent = MangaDetailsActivity.newIntent(applicationContext, manga)
|
||||
setContentIntent(PendingIntent.getActivity(applicationContext, id,
|
||||
intent, PendingIntent.FLAG_UPDATE_CURRENT))
|
||||
setContentIntent(
|
||||
PendingIntent.getActivity(
|
||||
applicationContext, id,
|
||||
intent, PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
)
|
||||
setAutoCancel(true)
|
||||
color = colorPrimary
|
||||
setShortcutId(manga.id.toString())
|
||||
@@ -182,9 +194,11 @@ class TrackWorker(context: Context, workerParams: WorkerParameters) :
|
||||
val manager =
|
||||
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
if (manager.getNotificationChannel(CHANNEL_ID) == null) {
|
||||
val channel = NotificationChannel(CHANNEL_ID,
|
||||
val channel = NotificationChannel(
|
||||
CHANNEL_ID,
|
||||
context.getString(R.string.new_chapters),
|
||||
NotificationManager.IMPORTANCE_DEFAULT)
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
)
|
||||
channel.setShowBadge(true)
|
||||
channel.lightColor = ContextCompat.getColor(context, R.color.blue_primary)
|
||||
channel.enableLights(true)
|
||||
|
||||
@@ -40,12 +40,12 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?android:listPreferredItemHeightSmall"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:drawableEnd="@drawable/ic_add"
|
||||
android:gravity="start|center_vertical"
|
||||
android:paddingStart="?android:listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:listPreferredItemPaddingEnd"
|
||||
android:text="@string/add_new_category"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||
android:textColor="?android:textColorPrimary" />
|
||||
android:textColor="?android:textColorPrimary"
|
||||
app:drawableEndCompat="@drawable/ic_add" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -6,7 +6,8 @@
|
||||
android:layout_height="?android:listPreferredItemHeightSmall"
|
||||
android:background="?android:windowBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
android:orientation="horizontal"
|
||||
tools:ignore="Overdraw">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView_handle"
|
||||
|
||||
@@ -89,10 +89,10 @@
|
||||
android:id="@+id/textView_rating"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableStart="@drawable/ic_star_rating"
|
||||
android:drawablePadding="4dp"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||
tools:text="10/10" />
|
||||
tools:text="10/10"
|
||||
app:drawableStartCompat="@drawable/ic_star_rating" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:background="?android:windowBackground"
|
||||
android:layout_width="match_parent"
|
||||
@@ -33,11 +34,11 @@
|
||||
android:id="@+id/textView_error"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableTop="@drawable/ic_error_large"
|
||||
android:drawablePadding="12dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
tools:text="@tools:sample/lorem[6]" />
|
||||
tools:text="@tools:sample/lorem[6]"
|
||||
app:drawableTopCompat="@drawable/ic_error_large" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_retry"
|
||||
|
||||
@@ -36,11 +36,11 @@
|
||||
android:id="@+id/textView_error"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableTop="@drawable/ic_error_large"
|
||||
android:drawablePadding="12dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
tools:text="@tools:sample/lorem[6]" />
|
||||
tools:text="@tools:sample/lorem[6]"
|
||||
app:drawableTopCompat="@drawable/ic_error_large" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_retry"
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?listPreferredItemHeightSmall"
|
||||
android:background="?selectableItemBackground"
|
||||
android:drawableStart="@drawable/ic_history"
|
||||
android:drawablePadding="20dp"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="?listPreferredItemPaddingStart"
|
||||
@@ -13,4 +13,5 @@
|
||||
android:textAppearance="?textAppearanceListItemSmall"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:theme="@style/AppPopupTheme"
|
||||
tools:text="@tools:sample/full_names" />
|
||||
tools:text="@tools:sample/full_names"
|
||||
app:drawableStartCompat="@drawable/ic_history" />
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_save_this"
|
||||
android:title="@string/save_this_chapter" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_save_this_next"
|
||||
android:title="@string/save_this_chapter_and_next" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_save_this_prev"
|
||||
android:title="@string/save_this_chapter_and_prev" />
|
||||
|
||||
</menu>
|
||||
@@ -38,9 +38,6 @@
|
||||
<string name="processing_">Обработка…</string>
|
||||
<string name="download_complete">Загрузка завершена</string>
|
||||
<string name="downloads">Загрузки</string>
|
||||
<string name="save_this_chapter_and_prev">Сохранить предыдущие главы</string>
|
||||
<string name="save_this_chapter_and_next">Сохранить следующие главы</string>
|
||||
<string name="save_this_chapter">Сохранить эту главу</string>
|
||||
<string name="by_name">По имени</string>
|
||||
<string name="popular">Популярная</string>
|
||||
<string name="updated">Обновлённая</string>
|
||||
|
||||
@@ -39,9 +39,6 @@
|
||||
<string name="processing_">Processing…</string>
|
||||
<string name="download_complete">Download complete</string>
|
||||
<string name="downloads">Downloads</string>
|
||||
<string name="save_this_chapter_and_prev">Save this chapter and prev.</string>
|
||||
<string name="save_this_chapter_and_next">Save this chapter and next</string>
|
||||
<string name="save_this_chapter">Save this chapter</string>
|
||||
<string name="by_name">By name</string>
|
||||
<string name="popular">Popular</string>
|
||||
<string name="updated">Updated</string>
|
||||
|
||||
Reference in New Issue
Block a user