Tracking manga updates

This commit is contained in:
Koitharu
2020-03-29 17:32:52 +03:00
parent 80c8344f8d
commit aad26d24ec
12 changed files with 116 additions and 22 deletions

View File

@@ -1,12 +1,19 @@
package org.koitharu.kotatsu.domain
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.media.ThumbnailUtils
import android.util.Size
import androidx.annotation.Px
import androidx.core.graphics.drawable.toBitmap
import coil.Coil
import coil.api.get
import okhttp3.OkHttpClient
import okhttp3.Request
import org.koin.core.KoinComponent
import org.koin.core.get
import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.model.MangaPage
import org.koitharu.kotatsu.core.prefs.ReaderMode
import org.koitharu.kotatsu.utils.ext.await
@@ -54,4 +61,23 @@ object MangaUtils : KoinComponent {
check(imageHeight > 0 && imageWidth > 0)
return Size(imageWidth, imageHeight)
}
suspend fun getMangaIcon(manga: Manga, @Px width: Int, @Px height: Int): Bitmap? {
try {
val bmp = Coil.loader().get(manga.coverUrl) {
size(width, height)
}.toBitmap()
return ThumbnailUtils.extractThumbnail(
bmp,
width,
height,
ThumbnailUtils.OPTIONS_RECYCLE_INPUT
)
} catch (e: Throwable) {
if (BuildConfig.DEBUG) {
e.printStackTrace()
}
return null
}
}
}

View File

@@ -5,10 +5,10 @@ import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.graphics.drawable.toBitmap
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.ui.details.MangaDetailsActivity
@@ -73,7 +73,7 @@ class DownloadNotification(private val context: Context) {
}
fun setLargeIcon(icon: Drawable?) {
builder.setLargeIcon((icon as? BitmapDrawable)?.bitmap)
builder.setLargeIcon(icon?.toBitmap())
}
fun setProgress(chaptersTotal: Int, pagesTotal: Int, chapter: Int, page: Int) {

View File

@@ -4,7 +4,6 @@ import android.content.Context
import android.content.Intent
import android.net.ConnectivityManager
import android.os.PowerManager
import android.os.WorkSource
import android.webkit.MimeTypeMap
import android.widget.Toast
import androidx.core.content.ContextCompat
@@ -14,7 +13,7 @@ import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import okhttp3.OkHttpClient
import okhttp3.Request
import org.koin.core.inject
import org.koin.android.ext.android.inject
import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.local.PagesCache

View File

@@ -2,15 +2,19 @@ package org.koitharu.kotatsu.ui.tracker
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.job.JobInfo
import android.app.job.JobParameters
import android.app.job.JobScheduler
import android.content.ComponentName
import android.content.Context
import android.os.Build
import androidx.annotation.MainThread
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap
import coil.Coil
import coil.api.get
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.koitharu.kotatsu.R
@@ -19,20 +23,19 @@ import org.koitharu.kotatsu.core.model.MangaChapter
import org.koitharu.kotatsu.domain.MangaProviderFactory
import org.koitharu.kotatsu.domain.tracking.TrackingRepository
import org.koitharu.kotatsu.ui.common.BaseJobService
import org.koitharu.kotatsu.ui.details.MangaDetailsActivity
import org.koitharu.kotatsu.utils.ext.safe
import java.util.concurrent.TimeUnit
class TrackerJobService : BaseJobService() {
private lateinit var repo: TrackingRepository
override fun onCreate() {
super.onCreate()
repo = TrackingRepository()
private val notificationManager by lazy(LazyThreadSafetyMode.NONE) {
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
}
override suspend fun doWork(params: JobParameters) {
withContext(Dispatchers.IO) {
val repo = TrackingRepository()
val tracks = repo.getAllTracks()
if (tracks.isEmpty()) {
return@withContext
@@ -53,14 +56,16 @@ class TrackerJobService : BaseJobService() {
newChapters = 0
)
}
track.knownChaptersCount == 0 && track.lastChapterId == 0L -> { //manga was empty on last check
track.knownChaptersCount == 0 && track.lastChapterId == 0L -> { //manga was empty on last check
repo.storeTrackResult(
mangaId = track.manga.id,
knownChaptersCount = track.knownChaptersCount,
lastChapterId = 0L,
newChapters = chapters.size
)
//TODO notify
if (chapters.isNotEmpty()) {
showNotification(track.manga, chapters)
}
}
chapters.size == track.knownChaptersCount -> {
if (chapters.lastOrNull()?.id == track.lastChapterId) {
@@ -78,24 +83,30 @@ class TrackerJobService : BaseJobService() {
newChapters = 0
)
} else {
val newChapters = chapters.size - knownChapter + 1
repo.storeTrackResult(
mangaId = track.manga.id,
knownChaptersCount = knownChapter + 1,
lastChapterId = track.lastChapterId,
newChapters = chapters.size - knownChapter + 1
newChapters = newChapters
)
//TODO notify
if (newChapters != 0) {
showNotification(track.manga, chapters.takeLast(newChapters))
}
}
}
}
else -> {
val newChapters = chapters.size - track.knownChaptersCount
repo.storeTrackResult(
mangaId = track.manga.id,
knownChaptersCount = track.knownChaptersCount,
lastChapterId = track.lastChapterId,
newChapters = chapters.size - track.knownChaptersCount
newChapters = newChapters
)
//TODO notify
if (newChapters != 0) {
showNotification(track.manga, chapters.takeLast(newChapters))
}
}
}
success++
@@ -106,24 +117,55 @@ class TrackerJobService : BaseJobService() {
}
}
@MainThread
private fun showNotification(manga: Manga, newChapters: List<MangaChapter>) {
//TODO
private suspend fun showNotification(manga: Manga, newChapters: List<MangaChapter>) {
val id = manga.url.hashCode()
val colorPrimary = ContextCompat.getColor(this@TrackerJobService, R.color.blue_primary)
val builder = NotificationCompat.Builder(this, CHANNEL_ID)
with(builder) {
setContentText(resources.getQuantityString(R.plurals.new_chapters,
newChapters.size, newChapters.size))
setContentText(manga.title)
setNumber(newChapters.size)
setLargeIcon(safe {
Coil.loader().get(manga.coverUrl).toBitmap()
})
setSmallIcon(R.drawable.ic_stat_book_plus)
val style = NotificationCompat.InboxStyle(this)
for (chapter in newChapters) {
style.addLine(chapter.name)
}
style.setSummaryText(manga.title)
setStyle(style)
val intent = MangaDetailsActivity.newIntent(this@TrackerJobService, manga)
setContentIntent(PendingIntent.getActivity(this@TrackerJobService, id,
intent, PendingIntent.FLAG_UPDATE_CURRENT))
setAutoCancel(true)
color = colorPrimary
setLights(colorPrimary, 1000, 5000)
setPriority(NotificationCompat.PRIORITY_DEFAULT)
}
withContext(Dispatchers.Main) {
notificationManager.notify(TAG, id, builder.build())
}
}
companion object {
private const val JOB_ID = 7
private const val CHANNEL_ID = "tracking"
private const val TAG = "tracking"
@RequiresApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(context: Context) {
val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val manager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (manager.getNotificationChannel(CHANNEL_ID) == null) {
val channel = NotificationChannel(CHANNEL_ID,
context.getString(R.string.new_chapters), NotificationManager.IMPORTANCE_DEFAULT)
context.getString(R.string.new_chapters),
NotificationManager.IMPORTANCE_DEFAULT)
channel.setShowBadge(true)
channel.lightColor = ContextCompat.getColor(context, R.color.blue_primary)
channel.enableLights(true)
manager.createNotificationChannel(channel)
}
}
@@ -136,7 +178,8 @@ class TrackerJobService : BaseJobService() {
// if (scheduler.allPendingJobs != null) {
// return
// }
val jobInfo = JobInfo.Builder(JOB_ID, ComponentName(context, TrackerJobService::class.java))
val jobInfo =
JobInfo.Builder(JOB_ID, ComponentName(context, TrackerJobService::class.java))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
jobInfo.setRequiredNetworkType(JobInfo.NETWORK_TYPE_NOT_ROAMING)
} else {

View File

@@ -0,0 +1,17 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="24"
android:viewportHeight="24">
<group
android:scaleX="0.92"
android:scaleY="0.92"
android:translateX="0.96"
android:translateY="0.96">
<path
android:fillColor="#FF000000"
android:pathData="M18,22H6A2,2 0,0 1,4 20V4C4,2.89 4.9,2 6,2H7V9L9.5,7.5L12,9V2H18A2,2 0,0 1,20 4V20A2,2 0,0 1,18 22M14,20H16V18H18V16H16V14H14V16H12V18H14V20Z" />
</group>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 629 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 914 B

View File

@@ -10,4 +10,9 @@
<item quantity="few">%1$d элемента</item>
<item quantity="many">%1$d элементов</item>
</plurals>
<plurals name="new_chapters">
<item quantity="one">%1$d новая глава</item>
<item quantity="few">%1$d новых главы</item>
<item quantity="many">%1$d новых глав</item>
</plurals>
</resources>

View File

@@ -8,4 +8,8 @@
<item quantity="one">%1$d item</item>
<item quantity="other">%1$d items</item>
</plurals>
<plurals name="new_chapters">
<item quantity="one">%1$d new chapter</item>
<item quantity="other">%1$d new chapters</item>
</plurals>
</resources>