Skip to content

Commit

Permalink
增加导出 EPUB 提示对话和通知
Browse files Browse the repository at this point in the history
  • Loading branch information
yukonisen committed Jan 13, 2025
1 parent 1e377ea commit c2e7fac
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 27 deletions.
2 changes: 1 addition & 1 deletion app/release/output-metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 10000005,
"versionCode": 10000021,
"versionName": "1.0.0",
"outputFile": "LightNovelReader-1.0.0-release.apk"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package indi.dmzz_yyhyy.lightnovelreader.data.work

import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.net.Uri
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.hilt.work.HiltWorker
import androidx.work.Worker
import androidx.work.WorkerParameters
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import indi.dmzz_yyhyy.lightnovelreader.R
import indi.dmzz_yyhyy.lightnovelreader.data.book.ChapterContent
import indi.dmzz_yyhyy.lightnovelreader.data.web.WebBookDataSource
import indi.dmzz_yyhyy.lightnovelreader.utils.ImageDownloader
Expand All @@ -23,21 +29,85 @@ class ExportBookToEPUBWork @AssistedInject constructor(
@Assisted workerParams: WorkerParameters,
private val webBookDataSource: WebBookDataSource
) : Worker(appContext, workerParams) {

private val notificationManager = appContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
private var notification: Notification? = null
val coroutineScope = CoroutineScope(Dispatchers.IO)

private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
"BookEpubExport",
"EPUB 导出进度",
NotificationManager.IMPORTANCE_LOW
)
notificationManager.createNotificationChannel(channel)
}
}

private fun showProgressNotification() {
notification = NotificationCompat.Builder(applicationContext, "BookEpubExport")
.setContentTitle("导出 ${inputData.getString("title")}")
.setContentText("处理中...")
.setSmallIcon(R.drawable.file_export_24px)
.setProgress(100, 0, true)
.setPriority(NotificationCompat.PRIORITY_LOW)
.build()

notificationManager.notify(1, notification)
}

private fun updateFailureNotification() {
notification = NotificationCompat.Builder(applicationContext, "BookEpubExport")
.setContentTitle("导出 ${inputData.getString("title")}")
.setContentText("导出失败")
.setSmallIcon(R.drawable.file_export_24px)
.setProgress(0, 0, false)
.setAutoCancel(true)
.build()

notificationManager.notify(1, notification)
}

private fun updateCompletionNotification() {
notification = NotificationCompat.Builder(applicationContext, "BookEpubExport")
.setContentTitle("导出 ${inputData.getString("title")}")
.setContentText("已完成")
.setSmallIcon(R.drawable.file_export_24px)
.setProgress(0, 0, false)
.setAutoCancel(true)
.build()

notificationManager.notify(1, notification)
}

override fun doWork(): Result {
createNotificationChannel()
showProgressNotification()

val bookId = inputData.getInt("bookId", -1)
val fileUri = inputData.getString("uri")?.let(Uri::parse) ?: return Result.failure()
val tempDir = applicationContext.cacheDir.resolve("epub").resolve(bookId.toString())
val cover = tempDir.resolve("cover.jpg")
if (bookId < 0) return Result.failure()
if (bookId < 0) {
updateFailureNotification()
return Result.failure()
}

val tasks = mutableListOf<ImageDownloader.Task>()
val epub = EpubBuilder().apply {
val bookInformation = webBookDataSource.getBookInformation(bookId) ?: return Result.failure()
val bookVolumes = webBookDataSource.getBookVolumes(bookId) ?: return Result.failure()
val bookInformation = webBookDataSource.getBookInformation(bookId) ?: return Result.failure().also {
updateFailureNotification()
}
val bookVolumes = webBookDataSource.getBookVolumes(bookId) ?: return Result.failure().also {
updateFailureNotification()
}
val bookContentMap = mutableMapOf<Int, ChapterContent>()
bookVolumes.volumes.forEach { volume ->
volume.chapters.forEach {
bookContentMap[it.id] = webBookDataSource.getChapterContent(it.id, bookId) ?: return Result.failure()
bookContentMap[it.id] = webBookDataSource.getChapterContent(it.id, bookId) ?: return Result.failure().also {
updateFailureNotification()
}
}
}
title = bookInformation.title
Expand All @@ -46,10 +116,8 @@ class ExportBookToEPUBWork @AssistedInject constructor(
description = bookInformation.description
publisher = bookInformation.publishingHouse
tasks.add(ImageDownloader.Task(cover, bookInformation.coverUrl))
if (!tempDir.exists())
tempDir.mkdirs()
else
tempDir.listFiles()?.forEach(File::delete)
if (!tempDir.exists()) tempDir.mkdirs()
else tempDir.listFiles()?.forEach(File::delete)
cover(cover)
bookVolumes.volumes.forEach { volume ->
chapter {
Expand All @@ -63,8 +131,7 @@ class ExportBookToEPUBWork @AssistedInject constructor(
val image = tempDir.resolve(singleText.hashCode().toString() + ".jpg")
tasks.add(ImageDownloader.Task(image, singleText))
image(image)
}
else {
} else {
singleText.split("\n").forEach {
text(it)
br()
Expand All @@ -77,6 +144,7 @@ class ExportBookToEPUBWork @AssistedInject constructor(
}
}
}

val imageDownloader = ImageDownloader(
tasks = tasks,
coroutineScope = coroutineScope,
Expand All @@ -86,6 +154,7 @@ class ExportBookToEPUBWork @AssistedInject constructor(
applicationContext.contentResolver.openOutputStream(fileUri).use {
it?.write(file.readBytes())
}
updateCompletionNotification()
tempDir.delete()
}
)
Expand All @@ -98,4 +167,4 @@ class ExportBookToEPUBWork @AssistedInject constructor(
super.onStopped()
coroutineScope.cancel()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Badge
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
Expand All @@ -43,6 +42,7 @@ import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
Expand All @@ -68,6 +68,7 @@ import indi.dmzz_yyhyy.lightnovelreader.R
import indi.dmzz_yyhyy.lightnovelreader.data.book.BookInformation
import indi.dmzz_yyhyy.lightnovelreader.data.book.Volume
import indi.dmzz_yyhyy.lightnovelreader.ui.components.Cover
import indi.dmzz_yyhyy.lightnovelreader.ui.components.ExportToEpubDialog
import indi.dmzz_yyhyy.lightnovelreader.ui.components.Loading
import indi.dmzz_yyhyy.lightnovelreader.ui.home.bookshelf.home.BookStatusIcon
import indi.dmzz_yyhyy.lightnovelreader.ui.home.settings.list.launcher
Expand Down Expand Up @@ -140,11 +141,13 @@ private fun Content(
val context = LocalContext.current
val scope = rememberCoroutineScope()
val uiState = viewModel.uiState
var showExportEpubDialog by remember { mutableStateOf(false) }

@Suppress("SENSELESS_COMPARISON")
val exportToEPUBLauncher = launcher {
scope.launch {
Toast.makeText(context, "开始导出书本 ${viewModel.uiState.bookInformation.title}", Toast.LENGTH_SHORT).show()
viewModel.exportToEpub(it, id).collect {
viewModel.exportToEpub(it, id, uiState.bookInformation.title).collect {
if (it != null)
when (it.state) {
WorkInfo.State.SUCCEEDED -> {
Expand All @@ -158,10 +161,19 @@ private fun Content(
}
}
}
if (showExportEpubDialog) {
ExportToEpubDialog (
onDismissRequest = { showExportEpubDialog = false },
onConfirmation = {
showExportEpubDialog = false
createDataFile(viewModel.uiState.bookInformation.title, exportToEPUBLauncher)
}
)
}
topBar {
TopBar(
onClickBackButton = onClickBackButton,
onClickExport = { createDataFile(viewModel.uiState.bookInformation.title, exportToEPUBLauncher) },
onClickExport = { showExportEpubDialog = true },
scrollBehavior = it
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package indi.dmzz_yyhyy.lightnovelreader.ui.book.detail

import android.icu.text.CaseMap.Title
import android.net.Uri
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
Expand Down Expand Up @@ -51,12 +52,13 @@ class DetailViewModel @Inject constructor(
}
}

fun exportToEpub(uri: Uri, bookId: Int): Flow<WorkInfo> {
fun exportToEpub(uri: Uri, bookId: Int, title: String): Flow<WorkInfo> {
val workRequest = OneTimeWorkRequestBuilder<ExportBookToEPUBWork>()
.setInputData(
workDataOf(
"bookId" to bookId,
"uri" to uri.toString(),
"title" to title
)
)
.build()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ class MutableExportContext: ExportContext {
}

@Composable
fun ExportDialog(
fun ExportUserDataDialog(
onDismissRequest: () -> Unit,
onClickSaveAndSend: (ExportContext) -> Unit,
onClickSaveToFile: (ExportContext) -> Unit
Expand Down Expand Up @@ -700,4 +700,33 @@ fun SettingsAboutInfoDialog(
},
confirmButton = {},
)
}

@Composable
fun ExportToEpubDialog(
onDismissRequest: () -> Unit,
onConfirmation: () -> Unit,
) {
AlertDialog (
onDismissRequest = onDismissRequest,
title = { Text("导出为 EPUB") },
text = {
Text("EPUB (Electronic Publication) 是一种开放的电子书标准,格式为 .epub。\n\n"+
"要将这本书导出为 EPUB 吗?")
},
confirmButton = {
TextButton(
onClick = onConfirmation
) {
Text(stringResource(android.R.string.ok))
}
},
dismissButton = {
TextButton(
onClick = onDismissRequest
) {
Text(stringResource(R.string.cancel))
}
}
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -353,18 +353,13 @@ private fun ReadingHeaderCard(
fontSize = 19.sp,
lineHeight = titleLineHeight,
)
Text(
text = "章节:",
color = MaterialTheme.colorScheme.secondary,
fontSize = 14.sp,
lineHeight = 16.sp
)
Text(
text = book.lastReadChapterTitle,
maxLines = 1,
fontSize = 15.sp,
fontSize = 14.sp,
color = MaterialTheme.colorScheme.primary,
overflow = TextOverflow.Ellipsis
overflow = TextOverflow.Ellipsis,
fontWeight = FontWeight.Bold
)
Spacer(modifier = Modifier.height(2.dp))
Row(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import androidx.work.WorkInfo
import androidx.work.WorkManager
import indi.dmzz_yyhyy.lightnovelreader.R
import indi.dmzz_yyhyy.lightnovelreader.ui.components.ExportContext
import indi.dmzz_yyhyy.lightnovelreader.ui.components.ExportDialog
import indi.dmzz_yyhyy.lightnovelreader.ui.components.ExportUserDataDialog
import indi.dmzz_yyhyy.lightnovelreader.ui.components.MutableExportContext
import indi.dmzz_yyhyy.lightnovelreader.ui.components.SettingsClickableEntry
import indi.dmzz_yyhyy.lightnovelreader.ui.components.SourceChangeDialog
Expand Down Expand Up @@ -97,7 +97,7 @@ fun DataSettingsList(
)
}
if (displayExportDialog) {
ExportDialog(
ExportUserDataDialog(
onDismissRequest = { displayExportDialog = false },
onClickSaveAndSend = {
displayExportDialog = false
Expand Down

0 comments on commit c2e7fac

Please sign in to comment.