[修复] 修复一些问题
This commit is contained in:
@@ -16,13 +16,11 @@ import android.graphics.drawable.TransitionDrawable
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.method.ScrollingMovementMethod
|
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.CheckBox
|
import android.widget.CheckBox
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.activity.OnBackPressedCallback
|
|
||||||
import androidx.activity.addCallback
|
import androidx.activity.addCallback
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
@@ -54,7 +52,6 @@ import io.legado.app.help.book.isAudio
|
|||||||
import io.legado.app.help.book.isImage
|
import io.legado.app.help.book.isImage
|
||||||
import io.legado.app.help.book.isLocal
|
import io.legado.app.help.book.isLocal
|
||||||
import io.legado.app.help.book.isLocalTxt
|
import io.legado.app.help.book.isLocalTxt
|
||||||
import io.legado.app.help.book.isNotShelf
|
|
||||||
import io.legado.app.help.book.isWebFile
|
import io.legado.app.help.book.isWebFile
|
||||||
import io.legado.app.help.book.removeType
|
import io.legado.app.help.book.removeType
|
||||||
import io.legado.app.help.config.AppConfig
|
import io.legado.app.help.config.AppConfig
|
||||||
@@ -62,7 +59,6 @@ import io.legado.app.help.config.LocalConfig
|
|||||||
import io.legado.app.lib.dialogs.alert
|
import io.legado.app.lib.dialogs.alert
|
||||||
import io.legado.app.lib.dialogs.selector
|
import io.legado.app.lib.dialogs.selector
|
||||||
import io.legado.app.model.BookCover
|
import io.legado.app.model.BookCover
|
||||||
import io.legado.app.model.ReadBook
|
|
||||||
import io.legado.app.model.remote.RemoteBookWebDav
|
import io.legado.app.model.remote.RemoteBookWebDav
|
||||||
import io.legado.app.ui.about.AppLogDialog
|
import io.legado.app.ui.about.AppLogDialog
|
||||||
import io.legado.app.ui.book.audio.AudioPlayActivity
|
import io.legado.app.ui.book.audio.AudioPlayActivity
|
||||||
@@ -158,7 +154,6 @@ class BookInfoActivity :
|
|||||||
viewModel.refreshBook(book)
|
viewModel.refreshBook(book)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private lateinit var backCallback: OnBackPressedCallback
|
|
||||||
private var surfaceFinalColor: Int = 0
|
private var surfaceFinalColor: Int = 0
|
||||||
private var surfaceContainerFinalColor: Int = 0
|
private var surfaceContainerFinalColor: Int = 0
|
||||||
private var secondaryFinalColor: Int = 0
|
private var secondaryFinalColor: Int = 0
|
||||||
@@ -178,7 +173,6 @@ class BookInfoActivity :
|
|||||||
|
|
||||||
@SuppressLint("PrivateResource")
|
@SuppressLint("PrivateResource")
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
postponeEnterTransition()
|
|
||||||
setEnterSharedElementCallback(MaterialContainerTransformSharedElementCallback())
|
setEnterSharedElementCallback(MaterialContainerTransformSharedElementCallback())
|
||||||
setExitSharedElementCallback(MaterialContainerTransformSharedElementCallback())
|
setExitSharedElementCallback(MaterialContainerTransformSharedElementCallback())
|
||||||
val transform = MaterialContainerTransform().apply {
|
val transform = MaterialContainerTransform().apply {
|
||||||
@@ -187,7 +181,6 @@ class BookInfoActivity :
|
|||||||
}
|
}
|
||||||
window.sharedElementEnterTransition = transform
|
window.sharedElementEnterTransition = transform
|
||||||
window.sharedElementReturnTransition = transform
|
window.sharedElementReturnTransition = transform
|
||||||
window.sharedElementsUseOverlay = false
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setupBackCallback()
|
setupBackCallback()
|
||||||
surfaceFinalColor =
|
surfaceFinalColor =
|
||||||
@@ -389,7 +382,7 @@ class BookInfoActivity :
|
|||||||
|
|
||||||
private fun setupBackCallback() {
|
private fun setupBackCallback() {
|
||||||
onBackPressedDispatcher.addCallback(this) {
|
onBackPressedDispatcher.addCallback(this) {
|
||||||
if (!viewModel.inBookshelf) {
|
if (!viewModel.inBookshelf && AppConfig.showAddToShelfAlert) {
|
||||||
viewModel.getBook()?.let { book ->
|
viewModel.getBook()?.let { book ->
|
||||||
alert(title = getString(R.string.add_to_bookshelf)) {
|
alert(title = getString(R.string.add_to_bookshelf)) {
|
||||||
setMessage(getString(R.string.check_add_bookshelf, book.name))
|
setMessage(getString(R.string.check_add_bookshelf, book.name))
|
||||||
@@ -442,7 +435,7 @@ class BookInfoActivity :
|
|||||||
addColorScheme(binding.ivCover.drawable)
|
addColorScheme(binding.ivCover.drawable)
|
||||||
tvName.text = book.name
|
tvName.text = book.name
|
||||||
tvRemark.text = book.remark
|
tvRemark.text = book.remark
|
||||||
if (book.remark == null)
|
if (book.remark.isNullOrEmpty())
|
||||||
cdRemark.gone()
|
cdRemark.gone()
|
||||||
else
|
else
|
||||||
cdRemark.visible()
|
cdRemark.visible()
|
||||||
|
|||||||
@@ -19,7 +19,12 @@ class BookInfoEditActivity : BaseComposeActivity(), ChangeCoverDialog.CallBack {
|
|||||||
BookInfoEditScreen(
|
BookInfoEditScreen(
|
||||||
viewModel = viewModel,
|
viewModel = viewModel,
|
||||||
onBack = { finish() },
|
onBack = { finish() },
|
||||||
onSave = ::saveData
|
onSave = {
|
||||||
|
viewModel.save {
|
||||||
|
setResult(RESULT_OK)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,16 +37,9 @@ class BookInfoEditActivity : BaseComposeActivity(), ChangeCoverDialog.CallBack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun saveData() {
|
|
||||||
viewModel.saveBook {
|
|
||||||
setResult(RESULT_OK)
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun coverChangeTo(coverUrl: String) {
|
override fun coverChangeTo(coverUrl: String) {
|
||||||
// 更新封面 URL
|
// 更新封面 URL
|
||||||
viewModel.updateCoverUrl(coverUrl)
|
viewModel.onCoverUrlChange(coverUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -13,6 +13,8 @@ import androidx.compose.foundation.rememberScrollState
|
|||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
|
import androidx.compose.material.icons.filled.FolderOpen
|
||||||
|
import androidx.compose.material.icons.filled.ImageSearch
|
||||||
import androidx.compose.material.icons.filled.Replay
|
import androidx.compose.material.icons.filled.Replay
|
||||||
import androidx.compose.material.icons.filled.Save
|
import androidx.compose.material.icons.filled.Save
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
@@ -21,16 +23,16 @@ import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
|||||||
import androidx.compose.material3.ExposedDropdownMenuAnchorType
|
import androidx.compose.material3.ExposedDropdownMenuAnchorType
|
||||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||||
import androidx.compose.material3.ExposedDropdownMenuDefaults
|
import androidx.compose.material3.ExposedDropdownMenuDefaults
|
||||||
import androidx.compose.material3.FilledTonalButton
|
import androidx.compose.material3.FilledTonalIconButton
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.IconButtonDefaults
|
||||||
import androidx.compose.material3.MediumTopAppBar
|
import androidx.compose.material3.MediumTopAppBar
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
@@ -43,9 +45,6 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import io.legado.app.R
|
import io.legado.app.R
|
||||||
import io.legado.app.data.entities.Book
|
|
||||||
import io.legado.app.help.book.isAudio
|
|
||||||
import io.legado.app.help.book.isImage
|
|
||||||
import io.legado.app.ui.book.changecover.ChangeCoverDialog
|
import io.legado.app.ui.book.changecover.ChangeCoverDialog
|
||||||
import io.legado.app.ui.widget.components.Cover
|
import io.legado.app.ui.widget.components.Cover
|
||||||
import io.legado.app.utils.SelectImageContract
|
import io.legado.app.utils.SelectImageContract
|
||||||
@@ -59,7 +58,7 @@ fun BookInfoEditScreen(
|
|||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
onSave: () -> Unit
|
onSave: () -> Unit
|
||||||
) {
|
) {
|
||||||
val book by viewModel.bookData.collectAsStateWithLifecycle()
|
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
||||||
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
@@ -76,7 +75,9 @@ fun BookInfoEditScreen(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions = {
|
actions = {
|
||||||
FilledTonalButton(onClick = onSave) {
|
FilledTonalIconButton(
|
||||||
|
onClick = { viewModel.save(onSave) },
|
||||||
|
shapes = IconButtonDefaults.shapes()) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Save,
|
imageVector = Icons.Default.Save,
|
||||||
contentDescription = stringResource(id = R.string.action_save)
|
contentDescription = stringResource(id = R.string.action_save)
|
||||||
@@ -87,13 +88,13 @@ fun BookInfoEditScreen(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
content = { paddingValues ->
|
content = { paddingValues ->
|
||||||
book?.let {
|
uiState.book?.let {
|
||||||
BookInfoEditContent(
|
BookInfoEditContent(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(paddingValues)
|
.padding(paddingValues)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.verticalScroll(rememberScrollState()),
|
.verticalScroll(rememberScrollState()),
|
||||||
book = it,
|
uiState = uiState,
|
||||||
viewModel = viewModel
|
viewModel = viewModel
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -101,59 +102,56 @@ fun BookInfoEditScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun BookInfoEditContent(
|
fun BookInfoEditContent(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
book: Book,
|
uiState: BookInfoEditUiState,
|
||||||
viewModel: BookInfoEditViewModel
|
viewModel: BookInfoEditViewModel
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
var name by remember(book.name) { mutableStateOf(book.name) }
|
|
||||||
var author by remember(book.author) { mutableStateOf(book.author) }
|
|
||||||
var coverUrl by remember(book.customCoverUrl) { mutableStateOf(book.getDisplayCover()) }
|
|
||||||
var intro by remember(book.customIntro) { mutableStateOf(book.getDisplayIntro()) }
|
|
||||||
var remark by remember(book.remark) { mutableStateOf(book.remark) }
|
|
||||||
|
|
||||||
val bookTypes = arrayOf("文本", "音频", "图片")
|
|
||||||
val selectedTypeIndex = when {
|
|
||||||
book.isImage -> 2
|
|
||||||
book.isAudio -> 1
|
|
||||||
else -> 0
|
|
||||||
}
|
|
||||||
var selectedType by remember { mutableStateOf(bookTypes[selectedTypeIndex]) }
|
|
||||||
|
|
||||||
val selectCover = rememberLauncherForActivityResult(SelectImageContract()) {
|
val selectCover = rememberLauncherForActivityResult(SelectImageContract()) {
|
||||||
it.uri?.let { uri ->
|
it.uri?.let { uri ->
|
||||||
viewModel.coverChangeTo(context, uri) { newCoverUrl ->
|
viewModel.coverChangeTo(context, uri)
|
||||||
coverUrl = newCoverUrl
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
LaunchedEffect(coverUrl) {
|
|
||||||
viewModel.book?.customCoverUrl = coverUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier.padding(16.dp),
|
modifier = modifier.padding(16.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
Cover(
|
Cover(
|
||||||
path = coverUrl,
|
path = uiState.coverUrl,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth(0.3f)
|
.fillMaxWidth(0.3f)
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||||
FilledTonalButton(onClick = {
|
FilledTonalIconButton(
|
||||||
(context as? BookInfoEditActivity)?.showDialogFragment(ChangeCoverDialog(book.name, book.author))
|
onClick = {
|
||||||
}) {
|
(context as? BookInfoEditActivity)?.showDialogFragment(
|
||||||
Text("网络搜索")
|
ChangeCoverDialog(
|
||||||
|
uiState.name,
|
||||||
|
uiState.author
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
shapes = IconButtonDefaults.shapes()) {
|
||||||
|
Icon(
|
||||||
|
Icons.Default.ImageSearch,
|
||||||
|
contentDescription = stringResource(id = R.string.default_cover)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
FilledTonalButton(onClick = { selectCover.launch() }) {
|
FilledTonalIconButton(onClick = { selectCover.launch() },
|
||||||
Text("本地选择")
|
shapes = IconButtonDefaults.shapes()) {
|
||||||
|
Icon(
|
||||||
|
Icons.Default.FolderOpen,
|
||||||
|
contentDescription = stringResource(id = R.string.default_cover)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
FilledTonalButton(onClick = { coverUrl = book.coverUrl ?: "" }) {
|
FilledTonalIconButton(onClick = { viewModel.resetCover() },
|
||||||
|
shapes = IconButtonDefaults.shapes()) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Default.Replay,
|
Icons.Default.Replay,
|
||||||
contentDescription = stringResource(id = R.string.default_cover)
|
contentDescription = stringResource(id = R.string.default_cover)
|
||||||
@@ -162,57 +160,53 @@ fun BookInfoEditContent(
|
|||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = name,
|
value = uiState.name,
|
||||||
onValueChange = { name = it },
|
onValueChange = { viewModel.onNameChange(it) },
|
||||||
label = { Text("书名") },
|
label = { Text("书名") },
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = author,
|
value = uiState.author,
|
||||||
onValueChange = { author = it },
|
onValueChange = { viewModel.onAuthorChange(it) },
|
||||||
label = { Text("作者") },
|
label = { Text("作者") },
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
BookTypeDropdown(
|
BookTypeDropdown(
|
||||||
bookTypes = bookTypes,
|
bookTypes = uiState.bookTypes,
|
||||||
selectedType = selectedType,
|
selectedType = uiState.selectedType,
|
||||||
onTypeSelected = { selectedType = it }
|
onTypeSelected = { viewModel.onBookTypeChange(it) }
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = coverUrl ?: "",
|
value = uiState.coverUrl ?: "",
|
||||||
onValueChange = { coverUrl = it },
|
onValueChange = { viewModel.onCoverUrlChange(it) },
|
||||||
label = { Text("封面链接") },
|
label = { Text("封面链接") },
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = intro ?: "",
|
value = uiState.intro ?: "",
|
||||||
onValueChange = { intro = it },
|
onValueChange = { viewModel.onIntroChange(it) },
|
||||||
label = { Text("简介") },
|
label = { Text("简介") },
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
maxLines = 5
|
maxLines = 5
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = remark ?: "",
|
value = uiState.remark ?: "",
|
||||||
onValueChange = { remark = it },
|
onValueChange = { viewModel.onRemarkChange(it) },
|
||||||
label = { Text("备注") },
|
label = { Text("备注") },
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(name, author, selectedType, coverUrl, intro, remark) {
|
|
||||||
viewModel.updateBookState(name, author, selectedType, bookTypes, coverUrl, intro, remark)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun BookTypeDropdown(
|
fun BookTypeDropdown(
|
||||||
bookTypes: Array<String>,
|
bookTypes: List<String>,
|
||||||
selectedType: String,
|
selectedType: String,
|
||||||
onTypeSelected: (String) -> Unit
|
onTypeSelected: (String) -> Unit
|
||||||
) {
|
) {
|
||||||
@@ -223,7 +217,9 @@ fun BookTypeDropdown(
|
|||||||
onExpandedChange = { expanded = !expanded }
|
onExpandedChange = { expanded = !expanded }
|
||||||
) {
|
) {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
modifier = Modifier.fillMaxWidth().menuAnchor(
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.menuAnchor(
|
||||||
ExposedDropdownMenuAnchorType.PrimaryEditable,
|
ExposedDropdownMenuAnchorType.PrimaryEditable,
|
||||||
true
|
true
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import io.legado.app.data.appDb
|
|||||||
import io.legado.app.data.entities.Book
|
import io.legado.app.data.entities.Book
|
||||||
import io.legado.app.help.book.BookHelp
|
import io.legado.app.help.book.BookHelp
|
||||||
import io.legado.app.help.book.addType
|
import io.legado.app.help.book.addType
|
||||||
|
import io.legado.app.help.book.isAudio
|
||||||
|
import io.legado.app.help.book.isImage
|
||||||
import io.legado.app.help.book.isLocal
|
import io.legado.app.help.book.isLocal
|
||||||
import io.legado.app.help.book.removeType
|
import io.legado.app.help.book.removeType
|
||||||
import io.legado.app.model.ReadBook
|
import io.legado.app.model.ReadBook
|
||||||
@@ -23,30 +25,99 @@ import kotlinx.coroutines.flow.asStateFlow
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
|
|
||||||
|
data class BookInfoEditUiState(
|
||||||
|
val name: String = "",
|
||||||
|
val author: String = "",
|
||||||
|
val coverUrl: String? = null,
|
||||||
|
val intro: String? = null,
|
||||||
|
val remark: String? = null,
|
||||||
|
val selectedType: String = "文本",
|
||||||
|
val bookTypes: List<String> = listOf("文本", "音频", "图片"),
|
||||||
|
val book: Book? = null,
|
||||||
|
)
|
||||||
|
|
||||||
class BookInfoEditViewModel(application: Application) : BaseViewModel(application) {
|
class BookInfoEditViewModel(application: Application) : BaseViewModel(application) {
|
||||||
var book: Book? = null
|
var book: Book? = null
|
||||||
private val _bookData = MutableStateFlow<Book?>(null)
|
private val _uiState = MutableStateFlow(BookInfoEditUiState())
|
||||||
val bookData: StateFlow<Book?> = _bookData.asStateFlow()
|
val uiState: StateFlow<BookInfoEditUiState> = _uiState.asStateFlow()
|
||||||
|
|
||||||
fun loadBook(bookUrl: String) {
|
fun loadBook(bookUrl: String) {
|
||||||
execute {
|
execute {
|
||||||
book = appDb.bookDao.getBook(bookUrl)
|
book = appDb.bookDao.getBook(bookUrl)
|
||||||
book?.let {
|
book?.let {
|
||||||
_bookData.value = it
|
val selectedTypeIndex = when {
|
||||||
|
it.isImage -> 2
|
||||||
|
it.isAudio -> 1
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
_uiState.value = BookInfoEditUiState(
|
||||||
|
name = it.name,
|
||||||
|
author = it.author,
|
||||||
|
coverUrl = it.getDisplayCover(),
|
||||||
|
intro = it.getDisplayIntro(),
|
||||||
|
remark = it.remark,
|
||||||
|
selectedType = _uiState.value.bookTypes[selectedTypeIndex],
|
||||||
|
book = it
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveBook(success: (() -> Unit)?) {
|
fun onNameChange(name: String) {
|
||||||
|
_uiState.value = _uiState.value.copy(name = name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onAuthorChange(author: String) {
|
||||||
|
_uiState.value = _uiState.value.copy(author = author)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onCoverUrlChange(coverUrl: String) {
|
||||||
|
_uiState.value = _uiState.value.copy(coverUrl = coverUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onIntroChange(intro: String) {
|
||||||
|
_uiState.value = _uiState.value.copy(intro = intro)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onRemarkChange(remark: String) {
|
||||||
|
_uiState.value = _uiState.value.copy(remark = remark)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onBookTypeChange(bookType: String) {
|
||||||
|
_uiState.value = _uiState.value.copy(selectedType = bookType)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resetCover() {
|
||||||
|
_uiState.value = _uiState.value.copy(coverUrl = book?.coverUrl ?: "")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun save(onSuccess: () -> Unit) {
|
||||||
execute {
|
execute {
|
||||||
|
val currentState = _uiState.value
|
||||||
book?.let { book ->
|
book?.let { book ->
|
||||||
|
val oldBook = book.copy()
|
||||||
|
book.name = currentState.name
|
||||||
|
book.author = currentState.author
|
||||||
|
book.remark = currentState.remark
|
||||||
|
val local = if (book.isLocal) BookType.local else 0
|
||||||
|
val bookType = when (currentState.selectedType) {
|
||||||
|
currentState.bookTypes[2] -> BookType.image or local
|
||||||
|
currentState.bookTypes[1] -> BookType.audio or local
|
||||||
|
else -> BookType.text or local
|
||||||
|
}
|
||||||
|
book.removeType(BookType.local, BookType.image, BookType.audio, BookType.text)
|
||||||
|
book.addType(bookType)
|
||||||
|
book.customCoverUrl = if (currentState.coverUrl == book.coverUrl) null else currentState.coverUrl
|
||||||
|
book.customIntro = if (currentState.intro == book.intro) null else currentState.intro
|
||||||
|
BookHelp.updateCacheFolder(oldBook, book)
|
||||||
|
|
||||||
if (ReadBook.book?.bookUrl == book.bookUrl) {
|
if (ReadBook.book?.bookUrl == book.bookUrl) {
|
||||||
ReadBook.book = book
|
ReadBook.book = book
|
||||||
}
|
}
|
||||||
appDb.bookDao.update(book)
|
appDb.bookDao.update(book)
|
||||||
}
|
}
|
||||||
}.onSuccess {
|
}.onSuccess {
|
||||||
success?.invoke()
|
onSuccess.invoke()
|
||||||
}.onError {
|
}.onError {
|
||||||
if (it is SQLiteConstraintException) {
|
if (it is SQLiteConstraintException) {
|
||||||
AppLog.put("书籍信息保存失败,存在相同书名作者书籍\n$it", it, true)
|
AppLog.put("书籍信息保存失败,存在相同书名作者书籍\n$it", it, true)
|
||||||
@@ -56,35 +127,7 @@ class BookInfoEditViewModel(application: Application) : BaseViewModel(applicatio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateBookState(
|
fun coverChangeTo(context: Context, uri: Uri) {
|
||||||
name: String,
|
|
||||||
author: String,
|
|
||||||
selectedType: String,
|
|
||||||
bookTypes: Array<String>,
|
|
||||||
coverUrl: String?,
|
|
||||||
intro: String?,
|
|
||||||
remark: String?
|
|
||||||
) {
|
|
||||||
book?.let { book ->
|
|
||||||
val oldBook = book.copy()
|
|
||||||
book.name = name
|
|
||||||
book.author = author
|
|
||||||
book.remark = remark
|
|
||||||
val local = if (book.isLocal) BookType.local else 0
|
|
||||||
val bookType = when (selectedType) {
|
|
||||||
bookTypes[2] -> BookType.image or local
|
|
||||||
bookTypes[1] -> BookType.audio or local
|
|
||||||
else -> BookType.text or local
|
|
||||||
}
|
|
||||||
book.removeType(BookType.local, BookType.image, BookType.audio, BookType.text)
|
|
||||||
book.addType(bookType)
|
|
||||||
book.customCoverUrl = if (coverUrl == book.coverUrl) null else coverUrl
|
|
||||||
book.customIntro = if (intro == book.intro) null else intro
|
|
||||||
BookHelp.updateCacheFolder(oldBook, book)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun coverChangeTo(context: Context, uri: Uri, onFinally: (coverUrl: String) -> Unit) {
|
|
||||||
execute {
|
execute {
|
||||||
runCatching {
|
runCatching {
|
||||||
context.externalCacheDir?.let { externalCacheDir ->
|
context.externalCacheDir?.let { externalCacheDir ->
|
||||||
@@ -97,7 +140,7 @@ class BookInfoEditViewModel(application: Application) : BaseViewModel(applicatio
|
|||||||
inputStream.copyTo(outputStream)
|
inputStream.copyTo(outputStream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onFinally(coverFile.absolutePath)
|
_uiState.value = _uiState.value.copy(coverUrl = coverFile.absolutePath)
|
||||||
} ?: run {
|
} ?: run {
|
||||||
AppLog.put("External cache directory is null", Throwable("Null directory"), true)
|
AppLog.put("External cache directory is null", Throwable("Null directory"), true)
|
||||||
}
|
}
|
||||||
@@ -106,13 +149,4 @@ class BookInfoEditViewModel(application: Application) : BaseViewModel(applicatio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun updateCoverUrl(coverUrl: String) {
|
|
||||||
book?.let {
|
|
||||||
val updatedBook = it.copy(customCoverUrl = coverUrl)
|
|
||||||
_bookData.value = updatedBook
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -286,8 +286,6 @@ class ReadBookActivity : BaseReadBookActivity(),
|
|||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
|
||||||
|
|
||||||
setEnterSharedElementCallback(MaterialContainerTransformSharedElementCallback())
|
setEnterSharedElementCallback(MaterialContainerTransformSharedElementCallback())
|
||||||
setExitSharedElementCallback(MaterialContainerTransformSharedElementCallback())
|
setExitSharedElementCallback(MaterialContainerTransformSharedElementCallback())
|
||||||
val transform = MaterialContainerTransform().apply {
|
val transform = MaterialContainerTransform().apply {
|
||||||
|
|||||||
@@ -41,8 +41,7 @@ markdownCompose = "0.5.0"
|
|||||||
markwon = "4.6.2"
|
markwon = "4.6.2"
|
||||||
material = "1.14.0-alpha08"
|
material = "1.14.0-alpha08"
|
||||||
material3 = "1.5.0-alpha11"
|
material3 = "1.5.0-alpha11"
|
||||||
material3IconsExtended = "1.2.0"
|
material3IconsExtended = "1.7.8"
|
||||||
materialIconsExtended = "1.7.8"
|
|
||||||
media = "1.7.1"
|
media = "1.7.1"
|
||||||
media3 = "1.8.0"
|
media3 = "1.8.0"
|
||||||
nanoHttpd = "2.3.1"
|
nanoHttpd = "2.3.1"
|
||||||
@@ -90,9 +89,8 @@ androidx-compose-animation = { module = "androidx.compose.animation:animation",
|
|||||||
androidx-compose-bom = { module = "androidx.compose:compose-bom", version.ref = "composeBom" }
|
androidx-compose-bom = { module = "androidx.compose:compose-bom", version.ref = "composeBom" }
|
||||||
androidx-compose-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "foundation" }
|
androidx-compose-foundation = { module = "androidx.compose.foundation:foundation", version.ref = "foundation" }
|
||||||
androidx-compose-material = { module = "androidx.compose.material:material" }
|
androidx-compose-material = { module = "androidx.compose.material:material" }
|
||||||
compose-materialIcons = { group = "androidx.compose.material", name = "material-icons-extended", version = "1.7.8" }
|
compose-materialIcons = { group = "androidx.compose.material", name = "material-icons-extended", version.ref = "material3IconsExtended" }
|
||||||
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" }
|
androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "material3" }
|
||||||
androidx-compose-material3-icons-extended = { module = "androidx.compose.material3:material3-icons-extended", version.ref = "material3IconsExtended" }
|
|
||||||
androidx-compose-ui = { module = "androidx.compose.ui:ui" }
|
androidx-compose-ui = { module = "androidx.compose.ui:ui" }
|
||||||
androidx-compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
|
androidx-compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
|
||||||
androidx-compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" }
|
androidx-compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" }
|
||||||
|
|||||||
Reference in New Issue
Block a user