Refactor tracker
This commit is contained in:
@@ -135,7 +135,7 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
||||
get() = prefs.getEnumValue(KEY_ZOOM_MODE, ZoomMode.FIT_CENTER)
|
||||
|
||||
val trackSources: Set<String>
|
||||
get() = prefs.getStringSet(KEY_TRACK_SOURCES, null) ?: arraySetOf(TRACK_FAVOURITES, TRACK_HISTORY)
|
||||
get() = prefs.getStringSet(KEY_TRACK_SOURCES, null) ?: setOf(TRACK_FAVOURITES)
|
||||
|
||||
var appPassword: String?
|
||||
get() = prefs.getString(KEY_APP_PASSWORD, null)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.koitharu.kotatsu.core.util.ext
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.ActivityManager
|
||||
@@ -13,6 +14,7 @@ import android.content.ContextWrapper
|
||||
import android.content.OperationApplicationException
|
||||
import android.content.SharedPreferences
|
||||
import android.content.SyncResult
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.ResolveInfo
|
||||
import android.database.SQLException
|
||||
import android.graphics.Color
|
||||
@@ -28,6 +30,8 @@ import android.widget.Toast
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.annotation.IntegerRes
|
||||
import androidx.core.app.ActivityOptionsCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.coroutineScope
|
||||
@@ -220,3 +224,9 @@ inline fun Activity.catchingWebViewUnavailability(block: () -> Unit): Boolean {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.checkNotificationPermission(): Boolean = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED
|
||||
} else {
|
||||
NotificationManagerCompat.from(this).areNotificationsEnabled()
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ class Tracker @Inject constructor(
|
||||
if (sources.isEmpty()) {
|
||||
return emptyList()
|
||||
}
|
||||
val knownIds = HashSet<Manga>()
|
||||
val knownManga = HashSet<Long>()
|
||||
val result = ArrayList<TrackingItem>()
|
||||
// Favourites
|
||||
if (AppSettings.TRACK_FAVOURITES in sources) {
|
||||
@@ -42,7 +42,7 @@ class Tracker @Inject constructor(
|
||||
null
|
||||
}
|
||||
for (track in categoryTracks) {
|
||||
if (knownIds.add(track.manga)) {
|
||||
if (knownManga.add(track.manga.id)) {
|
||||
result.add(TrackingItem(track, channelId))
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ class Tracker @Inject constructor(
|
||||
null
|
||||
}
|
||||
for (track in historyTracks) {
|
||||
if (knownIds.add(track.manga)) {
|
||||
if (knownManga.add(track.manga.id)) {
|
||||
result.add(TrackingItem(track, channelId))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.koitharu.kotatsu.tracker.work
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
@@ -34,11 +33,11 @@ import dagger.Reusable
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.channelFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.supervisorScope
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Semaphore
|
||||
import kotlinx.coroutines.sync.withPermit
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -49,6 +48,7 @@ import org.koitharu.kotatsu.core.logs.FileLogger
|
||||
import org.koitharu.kotatsu.core.logs.TrackerLogger
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.util.ext.awaitUniqueWorkInfoByName
|
||||
import org.koitharu.kotatsu.core.util.ext.checkNotificationPermission
|
||||
import org.koitharu.kotatsu.core.util.ext.toBitmapOrNull
|
||||
import org.koitharu.kotatsu.core.util.ext.trySetForeground
|
||||
import org.koitharu.kotatsu.details.ui.DetailsActivity
|
||||
@@ -70,6 +70,7 @@ class TrackWorker @AssistedInject constructor(
|
||||
private val tracker: Tracker,
|
||||
@TrackerLogger private val logger: FileLogger,
|
||||
) : CoroutineWorker(context, workerParams) {
|
||||
|
||||
private val notificationManager by lazy { NotificationManagerCompat.from(applicationContext) }
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
@@ -121,35 +122,36 @@ class TrackWorker @AssistedInject constructor(
|
||||
|
||||
private suspend fun checkUpdatesAsync(tracks: List<TrackingItem>): List<MangaUpdates?> {
|
||||
val semaphore = Semaphore(MAX_PARALLELISM)
|
||||
return supervisorScope {
|
||||
tracks.map { (track, channelId) ->
|
||||
async {
|
||||
return channelFlow {
|
||||
for ((track, channelId) in tracks) {
|
||||
launch {
|
||||
semaphore.withPermit {
|
||||
runCatchingCancellable {
|
||||
tracker.fetchUpdates(track, commit = true)
|
||||
}.onFailure { e ->
|
||||
if (e is CloudFlareProtectedException) {
|
||||
CaptchaNotifier(applicationContext).notify(e)
|
||||
}
|
||||
logger.log("checkUpdatesAsync", e)
|
||||
}.onSuccess { updates ->
|
||||
if (updates.isValid && updates.isNotEmpty()) {
|
||||
showNotification(
|
||||
manga = updates.manga,
|
||||
channelId = channelId,
|
||||
newChapters = updates.newChapters,
|
||||
)
|
||||
}
|
||||
}.getOrNull()
|
||||
send(
|
||||
runCatchingCancellable {
|
||||
tracker.fetchUpdates(track, commit = true)
|
||||
}.onFailure { e ->
|
||||
if (e is CloudFlareProtectedException) {
|
||||
CaptchaNotifier(applicationContext).notify(e)
|
||||
}
|
||||
logger.log("checkUpdatesAsync", e)
|
||||
}.onSuccess { updates ->
|
||||
if (updates.isValid && updates.isNotEmpty()) {
|
||||
showNotification(
|
||||
manga = updates.manga,
|
||||
channelId = channelId,
|
||||
newChapters = updates.newChapters,
|
||||
)
|
||||
}
|
||||
}.getOrNull(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}.awaitAll()
|
||||
}
|
||||
}
|
||||
}.toList(ArrayList(tracks.size))
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
private suspend fun showNotification(manga: Manga, channelId: String?, newChapters: List<MangaChapter>) {
|
||||
if (newChapters.isEmpty() || channelId == null || !notificationManager.areNotificationsEnabled()) {
|
||||
if (newChapters.isEmpty() || channelId == null || !applicationContext.checkNotificationPermission()) {
|
||||
return
|
||||
}
|
||||
val id = manga.url.hashCode()
|
||||
|
||||
Reference in New Issue
Block a user