mirror of
https://github.com/gedoor/legado.git
synced 2024-08-30 09:23:26 +08:00
优化
This commit is contained in:
parent
c9d07d08c4
commit
3882904f1d
@ -31,7 +31,12 @@ abstract class BaseService : LifecycleService() {
|
|||||||
super.onCreate()
|
super.onCreate()
|
||||||
LifecycleHelp.onServiceCreate(this)
|
LifecycleHelp.onServiceCreate(this)
|
||||||
checkNotificationPermission()
|
checkNotificationPermission()
|
||||||
upNotification()
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
startForegroundNotification()
|
||||||
|
return super.onStartCommand(intent, flags, startId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
@ -52,9 +57,9 @@ abstract class BaseService : LifecycleService() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新通知
|
* 开启前台服务并发送通知
|
||||||
*/
|
*/
|
||||||
open fun upNotification() {
|
open fun startForegroundNotification() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +72,7 @@ abstract class BaseService : LifecycleService() {
|
|||||||
.rationale(R.string.notification_permission_rationale)
|
.rationale(R.string.notification_permission_rationale)
|
||||||
.onGranted {
|
.onGranted {
|
||||||
if (lifecycleScope.isActive) {
|
if (lifecycleScope.isActive) {
|
||||||
upNotification()
|
startForegroundNotification()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.request()
|
.request()
|
||||||
|
@ -14,7 +14,13 @@ import io.legado.app.help.RuleBigDataHelp
|
|||||||
import io.legado.app.help.config.AppConfig
|
import io.legado.app.help.config.AppConfig
|
||||||
import io.legado.app.model.analyzeRule.AnalyzeUrl
|
import io.legado.app.model.analyzeRule.AnalyzeUrl
|
||||||
import io.legado.app.model.analyzeRule.RuleDataInterface
|
import io.legado.app.model.analyzeRule.RuleDataInterface
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.ChineseUtils
|
||||||
|
import io.legado.app.utils.GSON
|
||||||
|
import io.legado.app.utils.MD5Utils
|
||||||
|
import io.legado.app.utils.NetworkUtils
|
||||||
|
import io.legado.app.utils.fromJsonObject
|
||||||
|
import io.legado.app.utils.replace
|
||||||
|
import io.legado.app.utils.toastOnUi
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.parcelize.IgnoredOnParcel
|
import kotlinx.parcelize.IgnoredOnParcel
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
@ -110,7 +116,7 @@ data class BookChapter(
|
|||||||
try {
|
try {
|
||||||
val mDisplayTitle = if (item.isRegex) {
|
val mDisplayTitle = if (item.isRegex) {
|
||||||
displayTitle.replace(
|
displayTitle.replace(
|
||||||
item.pattern.toRegex(),
|
item.regex,
|
||||||
item.replacement,
|
item.replacement,
|
||||||
item.getValidTimeoutMillisecond()
|
item.getValidTimeoutMillisecond()
|
||||||
)
|
)
|
||||||
|
@ -4,11 +4,13 @@ import android.os.Parcelable
|
|||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import androidx.room.ColumnInfo
|
import androidx.room.ColumnInfo
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
|
import androidx.room.Ignore
|
||||||
import androidx.room.Index
|
import androidx.room.Index
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
import io.legado.app.constant.AppLog
|
import io.legado.app.constant.AppLog
|
||||||
import io.legado.app.exception.NoStackTraceException
|
import io.legado.app.exception.NoStackTraceException
|
||||||
|
import kotlinx.parcelize.IgnoredOnParcel
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
@ -68,6 +70,12 @@ data class ReplaceRule(
|
|||||||
return id.hashCode()
|
return id.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@delegate:Ignore
|
||||||
|
@IgnoredOnParcel
|
||||||
|
val regex: Regex by lazy {
|
||||||
|
pattern.toRegex()
|
||||||
|
}
|
||||||
|
|
||||||
fun getDisplayNameGroup(): String {
|
fun getDisplayNameGroup(): String {
|
||||||
return if (group.isNullOrBlank()) {
|
return if (group.isNullOrBlank()) {
|
||||||
name
|
name
|
||||||
|
@ -152,7 +152,7 @@ class ContentProcessor private constructor(
|
|||||||
try {
|
try {
|
||||||
val tmp = if (item.isRegex) {
|
val tmp = if (item.isRegex) {
|
||||||
mContent.replace(
|
mContent.replace(
|
||||||
item.pattern.toRegex(),
|
item.regex,
|
||||||
item.replacement,
|
item.replacement,
|
||||||
item.getValidTimeoutMillisecond()
|
item.getValidTimeoutMillisecond()
|
||||||
)
|
)
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
package io.legado.app.help.coroutine
|
|
||||||
|
|
||||||
import kotlinx.coroutines.*
|
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
|
||||||
import java.util.concurrent.PriorityBlockingQueue
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
|
||||||
|
|
||||||
class OrderCoroutine<T>(val threadCount: Int) {
|
|
||||||
private val taskList = ArrayList<suspend CoroutineScope.() -> T>()
|
|
||||||
private val taskResultMap = ConcurrentHashMap<Int, T>()
|
|
||||||
private val finishTaskIndex = PriorityBlockingQueue<Int>()
|
|
||||||
|
|
||||||
private suspend fun start() = coroutineScope {
|
|
||||||
val taskIndex = AtomicInteger(0)
|
|
||||||
val tasks = taskList.toList()
|
|
||||||
for (i in 1..threadCount) {
|
|
||||||
launch {
|
|
||||||
while (true) {
|
|
||||||
ensureActive()
|
|
||||||
val curIndex = taskIndex.getAndIncrement()
|
|
||||||
val task = tasks.getOrNull(curIndex) ?: return@launch
|
|
||||||
taskResultMap[curIndex] = task.invoke(this)
|
|
||||||
finishTaskIndex.add(curIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun submit(block: suspend CoroutineScope.() -> T) {
|
|
||||||
taskList.add(block)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun collect(block: (index: Int, result: T) -> Unit) = withContext(IO) {
|
|
||||||
var index = 0
|
|
||||||
val taskSize = taskList.size
|
|
||||||
launch { start() }
|
|
||||||
while (index < taskSize) {
|
|
||||||
ensureActive()
|
|
||||||
if (finishTaskIndex.peek() == index) {
|
|
||||||
finishTaskIndex.poll()
|
|
||||||
block.invoke(index, taskResultMap.remove(index)!!)
|
|
||||||
index++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -83,6 +83,17 @@ object CacheBook {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
successDownloadSet.clear()
|
||||||
|
errorDownloadMap.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun close() {
|
||||||
|
cacheBookMap.forEach { it.value.stop() }
|
||||||
|
cacheBookMap.clear()
|
||||||
|
clear()
|
||||||
|
}
|
||||||
|
|
||||||
val downloadSummary: String
|
val downloadSummary: String
|
||||||
get() {
|
get() {
|
||||||
return "正在下载:${onDownloadCount}|等待中:${waitCount}|失败:${errorDownloadMap.count()}|成功:${successDownloadSet.size}"
|
return "正在下载:${onDownloadCount}|等待中:${waitCount}|失败:${errorDownloadMap.count()}|成功:${successDownloadSet.size}"
|
||||||
|
@ -55,6 +55,7 @@ import kotlinx.coroutines.isActive
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
import splitties.systemservices.audioManager
|
import splitties.systemservices.audioManager
|
||||||
|
import splitties.systemservices.notificationManager
|
||||||
import splitties.systemservices.powerManager
|
import splitties.systemservices.powerManager
|
||||||
import splitties.systemservices.wifiManager
|
import splitties.systemservices.wifiManager
|
||||||
|
|
||||||
@ -135,7 +136,7 @@ class AudioPlayService : BaseService(),
|
|||||||
.get()
|
.get()
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
cover = it
|
cover = it
|
||||||
upNotification()
|
upAudioPlayNotification()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,7 +192,7 @@ class AudioPlayService : BaseService(),
|
|||||||
wakeLock.acquire()
|
wakeLock.acquire()
|
||||||
wifiLock?.acquire()
|
wifiLock?.acquire()
|
||||||
}
|
}
|
||||||
upNotification()
|
upAudioPlayNotification()
|
||||||
if (!requestFocus()) {
|
if (!requestFocus()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -235,7 +236,7 @@ class AudioPlayService : BaseService(),
|
|||||||
upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PAUSED)
|
upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PAUSED)
|
||||||
AudioPlay.status = Status.PAUSE
|
AudioPlay.status = Status.PAUSE
|
||||||
postEvent(EventBus.AUDIO_STATE, Status.PAUSE)
|
postEvent(EventBus.AUDIO_STATE, Status.PAUSE)
|
||||||
upNotification()
|
upAudioPlayNotification()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printOnDebug()
|
e.printOnDebug()
|
||||||
}
|
}
|
||||||
@ -263,7 +264,7 @@ class AudioPlayService : BaseService(),
|
|||||||
upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING)
|
upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING)
|
||||||
AudioPlay.status = Status.PLAY
|
AudioPlay.status = Status.PLAY
|
||||||
postEvent(EventBus.AUDIO_STATE, Status.PLAY)
|
postEvent(EventBus.AUDIO_STATE, Status.PLAY)
|
||||||
upNotification()
|
upAudioPlayNotification()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printOnDebug()
|
e.printOnDebug()
|
||||||
stopSelf()
|
stopSelf()
|
||||||
@ -335,7 +336,7 @@ class AudioPlayService : BaseService(),
|
|||||||
AudioPlay.next(this)
|
AudioPlay.next(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
upNotification()
|
upAudioPlayNotification()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -370,7 +371,7 @@ class AudioPlayService : BaseService(),
|
|||||||
*/
|
*/
|
||||||
private fun doDs() {
|
private fun doDs() {
|
||||||
postEvent(EventBus.AUDIO_DS, timeMinute)
|
postEvent(EventBus.AUDIO_DS, timeMinute)
|
||||||
upNotification()
|
upAudioPlayNotification()
|
||||||
dsJob?.cancel()
|
dsJob?.cancel()
|
||||||
dsJob = lifecycleScope.launch {
|
dsJob = lifecycleScope.launch {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
@ -384,7 +385,7 @@ class AudioPlayService : BaseService(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
postEvent(EventBus.AUDIO_DS, timeMinute)
|
postEvent(EventBus.AUDIO_DS, timeMinute)
|
||||||
upNotification()
|
upAudioPlayNotification()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -583,67 +584,78 @@ class AudioPlayService : BaseService(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createNotification(): NotificationCompat.Builder {
|
||||||
|
var nTitle: String = when {
|
||||||
|
pause -> getString(R.string.audio_pause)
|
||||||
|
timeMinute in 1..60 -> getString(
|
||||||
|
R.string.playing_timer,
|
||||||
|
timeMinute
|
||||||
|
)
|
||||||
|
|
||||||
|
else -> getString(R.string.audio_play_t)
|
||||||
|
}
|
||||||
|
nTitle += ": ${AudioPlay.book?.name}"
|
||||||
|
var nSubtitle = AudioPlay.durChapter?.title
|
||||||
|
if (nSubtitle.isNullOrEmpty()) {
|
||||||
|
nSubtitle = getString(R.string.audio_play_s)
|
||||||
|
}
|
||||||
|
val builder = NotificationCompat
|
||||||
|
.Builder(this@AudioPlayService, AppConst.channelIdReadAloud)
|
||||||
|
.setSmallIcon(R.drawable.ic_volume_up)
|
||||||
|
.setSubText(getString(R.string.audio))
|
||||||
|
.setOngoing(true)
|
||||||
|
.setContentTitle(nTitle)
|
||||||
|
.setContentText(nSubtitle)
|
||||||
|
.setContentIntent(
|
||||||
|
activityPendingIntent<AudioPlayActivity>("activity")
|
||||||
|
)
|
||||||
|
builder.setLargeIcon(cover)
|
||||||
|
if (pause) {
|
||||||
|
builder.addAction(
|
||||||
|
R.drawable.ic_play_24dp,
|
||||||
|
getString(R.string.resume),
|
||||||
|
servicePendingIntent<AudioPlayService>(IntentAction.resume)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
builder.addAction(
|
||||||
|
R.drawable.ic_pause_24dp,
|
||||||
|
getString(R.string.pause),
|
||||||
|
servicePendingIntent<AudioPlayService>(IntentAction.pause)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
builder.addAction(
|
||||||
|
R.drawable.ic_stop_black_24dp,
|
||||||
|
getString(R.string.stop),
|
||||||
|
servicePendingIntent<AudioPlayService>(IntentAction.stop)
|
||||||
|
)
|
||||||
|
builder.addAction(
|
||||||
|
R.drawable.ic_time_add_24dp,
|
||||||
|
getString(R.string.set_timer),
|
||||||
|
servicePendingIntent<AudioPlayService>(IntentAction.addTimer)
|
||||||
|
)
|
||||||
|
builder.setStyle(
|
||||||
|
androidx.media.app.NotificationCompat.MediaStyle()
|
||||||
|
.setShowActionsInCompactView(0, 1, 2)
|
||||||
|
.setMediaSession(mediaSessionCompat?.sessionToken)
|
||||||
|
)
|
||||||
|
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun upAudioPlayNotification() {
|
||||||
|
execute {
|
||||||
|
createNotification()
|
||||||
|
}.onSuccess {
|
||||||
|
notificationManager.notify(NotificationId.AudioPlayService, it.build())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新通知
|
* 更新通知
|
||||||
*/
|
*/
|
||||||
override fun upNotification() {
|
override fun startForegroundNotification() {
|
||||||
execute {
|
execute {
|
||||||
var nTitle: String = when {
|
createNotification()
|
||||||
pause -> getString(R.string.audio_pause)
|
|
||||||
timeMinute in 1..60 -> getString(
|
|
||||||
R.string.playing_timer,
|
|
||||||
timeMinute
|
|
||||||
)
|
|
||||||
|
|
||||||
else -> getString(R.string.audio_play_t)
|
|
||||||
}
|
|
||||||
nTitle += ": ${AudioPlay.book?.name}"
|
|
||||||
var nSubtitle = AudioPlay.durChapter?.title
|
|
||||||
if (nSubtitle.isNullOrEmpty()) {
|
|
||||||
nSubtitle = getString(R.string.audio_play_s)
|
|
||||||
}
|
|
||||||
val builder = NotificationCompat
|
|
||||||
.Builder(this@AudioPlayService, AppConst.channelIdReadAloud)
|
|
||||||
.setSmallIcon(R.drawable.ic_volume_up)
|
|
||||||
.setSubText(getString(R.string.audio))
|
|
||||||
.setOngoing(true)
|
|
||||||
.setContentTitle(nTitle)
|
|
||||||
.setContentText(nSubtitle)
|
|
||||||
.setContentIntent(
|
|
||||||
activityPendingIntent<AudioPlayActivity>("activity")
|
|
||||||
)
|
|
||||||
builder.setLargeIcon(cover)
|
|
||||||
if (pause) {
|
|
||||||
builder.addAction(
|
|
||||||
R.drawable.ic_play_24dp,
|
|
||||||
getString(R.string.resume),
|
|
||||||
servicePendingIntent<AudioPlayService>(IntentAction.resume)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
builder.addAction(
|
|
||||||
R.drawable.ic_pause_24dp,
|
|
||||||
getString(R.string.pause),
|
|
||||||
servicePendingIntent<AudioPlayService>(IntentAction.pause)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
builder.addAction(
|
|
||||||
R.drawable.ic_stop_black_24dp,
|
|
||||||
getString(R.string.stop),
|
|
||||||
servicePendingIntent<AudioPlayService>(IntentAction.stop)
|
|
||||||
)
|
|
||||||
builder.addAction(
|
|
||||||
R.drawable.ic_time_add_24dp,
|
|
||||||
getString(R.string.set_timer),
|
|
||||||
servicePendingIntent<AudioPlayService>(IntentAction.addTimer)
|
|
||||||
)
|
|
||||||
builder.setStyle(
|
|
||||||
androidx.media.app.NotificationCompat.MediaStyle()
|
|
||||||
.setShowActionsInCompactView(0, 1, 2)
|
|
||||||
.setMediaSession(mediaSessionCompat?.sessionToken)
|
|
||||||
)
|
|
||||||
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
|
||||||
builder
|
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
startForeground(NotificationId.AudioPlayService, it.build())
|
startForeground(NotificationId.AudioPlayService, it.build())
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,13 @@ import androidx.media.AudioFocusRequestCompat
|
|||||||
import androidx.media.AudioManagerCompat
|
import androidx.media.AudioManagerCompat
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
import io.legado.app.base.BaseService
|
import io.legado.app.base.BaseService
|
||||||
import io.legado.app.constant.*
|
import io.legado.app.constant.AppConst
|
||||||
|
import io.legado.app.constant.AppLog
|
||||||
|
import io.legado.app.constant.EventBus
|
||||||
|
import io.legado.app.constant.IntentAction
|
||||||
|
import io.legado.app.constant.NotificationId
|
||||||
|
import io.legado.app.constant.PreferKey
|
||||||
|
import io.legado.app.constant.Status
|
||||||
import io.legado.app.help.MediaHelp
|
import io.legado.app.help.MediaHelp
|
||||||
import io.legado.app.help.config.AppConfig
|
import io.legado.app.help.config.AppConfig
|
||||||
import io.legado.app.help.glide.ImageLoader
|
import io.legado.app.help.glide.ImageLoader
|
||||||
@ -30,10 +36,18 @@ import io.legado.app.model.ReadBook
|
|||||||
import io.legado.app.receiver.MediaButtonReceiver
|
import io.legado.app.receiver.MediaButtonReceiver
|
||||||
import io.legado.app.ui.book.read.ReadBookActivity
|
import io.legado.app.ui.book.read.ReadBookActivity
|
||||||
import io.legado.app.ui.book.read.page.entities.TextChapter
|
import io.legado.app.ui.book.read.page.entities.TextChapter
|
||||||
import io.legado.app.utils.*
|
import io.legado.app.utils.activityPendingIntent
|
||||||
import kotlinx.coroutines.*
|
import io.legado.app.utils.broadcastPendingIntent
|
||||||
|
import io.legado.app.utils.getPrefBoolean
|
||||||
|
import io.legado.app.utils.observeEvent
|
||||||
|
import io.legado.app.utils.postEvent
|
||||||
|
import io.legado.app.utils.toastOnUi
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
import splitties.systemservices.audioManager
|
import splitties.systemservices.audioManager
|
||||||
import splitties.systemservices.notificationManager
|
import splitties.systemservices.notificationManager
|
||||||
@ -158,7 +172,6 @@ abstract class BaseReadAloudService : BaseService(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
upNotification()
|
|
||||||
when (intent?.action) {
|
when (intent?.action) {
|
||||||
IntentAction.play -> newReadAloud(
|
IntentAction.play -> newReadAloud(
|
||||||
intent.getBooleanExtra("play", true),
|
intent.getBooleanExtra("play", true),
|
||||||
@ -516,7 +529,7 @@ abstract class BaseReadAloudService : BaseService(),
|
|||||||
/**
|
/**
|
||||||
* 更新通知
|
* 更新通知
|
||||||
*/
|
*/
|
||||||
override fun upNotification() {
|
override fun startForegroundNotification() {
|
||||||
execute {
|
execute {
|
||||||
createNotification()
|
createNotification()
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
|
@ -24,6 +24,7 @@ import kotlinx.coroutines.delay
|
|||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
|
import splitties.systemservices.notificationManager
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
@ -59,13 +60,12 @@ class CacheBookService : BaseService() {
|
|||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
isRun = true
|
isRun = true
|
||||||
CacheBook.successDownloadSet.clear()
|
CacheBook.clear()
|
||||||
CacheBook.errorDownloadMap.clear()
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
delay(1000)
|
delay(1000)
|
||||||
notificationContent = CacheBook.downloadSummary
|
notificationContent = CacheBook.downloadSummary
|
||||||
upNotification()
|
upCacheBookNotification()
|
||||||
postEvent(EventBus.UP_DOWNLOAD, "")
|
postEvent(EventBus.UP_DOWNLOAD, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,10 +90,7 @@ class CacheBookService : BaseService() {
|
|||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
isRun = false
|
isRun = false
|
||||||
cachePool.close()
|
cachePool.close()
|
||||||
CacheBook.cacheBookMap.forEach { it.value.stop() }
|
CacheBook.close()
|
||||||
CacheBook.cacheBookMap.clear()
|
|
||||||
CacheBook.successDownloadSet.clear()
|
|
||||||
CacheBook.errorDownloadMap.clear()
|
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
postEvent(EventBus.UP_DOWNLOAD, "")
|
postEvent(EventBus.UP_DOWNLOAD, "")
|
||||||
}
|
}
|
||||||
@ -134,7 +131,7 @@ class CacheBookService : BaseService() {
|
|||||||
}
|
}
|
||||||
cacheBook.addDownload(start, end2)
|
cacheBook.addDownload(start, end2)
|
||||||
notificationContent = CacheBook.downloadSummary
|
notificationContent = CacheBook.downloadSummary
|
||||||
upNotification()
|
upCacheBookNotification()
|
||||||
if (downloadJob == null) {
|
if (downloadJob == null) {
|
||||||
download()
|
download()
|
||||||
}
|
}
|
||||||
@ -175,10 +172,16 @@ class CacheBookService : BaseService() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun upCacheBookNotification() {
|
||||||
|
notificationBuilder.setContentText(notificationContent)
|
||||||
|
val notification = notificationBuilder.build()
|
||||||
|
notificationManager.notify(NotificationId.CacheBookService, notification)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新通知
|
* 更新通知
|
||||||
*/
|
*/
|
||||||
override fun upNotification() {
|
override fun startForegroundNotification() {
|
||||||
notificationBuilder.setContentText(notificationContent)
|
notificationBuilder.setContentText(notificationContent)
|
||||||
val notification = notificationBuilder.build()
|
val notification = notificationBuilder.build()
|
||||||
startForeground(NotificationId.CacheBookService, notification)
|
startForeground(NotificationId.CacheBookService, notification)
|
||||||
|
@ -72,7 +72,7 @@ class CheckSourceService : BaseService() {
|
|||||||
check(it)
|
check(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
IntentAction.resume -> upNotification()
|
IntentAction.resume -> startForegroundNotification()
|
||||||
IntentAction.stop -> stopSelf()
|
IntentAction.stop -> stopSelf()
|
||||||
}
|
}
|
||||||
return super.onStartCommand(intent, flags, startId)
|
return super.onStartCommand(intent, flags, startId)
|
||||||
@ -96,7 +96,7 @@ class CheckSourceService : BaseService() {
|
|||||||
processIndex = 0
|
processIndex = 0
|
||||||
threadCount = min(allIds.size, threadCount)
|
threadCount = min(allIds.size, threadCount)
|
||||||
notificationMsg = getString(R.string.progress_show, "", 0, allIds.size)
|
notificationMsg = getString(R.string.progress_show, "", 0, allIds.size)
|
||||||
upNotification()
|
startForegroundNotification()
|
||||||
for (i in 0 until threadCount) {
|
for (i in 0 until threadCount) {
|
||||||
check()
|
check()
|
||||||
}
|
}
|
||||||
@ -252,7 +252,7 @@ class CheckSourceService : BaseService() {
|
|||||||
checkedIds.add(sourceUrl)
|
checkedIds.add(sourceUrl)
|
||||||
notificationMsg =
|
notificationMsg =
|
||||||
getString(R.string.progress_show, sourceName, checkedIds.size, allIds.size)
|
getString(R.string.progress_show, sourceName, checkedIds.size, allIds.size)
|
||||||
upNotification()
|
startForegroundNotification()
|
||||||
if (processIndex > allIds.size + threadCount - 1) {
|
if (processIndex > allIds.size + threadCount - 1) {
|
||||||
stopSelf()
|
stopSelf()
|
||||||
}
|
}
|
||||||
@ -262,7 +262,7 @@ class CheckSourceService : BaseService() {
|
|||||||
/**
|
/**
|
||||||
* 更新通知
|
* 更新通知
|
||||||
*/
|
*/
|
||||||
override fun upNotification() {
|
override fun startForegroundNotification() {
|
||||||
notificationBuilder.setContentText(notificationMsg)
|
notificationBuilder.setContentText(notificationMsg)
|
||||||
notificationBuilder.setProgress(allIds.size, checkedIds.size, false)
|
notificationBuilder.setProgress(allIds.size, checkedIds.size, false)
|
||||||
postEvent(EventBus.CHECK_SOURCE, notificationMsg)
|
postEvent(EventBus.CHECK_SOURCE, notificationMsg)
|
||||||
|
@ -223,7 +223,7 @@ class DownloadService : BaseService() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun upNotification() {
|
override fun startForegroundNotification() {
|
||||||
val notification = NotificationCompat.Builder(this, AppConst.channelIdDownload)
|
val notification = NotificationCompat.Builder(this, AppConst.channelIdDownload)
|
||||||
.setSmallIcon(R.drawable.ic_download)
|
.setSmallIcon(R.drawable.ic_download)
|
||||||
.setSubText(getString(R.string.action_download))
|
.setSubText(getString(R.string.action_download))
|
||||||
|
@ -50,12 +50,19 @@ import io.legado.app.utils.readText
|
|||||||
import io.legado.app.utils.servicePendingIntent
|
import io.legado.app.utils.servicePendingIntent
|
||||||
import io.legado.app.utils.toastOnUi
|
import io.legado.app.utils.toastOnUi
|
||||||
import io.legado.app.utils.writeBytes
|
import io.legado.app.utils.writeBytes
|
||||||
|
import kotlinx.coroutines.CoroutineStart
|
||||||
import kotlinx.coroutines.Deferred
|
import kotlinx.coroutines.Deferred
|
||||||
|
import kotlinx.coroutines.Dispatchers.Default
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
import kotlinx.coroutines.ensureActive
|
import kotlinx.coroutines.ensureActive
|
||||||
|
import kotlinx.coroutines.flow.buffer
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.coroutines.flow.withIndex
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import me.ag2s.epublib.domain.Author
|
import me.ag2s.epublib.domain.Author
|
||||||
import me.ag2s.epublib.domain.Date
|
import me.ag2s.epublib.domain.Date
|
||||||
@ -133,7 +140,7 @@ class ExportBookService : BaseService() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
override fun upNotification() {
|
override fun startForegroundNotification() {
|
||||||
val notification = NotificationCompat.Builder(this, AppConst.channelIdDownload)
|
val notification = NotificationCompat.Builder(this, AppConst.channelIdDownload)
|
||||||
.setSmallIcon(R.drawable.ic_export)
|
.setSmallIcon(R.drawable.ic_export)
|
||||||
.setSubText(getString(R.string.export_book))
|
.setSubText(getString(R.string.export_book))
|
||||||
@ -322,15 +329,23 @@ class ExportBookService : BaseService() {
|
|||||||
}"
|
}"
|
||||||
append(qy, null)
|
append(qy, null)
|
||||||
if (AppConfig.parallelExportBook) {
|
if (AppConfig.parallelExportBook) {
|
||||||
val oc =
|
coroutineScope {
|
||||||
OrderCoroutine<Pair<String, ArrayList<SrcData>?>>(AppConfig.threadCount)
|
flow {
|
||||||
appDb.bookChapterDao.getChapterList(book.bookUrl).forEach { chapter ->
|
appDb.bookChapterDao.getChapterList(book.bookUrl).forEach { chapter ->
|
||||||
oc.submit { getExportData(book, chapter, contentProcessor, useReplace) }
|
val task = async(Default, start = CoroutineStart.LAZY) {
|
||||||
}
|
getExportData(book, chapter, contentProcessor, useReplace)
|
||||||
oc.collect { index, result ->
|
}
|
||||||
postEvent(EventBus.EXPORT_BOOK, book.bookUrl)
|
emit(task)
|
||||||
exportProgress[book.bookUrl] = index
|
}
|
||||||
append.invoke(result.first, result.second)
|
}.onEach { it.start() }
|
||||||
|
.buffer(AppConfig.threadCount)
|
||||||
|
.map { it.await() }
|
||||||
|
.withIndex()
|
||||||
|
.collect { (index, result) ->
|
||||||
|
postEvent(EventBus.EXPORT_BOOK, book.bookUrl)
|
||||||
|
exportProgress[book.bookUrl] = index
|
||||||
|
append.invoke(result.first, result.second)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
appDb.bookChapterDao.getChapterList(book.bookUrl).forEachIndexed { index, chapter ->
|
appDb.bookChapterDao.getChapterList(book.bookUrl).forEachIndexed { index, chapter ->
|
||||||
|
@ -80,11 +80,11 @@ class WebService : BaseService() {
|
|||||||
if (address == null) {
|
if (address == null) {
|
||||||
hostAddress = getString(R.string.network_connection_unavailable)
|
hostAddress = getString(R.string.network_connection_unavailable)
|
||||||
notificationContent = hostAddress
|
notificationContent = hostAddress
|
||||||
upNotification()
|
startForegroundNotification()
|
||||||
} else {
|
} else {
|
||||||
hostAddress = getString(R.string.http_ip, address.hostAddress, getPort())
|
hostAddress = getString(R.string.http_ip, address.hostAddress, getPort())
|
||||||
notificationContent = hostAddress
|
notificationContent = hostAddress
|
||||||
upNotification()
|
startForegroundNotification()
|
||||||
}
|
}
|
||||||
postEvent(EventBus.WEB_SERVICE, hostAddress)
|
postEvent(EventBus.WEB_SERVICE, hostAddress)
|
||||||
}
|
}
|
||||||
@ -142,7 +142,7 @@ class WebService : BaseService() {
|
|||||||
isRun = true
|
isRun = true
|
||||||
postEvent(EventBus.WEB_SERVICE, hostAddress)
|
postEvent(EventBus.WEB_SERVICE, hostAddress)
|
||||||
notificationContent = hostAddress
|
notificationContent = hostAddress
|
||||||
upNotification()
|
startForegroundNotification()
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
toastOnUi(e.localizedMessage ?: "")
|
toastOnUi(e.localizedMessage ?: "")
|
||||||
e.printOnDebug()
|
e.printOnDebug()
|
||||||
@ -165,7 +165,7 @@ class WebService : BaseService() {
|
|||||||
/**
|
/**
|
||||||
* 更新通知
|
* 更新通知
|
||||||
*/
|
*/
|
||||||
override fun upNotification() {
|
override fun startForegroundNotification() {
|
||||||
val builder = NotificationCompat.Builder(this, AppConst.channelIdWeb)
|
val builder = NotificationCompat.Builder(this, AppConst.channelIdWeb)
|
||||||
.setSmallIcon(R.drawable.ic_web_service_noti)
|
.setSmallIcon(R.drawable.ic_web_service_noti)
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
|
Loading…
Reference in New Issue
Block a user