Tracking manga updates

remotes/weblate/feature/pagecrop
Koitharu 6 years ago
parent 80c8344f8d
commit aad26d24ec

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

@ -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) {

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

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

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

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

@ -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>
Loading…
Cancel
Save