diff --git a/app/src/main/java/io/legado/app/ui/about/ReadRecordActivity.kt b/app/src/main/java/io/legado/app/ui/about/ReadRecordActivity.kt index f551f3d6f..a73b7d2ba 100644 --- a/app/src/main/java/io/legado/app/ui/about/ReadRecordActivity.kt +++ b/app/src/main/java/io/legado/app/ui/about/ReadRecordActivity.kt @@ -20,12 +20,17 @@ import io.legado.app.lib.dialogs.alert import io.legado.app.lib.theme.primaryTextColor import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.ui.book.search.SearchActivity -import io.legado.app.utils.* +import io.legado.app.utils.applyTint +import io.legado.app.utils.cnCompare +import io.legado.app.utils.getInt +import io.legado.app.utils.putInt +import io.legado.app.utils.startActivity import io.legado.app.utils.viewbindingdelegate.viewBinding import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.text.SimpleDateFormat +import java.util.Locale class ReadRecordActivity : BaseActivity() { @@ -149,7 +154,7 @@ class ReadRecordActivity : BaseActivity() { inner class RecordAdapter(context: Context) : RecyclerAdapter(context) { - private val dateFormat = SimpleDateFormat("yyyy-MM-dd") + private val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()) override fun getViewBinding(parent: ViewGroup): ItemReadRecordBinding { return ItemReadRecordBinding.inflate(inflater, parent, false) diff --git a/app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkViewModel.kt b/app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkViewModel.kt index 2c7e291c4..55391327d 100644 --- a/app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/bookmark/AllBookmarkViewModel.kt @@ -1,10 +1,10 @@ package io.legado.app.ui.book.bookmark -import android.annotation.SuppressLint import android.app.Application import android.net.Uri import androidx.documentfile.provider.DocumentFile import io.legado.app.base.BaseViewModel +import io.legado.app.constant.AppLog import io.legado.app.data.appDb import io.legado.app.utils.* import java.io.File @@ -16,25 +16,32 @@ class AllBookmarkViewModel(application: Application) : BaseViewModel(application @Suppress("BlockingMethodInNonBlockingContext") - @SuppressLint("SimpleDateFormat") fun saveToFile(treeUri: Uri) { execute { - val dateFormat = SimpleDateFormat("yyMMddHHmmss") + val dateFormat = SimpleDateFormat("yyMMddHHmmss", Locale.getDefault()) + val bookmark = appDb.bookmarkDao.all if (treeUri.isContentScheme()) { val doc = DocumentFile.fromTreeUri(context, treeUri) ?.createFile("", "bookmark-${dateFormat.format(Date())}") doc?.let { context.contentResolver.openOutputStream(doc.uri)!!.use { - GSON.writeToOutputStream(it, appDb.bookmarkDao.all) + GSON.writeToOutputStream(it, bookmark) } } } else { val path = treeUri.path!! - val file = FileUtils.createFileIfNotExist(File(path), "bookmark-${dateFormat.format(Date())}") + val file = FileUtils.createFileIfNotExist( + File(path), + "bookmark-${dateFormat.format(Date())}" + ) FileOutputStream(file).use { - GSON.writeToOutputStream(it, appDb.bookmarkDao.all) + GSON.writeToOutputStream(it, bookmark) } } + }.onError { + AppLog.put("导出失败\n${it.localizedMessage}", it, true) + }.onSuccess { + context.toastOnUi("导出成功") } } diff --git a/app/src/main/java/io/legado/app/ui/book/toc/TocActivity.kt b/app/src/main/java/io/legado/app/ui/book/toc/TocActivity.kt index 259bc84f1..712f48cab 100644 --- a/app/src/main/java/io/legado/app/ui/book/toc/TocActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/toc/TocActivity.kt @@ -24,6 +24,7 @@ import io.legado.app.lib.theme.primaryTextColor import io.legado.app.model.ReadBook import io.legado.app.ui.about.AppLogDialog import io.legado.app.ui.book.toc.rule.TxtTocRuleDialog +import io.legado.app.ui.file.HandleFileContract import io.legado.app.ui.widget.dialog.WaitDialog import io.legado.app.utils.* import io.legado.app.utils.viewbindingdelegate.viewBinding @@ -41,6 +42,11 @@ class TocActivity : VMBaseActivity(), private var menu: Menu? = null private var searchView: SearchView? = null private val waitDialog by lazy { WaitDialog(this) } + private val exportDir = registerForActivityResult(HandleFileContract()) { + it.uri?.let { uri -> + viewModel.saveBookmark(uri) + } + } override fun onActivityCreated(savedInstanceState: Bundle?) { tabLayout = binding.titleBar.findViewById(R.id.tab_layout) @@ -71,9 +77,6 @@ class TocActivity : VMBaseActivity(), override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.book_toc, menu) this.menu = menu - viewModel.bookData.value?.let { - menu.setGroupVisible(R.id.menu_group_text, it.isLocalTxt) - } val search = menu.findItem(R.id.menu_search) searchView = (search.actionView as SearchView).apply { applyTint(primaryTextColor) @@ -110,6 +113,15 @@ class TocActivity : VMBaseActivity(), } override fun onMenuOpened(featureId: Int, menu: Menu): Boolean { + if (tabLayout.selectedTabPosition == 1) { + menu.setGroupVisible(R.id.menu_group_bookmark, true) + menu.setGroupVisible(R.id.menu_group_toc, false) + menu.setGroupVisible(R.id.menu_group_text, false) + } else { + menu.setGroupVisible(R.id.menu_group_bookmark, false) + menu.setGroupVisible(R.id.menu_group_toc, true) + menu.setGroupVisible(R.id.menu_group_text, viewModel.bookData.value?.isLocalTxt == true) + } menu.findItem(R.id.menu_use_replace)?.isChecked = AppConfig.tocUiUseReplace menu.findItem(R.id.menu_split_long_chapter)?.isChecked = @@ -122,6 +134,7 @@ class TocActivity : VMBaseActivity(), R.id.menu_toc_regex -> showDialogFragment( TxtTocRuleDialog(viewModel.bookData.value?.tocUrl) ) + R.id.menu_split_long_chapter -> { viewModel.bookData.value?.let { book -> item.isChecked = !item.isChecked @@ -129,6 +142,7 @@ class TocActivity : VMBaseActivity(), upBookAndToc(book) } } + R.id.menu_reverse_toc -> viewModel.reverseToc { viewModel.chapterListCallBack?.upChapterList(searchView?.query?.toString()) setResult(RESULT_OK, Intent().apply { @@ -136,11 +150,15 @@ class TocActivity : VMBaseActivity(), putExtra("chapterPos", 0) }) } + R.id.menu_use_replace -> { AppConfig.tocUiUseReplace = !item.isChecked viewModel.chapterListCallBack?.clearDisplayTitle() viewModel.chapterListCallBack?.upChapterList(searchView?.query?.toString()) } + + R.id.menu_export -> exportDir.launch() + R.id.menu_log -> showDialogFragment() } return super.onCompatOptionsItemSelected(item) diff --git a/app/src/main/java/io/legado/app/ui/book/toc/TocViewModel.kt b/app/src/main/java/io/legado/app/ui/book/toc/TocViewModel.kt index 374a13367..fe936e0e4 100644 --- a/app/src/main/java/io/legado/app/ui/book/toc/TocViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/toc/TocViewModel.kt @@ -2,11 +2,26 @@ package io.legado.app.ui.book.toc import android.app.Application +import android.net.Uri +import androidx.documentfile.provider.DocumentFile import androidx.lifecycle.MutableLiveData +import io.legado.app.R import io.legado.app.base.BaseViewModel +import io.legado.app.constant.AppLog import io.legado.app.data.appDb import io.legado.app.data.entities.Book +import io.legado.app.exception.NoStackTraceException import io.legado.app.model.localBook.LocalBook +import io.legado.app.utils.FileUtils +import io.legado.app.utils.GSON +import io.legado.app.utils.isContentScheme +import io.legado.app.utils.toastOnUi +import io.legado.app.utils.writeToOutputStream +import java.io.File +import java.io.FileOutputStream +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale class TocViewModel(application: Application) : BaseViewModel(application) { var bookUrl: String = "" @@ -63,6 +78,41 @@ class TocViewModel(application: Application) : BaseViewModel(application) { bookMarkCallBack?.upBookmark(newText) } + @Suppress("BlockingMethodInNonBlockingContext") + fun saveBookmark(treeUri: Uri) { + execute { + val book = bookData.value + ?: throw NoStackTraceException(context.getString(R.string.no_book)) + val dateFormat = SimpleDateFormat("yyMMddHHmmss", Locale.getDefault()) + val bookmark = appDb.bookmarkDao.getByBook(book.name, book.author) + if (treeUri.isContentScheme()) { + val doc = DocumentFile.fromTreeUri(context, treeUri) + ?.createFile("", "bookmark-${dateFormat.format(Date())}") + doc?.let { + context.contentResolver.openOutputStream(doc.uri)!!.use { + GSON.writeToOutputStream(it, bookmark) + } + } + } else { + val path = treeUri.path!! + val file = FileUtils.createFileIfNotExist( + File(path), "bookmark-${ + dateFormat.format( + Date() + ) + }" + ) + FileOutputStream(file).use { + GSON.writeToOutputStream(it, bookmark) + } + } + }.onError { + AppLog.put("导出失败\n${it.localizedMessage}", it, true) + }.onSuccess { + context.toastOnUi("导出成功") + } + } + interface ChapterListCallBack { fun upChapterList(searchKey: String?) diff --git a/app/src/main/java/io/legado/app/utils/StringUtils.kt b/app/src/main/java/io/legado/app/utils/StringUtils.kt index aec561c4d..de0e995f8 100644 --- a/app/src/main/java/io/legado/app/utils/StringUtils.kt +++ b/app/src/main/java/io/legado/app/utils/StringUtils.kt @@ -50,8 +50,7 @@ object StringUtils { * 将日期转换成昨天、今天、明天 */ fun dateConvert(source: String, pattern: String): String { - @SuppressLint("SimpleDateFormat") - val format = SimpleDateFormat(pattern) + val format = SimpleDateFormat(pattern, Locale.getDefault()) val calendar = Calendar.getInstance() kotlin.runCatching { val date = format.parse(source) ?: return "" diff --git a/app/src/main/res/menu/book_toc.xml b/app/src/main/res/menu/book_toc.xml index a0e42d801..24ca5de00 100644 --- a/app/src/main/res/menu/book_toc.xml +++ b/app/src/main/res/menu/book_toc.xml @@ -21,22 +21,39 @@ - + - + + + + + + + + + + +