From 8b0d369a944930a879bb1c204499560b0aec2730 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Dec 2019 21:41:40 +0800 Subject: [PATCH 01/85] up --- .../io/legado/app/service/AudioPlayService.kt | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/AudioPlayService.kt b/app/src/main/java/io/legado/app/service/AudioPlayService.kt index 2cedf7542..cf7815d03 100644 --- a/app/src/main/java/io/legado/app/service/AudioPlayService.kt +++ b/app/src/main/java/io/legado/app/service/AudioPlayService.kt @@ -157,6 +157,7 @@ class AudioPlayService : BaseService(), } private fun adjustProgress(position: Int) { + if (isM3U8()) return if (mediaPlayer.isPlaying) { mediaPlayer.seekTo(position) } else { @@ -177,21 +178,25 @@ class AudioPlayService : BaseService(), } } + private fun isM3U8(): Boolean { + return url.endsWith("m3u8") + } + /** * 加载完成 */ override fun onPrepared(mp: MediaPlayer?) { if (pause) return - mp?.let { - mp.start() - mp.seekTo(position) - postEvent(Bus.AUDIO_SIZE, mp.duration) - bookChapter?.let { - it.end = mp.duration.toLong() - } - handler.removeCallbacks(mpRunnable) - handler.post(mpRunnable) + mediaPlayer.start() + if (!isM3U8()) { + mediaPlayer.seekTo(position) + } + postEvent(Bus.AUDIO_SIZE, mediaPlayer.duration) + bookChapter?.let { + it.end = mediaPlayer.duration.toLong() } + handler.removeCallbacks(mpRunnable) + handler.post(mpRunnable) } /** From a4af037e50a7006797359ba1c249601355e28863 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Dec 2019 21:56:06 +0800 Subject: [PATCH 02/85] up --- .../io/legado/app/service/AudioPlayService.kt | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/AudioPlayService.kt b/app/src/main/java/io/legado/app/service/AudioPlayService.kt index cf7815d03..0a3c24e35 100644 --- a/app/src/main/java/io/legado/app/service/AudioPlayService.kt +++ b/app/src/main/java/io/legado/app/service/AudioPlayService.kt @@ -157,7 +157,6 @@ class AudioPlayService : BaseService(), } private fun adjustProgress(position: Int) { - if (isM3U8()) return if (mediaPlayer.isPlaying) { mediaPlayer.seekTo(position) } else { @@ -178,19 +177,13 @@ class AudioPlayService : BaseService(), } } - private fun isM3U8(): Boolean { - return url.endsWith("m3u8") - } - /** * 加载完成 */ override fun onPrepared(mp: MediaPlayer?) { if (pause) return mediaPlayer.start() - if (!isM3U8()) { - mediaPlayer.seekTo(position) - } + mediaPlayer.seekTo(position) postEvent(Bus.AUDIO_SIZE, mediaPlayer.duration) bookChapter?.let { it.end = mediaPlayer.duration.toLong() @@ -203,10 +196,10 @@ class AudioPlayService : BaseService(), * 播放出错 */ override fun onError(mp: MediaPlayer?, what: Int, extra: Int): Boolean { - AudioPlay.status = Status.STOP - postEvent(Bus.AUDIO_STATE, Status.STOP) - launch { - toast("error: $what $extra $url") + if (!mediaPlayer.isPlaying) { + AudioPlay.status = Status.STOP + postEvent(Bus.AUDIO_STATE, Status.STOP) + launch { toast("error: $what $extra $url") } } return true } From dcbe9531073a2c0d5cdd0d062bc7d69d562b24b5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Dec 2019 22:04:09 +0800 Subject: [PATCH 03/85] up --- .../io/legado/app/service/AudioPlayService.kt | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/AudioPlayService.kt b/app/src/main/java/io/legado/app/service/AudioPlayService.kt index 0a3c24e35..6855b8b84 100644 --- a/app/src/main/java/io/legado/app/service/AudioPlayService.kt +++ b/app/src/main/java/io/legado/app/service/AudioPlayService.kt @@ -134,14 +134,18 @@ class AudioPlayService : BaseService(), } private fun pause(pause: Boolean) { - AudioPlayService.pause = pause - handler.removeCallbacks(mpRunnable) - position = mediaPlayer.currentPosition - mediaPlayer.pause() - upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PAUSED) - AudioPlay.status = Status.PAUSE - postEvent(Bus.AUDIO_STATE, Status.PAUSE) - upNotification() + if (url.contains(".m3u8", false)) { + stopSelf() + } else { + AudioPlayService.pause = pause + handler.removeCallbacks(mpRunnable) + position = mediaPlayer.currentPosition + mediaPlayer.pause() + upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PAUSED) + AudioPlay.status = Status.PAUSE + postEvent(Bus.AUDIO_STATE, Status.PAUSE) + upNotification() + } } private fun resume() { From 1944ace9541b2080932a901c961b9e26005400ac Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 23 Dec 2019 22:07:10 +0800 Subject: [PATCH 04/85] up --- app/src/main/assets/updateLog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index 12171a213..586a8f614 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -6,6 +6,7 @@ **2019/12/23** * 修复每次打开翻页模式恢复默认的bug +* 修复m3u8报错问题 **2019/12/22** * 更新音频播放界面 From d9e2f979ae2d39c2ad76305299a6a1a1cfc2c6c2 Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 24 Dec 2019 08:43:31 +0800 Subject: [PATCH 05/85] up --- app/src/main/java/io/legado/app/constant/Bus.kt | 1 + .../java/io/legado/app/service/WebService.kt | 3 +++ .../java/io/legado/app/ui/main/my/MyFragment.kt | 17 +++++++++++++---- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/Bus.kt b/app/src/main/java/io/legado/app/constant/Bus.kt index 395d51ec4..b14c9f538 100644 --- a/app/src/main/java/io/legado/app/constant/Bus.kt +++ b/app/src/main/java/io/legado/app/constant/Bus.kt @@ -18,4 +18,5 @@ object Bus { const val AUDIO_SIZE = "audioSize" const val AUDIO_SPEED = "audioSpeed" const val SHOW_RSS = "showRss" + const val WEB_SERVICE_STOP = "webServiceStop" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/WebService.kt b/app/src/main/java/io/legado/app/service/WebService.kt index b32e6d6bc..25f2b6822 100644 --- a/app/src/main/java/io/legado/app/service/WebService.kt +++ b/app/src/main/java/io/legado/app/service/WebService.kt @@ -8,9 +8,11 @@ import io.legado.app.R import io.legado.app.base.BaseService import io.legado.app.constant.Action import io.legado.app.constant.AppConst +import io.legado.app.constant.Bus import io.legado.app.help.IntentHelp import io.legado.app.utils.NetworkUtils import io.legado.app.utils.getPrefInt +import io.legado.app.utils.postEvent import io.legado.app.web.HttpServer import io.legado.app.web.WebSocketServer import kotlinx.coroutines.launch @@ -54,6 +56,7 @@ class WebService : BaseService() { if (webSocketServer?.isAlive == true) { webSocketServer?.stop() } + postEvent(Bus.WEB_SERVICE_STOP, true) } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt index b84538aa1..e19d68ec5 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt @@ -7,9 +7,11 @@ import android.view.MenuItem import android.view.View import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat +import androidx.preference.SwitchPreference import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseFragment +import io.legado.app.constant.Bus import io.legado.app.help.BookHelp import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat @@ -23,10 +25,7 @@ import io.legado.app.ui.book.source.manage.BookSourceActivity import io.legado.app.ui.config.ConfigActivity import io.legado.app.ui.config.ConfigViewModel import io.legado.app.ui.replacerule.ReplaceRuleActivity -import io.legado.app.utils.LogUtils -import io.legado.app.utils.getPrefBoolean -import io.legado.app.utils.startActivity -import io.legado.app.utils.toast +import io.legado.app.utils.* import kotlinx.android.synthetic.main.view_title_bar.* import org.jetbrains.anko.startActivity @@ -64,7 +63,17 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config) { SharedPreferences.OnSharedPreferenceChangeListener { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + if (WebService.isRun) { + putPrefBoolean("webService", true) + } else { + putPrefBoolean("webService", false) + } addPreferencesFromResource(R.xml.pref_main) + observeEvent(Bus.WEB_SERVICE_STOP) { + findPreference("webService")?.let { + it.isChecked = false + } + } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { From a2235ca21d4dd827551c567be3165159134aa34e Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 25 Dec 2019 08:06:57 +0800 Subject: [PATCH 06/85] up --- .../java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt | 2 +- .../main/java/io/legado/app/service/AudioPlayService.kt | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt index bf8aded6d..b5343cf7f 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt @@ -117,7 +117,7 @@ class AnalyzeUrl( page?.let { val matcher = pagePattern.matcher(ruleUrl) while (matcher.find()) { - val pages = matcher.group(1).split(",") + val pages = matcher.group(1)!!.split(",") ruleUrl = if (page <= pages.size) { ruleUrl.replace(matcher.group(), pages[page - 1].trim { it <= ' ' }) } else { diff --git a/app/src/main/java/io/legado/app/service/AudioPlayService.kt b/app/src/main/java/io/legado/app/service/AudioPlayService.kt index 6855b8b84..ef2638c29 100644 --- a/app/src/main/java/io/legado/app/service/AudioPlayService.kt +++ b/app/src/main/java/io/legado/app/service/AudioPlayService.kt @@ -26,6 +26,7 @@ import io.legado.app.data.entities.BookChapter import io.legado.app.help.BookHelp import io.legado.app.help.IntentHelp import io.legado.app.help.MediaHelp +import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.receiver.MediaButtonReceiver import io.legado.app.service.help.AudioPlay import io.legado.app.ui.audio.AudioPlayActivity @@ -121,8 +122,10 @@ class AudioPlayService : BaseService(), AudioPlay.status = Status.PLAY postEvent(Bus.AUDIO_STATE, Status.PLAY) mediaPlayer.reset() - val uri = Uri.parse(url) - mediaPlayer.setDataSource(this, uri, AudioPlay.headers()) + val analyzeUrl = + AnalyzeUrl(url, headerMapF = AudioPlay.headers(), useWebView = true) + val uri = Uri.parse(analyzeUrl.url) + mediaPlayer.setDataSource(this, uri, analyzeUrl.headerMap) mediaPlayer.prepareAsync() } catch (e: Exception) { launch { From 3339c0540cd3522c3b91c6d0eb3a8de5c5424340 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 26 Dec 2019 15:06:21 +0800 Subject: [PATCH 07/85] up --- app/src/main/res/layout/item_download.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/src/main/res/layout/item_download.xml b/app/src/main/res/layout/item_download.xml index d829e291c..5ee60eeea 100644 --- a/app/src/main/res/layout/item_download.xml +++ b/app/src/main/res/layout/item_download.xml @@ -4,4 +4,19 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + + + + + + \ No newline at end of file From 6f7a518309f3079d21cadd5f8a4cb60abec53e9a Mon Sep 17 00:00:00 2001 From: Celeter Date: Thu, 26 Dec 2019 21:50:47 +0800 Subject: [PATCH 08/85] up --- app/src/main/assets/updateLog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index d424bc6cb..915ffb74d 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -4,6 +4,7 @@ * 先在旧版阅读2.19进行备份,再在新版阅读3.0的【我的】中,点击【备份与恢复】,选择【导入旧版本数据】,提示需要存储权限,选择允许即可导入成功。 * 注意:由于安卓10更改了权限策略,还需要给「允许安装其他应用」的权限才能导入源。MIUI11也需要此权限。 + **2019/12/15** * 修复清理缓存会把其他文件删除的问题 From 4d3c757f13debb56e9a3d6a8e080da7ca9ee0a19 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 27 Dec 2019 09:39:26 +0800 Subject: [PATCH 09/85] up --- .../main/java/io/legado/app/data/dao/BookDao.kt | 3 +++ app/src/main/java/io/legado/app/help/BookHelp.kt | 15 +++++++++++++-- .../io/legado/app/ui/download/DownloadActivity.kt | 2 ++ .../io/legado/app/ui/download/DownloadAdapter.kt | 7 +++++-- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index 42e76ddd6..d7fa8e1cf 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -17,6 +17,9 @@ interface BookDao { @Query("SELECT * FROM books WHERE origin = '${BookType.local}' order by durChapterTime desc") fun observeLocal(): LiveData> + @Query("SELECT * FROM books WHERE origin <> '${BookType.local}' order by durChapterTime desc") + fun observeWeb(): LiveData> + @Query("SELECT * FROM books WHERE `group` = :group") fun observeByGroup(group: Int): LiveData> diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index e6f17134a..5070a74dc 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -35,8 +35,15 @@ object BookHelp { FileHelp.getFolder(getBookCachePath()) } + @Synchronized fun saveContent(book: Book, bookChapter: BookChapter, content: String) { if (content.isEmpty()) return + FileHelp.getFolder(getBookFolder(book)).listFiles()?.forEach { + if (it.name.startsWith(String.format("%05d", bookChapter.index))) { + it.delete() + return@forEach + } + } val filePath = getChapterPath(book, bookChapter) val file = FileHelp.getFile(filePath) file.writeText(content) @@ -74,11 +81,15 @@ object BookHelp { } } - private fun getChapterPath(book: Book, bookChapter: BookChapter): String { + private fun getBookFolder(book: Book): String { val bookFolder = formatFolderName(book.name + book.bookUrl) + return "${getBookCachePath()}${File.separator}$bookFolder" + } + + private fun getChapterPath(book: Book, bookChapter: BookChapter): String { val chapterFile = String.format("%05d-%s", bookChapter.index, MD5Utils.md5Encode(bookChapter.title)) - return "${getBookCachePath()}${File.separator}$bookFolder${File.separator}$chapterFile.nb" + return "${getBookFolder(book)}${File.separator}$chapterFile.nb" } private fun formatFolderName(folderName: String): String { diff --git a/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt b/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt index 2ae90c8a5..633d38ca9 100644 --- a/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt +++ b/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt @@ -4,6 +4,7 @@ import android.os.Bundle import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager +import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseActivity import io.legado.app.data.entities.Book @@ -28,6 +29,7 @@ class DownloadActivity : BaseActivity(R.layout.activity_download) { private fun initLiveData() { bookshelfLiveData?.removeObservers(this) + bookshelfLiveData = App.db.bookDao().observeWeb() bookshelfLiveData?.observe(this, Observer { adapter.setItems(it) }) diff --git a/app/src/main/java/io/legado/app/ui/download/DownloadAdapter.kt b/app/src/main/java/io/legado/app/ui/download/DownloadAdapter.kt index 8407633ff..c6825041f 100644 --- a/app/src/main/java/io/legado/app/ui/download/DownloadAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/download/DownloadAdapter.kt @@ -5,14 +5,17 @@ import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.Book +import kotlinx.android.synthetic.main.item_download.view.* class DownloadAdapter(context: Context) : SimpleRecyclerAdapter(context, R.layout.item_download) { - override fun convert(holder: ItemViewHolder, item: Book, payloads: MutableList) { - + with(holder.itemView) { + tv_name.text = item.name + tv_author.text = item.author + } } } \ No newline at end of file From 4126bf8f168bc691a463d5b07e9207e2491949b0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 27 Dec 2019 11:03:25 +0800 Subject: [PATCH 10/85] up --- .../io/legado/app/ui/download/DownloadActivity.kt | 14 ++++++++++++++ app/src/main/res/menu/download.xml | 4 ++++ 2 files changed, 18 insertions(+) create mode 100644 app/src/main/res/menu/download.xml diff --git a/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt b/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt index 633d38ca9..ccf7facb0 100644 --- a/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt +++ b/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt @@ -1,6 +1,8 @@ package io.legado.app.ui.download import android.os.Bundle +import android.view.Menu +import android.view.MenuItem import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import androidx.recyclerview.widget.LinearLayoutManager @@ -21,6 +23,18 @@ class DownloadActivity : BaseActivity(R.layout.activity_download) { initLiveData() } + override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { + menuInflater.inflate(R.menu.download, menu) + return super.onCompatCreateOptionsMenu(menu) + } + + override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + + } + return super.onCompatOptionsItemSelected(item) + } + private fun initRecyclerView() { recycler_view.layoutManager = LinearLayoutManager(this) adapter = DownloadAdapter(this) diff --git a/app/src/main/res/menu/download.xml b/app/src/main/res/menu/download.xml new file mode 100644 index 000000000..e73b6af79 --- /dev/null +++ b/app/src/main/res/menu/download.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From bea0a08fa0e78a961fe93d4fca84e218fb7dc82a Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 27 Dec 2019 11:22:18 +0800 Subject: [PATCH 11/85] up --- .../main/java/io/legado/app/ui/download/DownloadActivity.kt | 2 ++ .../io/legado/app/ui/main/bookshelf/BookshelfFragment.kt | 3 ++- app/src/main/res/menu/download.xml | 6 +++++- app/src/main/res/menu/main_bookshelf.xml | 4 ++-- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt b/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt index ccf7facb0..30632f26c 100644 --- a/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt +++ b/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt @@ -30,7 +30,9 @@ class DownloadActivity : BaseActivity(R.layout.activity_download) { override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { + R.id.menu_download_start -> { + } } return super.onCompatOptionsItemSelected(item) } diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt index 4b8d578ec..15a494694 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfFragment.kt @@ -19,6 +19,7 @@ import io.legado.app.lib.dialogs.selector import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.accentColor import io.legado.app.ui.book.search.SearchActivity +import io.legado.app.ui.download.DownloadActivity import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.getViewModel import io.legado.app.utils.putPrefInt @@ -62,7 +63,7 @@ class BookshelfFragment : VMBaseFragment(R.layout.fragment_b } R.id.menu_arrange_bookshelf -> { } - R.id.menu_download_all -> viewModel.downloadAll() + R.id.menu_download -> startActivity() } } diff --git a/app/src/main/res/menu/download.xml b/app/src/main/res/menu/download.xml index e73b6af79..7762fc4e7 100644 --- a/app/src/main/res/menu/download.xml +++ b/app/src/main/res/menu/download.xml @@ -1,4 +1,8 @@ - + + + \ No newline at end of file diff --git a/app/src/main/res/menu/main_bookshelf.xml b/app/src/main/res/menu/main_bookshelf.xml index 45b586ca8..1c63a7629 100644 --- a/app/src/main/res/menu/main_bookshelf.xml +++ b/app/src/main/res/menu/main_bookshelf.xml @@ -21,9 +21,9 @@ app:showAsAction="never" /> Date: Fri, 27 Dec 2019 15:11:29 +0800 Subject: [PATCH 12/85] up --- app/src/main/res/layout/item_download.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/item_download.xml b/app/src/main/res/layout/item_download.xml index 5ee60eeea..f23794e94 100644 --- a/app/src/main/res/layout/item_download.xml +++ b/app/src/main/res/layout/item_download.xml @@ -2,7 +2,8 @@ + android:layout_height="wrap_content" + android:padding="16dp"> Date: Fri, 27 Dec 2019 15:12:08 +0800 Subject: [PATCH 13/85] up --- app/src/main/res/menu/download.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/menu/download.xml b/app/src/main/res/menu/download.xml index 7762fc4e7..50dfdbeaa 100644 --- a/app/src/main/res/menu/download.xml +++ b/app/src/main/res/menu/download.xml @@ -1,8 +1,10 @@ - + + android:title="@string/action_download" + app:showAsAction="ifRoom" /> \ No newline at end of file From 2a9a8df1c0ab50243461fcea7225bead09fa29e0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 27 Dec 2019 15:12:50 +0800 Subject: [PATCH 14/85] up --- app/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6231a701f..7dc6b33fd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -45,7 +45,7 @@ 阅读·搜索 书架还空着,先去添加吧! 搜索 - 下载任务 + 下载 列表视图 网格视图三列 网格视图四列 From 1466e9dee83de6c4e2cc59a825445243f522545b Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 27 Dec 2019 21:14:46 +0800 Subject: [PATCH 15/85] up --- .../io/legado/app/ui/download/DownloadActivity.kt | 14 ++++++++++++-- .../app/ui/main/bookshelf/BookshelfViewModel.kt | 8 -------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt b/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt index 30632f26c..850aac866 100644 --- a/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt +++ b/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt @@ -10,7 +10,10 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseActivity import io.legado.app.data.entities.Book +import io.legado.app.service.help.Download import kotlinx.android.synthetic.main.activity_download.* +import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.launch class DownloadActivity : BaseActivity(R.layout.activity_download) { @@ -30,8 +33,15 @@ class DownloadActivity : BaseActivity(R.layout.activity_download) { override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - R.id.menu_download_start -> { - + R.id.menu_download_start -> launch(IO) { + App.db.bookDao().webBooks.forEach { book -> + Download.start( + this@DownloadActivity, + book.bookUrl, + book.durChapterIndex, + book.totalChapterNum + ) + } } } return super.onCompatOptionsItemSelected(item) diff --git a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt index 7f116694e..83d3c41a5 100644 --- a/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/bookshelf/BookshelfViewModel.kt @@ -4,7 +4,6 @@ import android.app.Application import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.data.entities.BookGroup -import io.legado.app.service.help.Download class BookshelfViewModel(application: Application) : BaseViewModel(application) { @@ -33,11 +32,4 @@ class BookshelfViewModel(application: Application) : BaseViewModel(application) } } - fun downloadAll() { - execute { - App.db.bookDao().webBooks.forEach { book -> - Download.start(context, book.bookUrl, book.durChapterIndex, book.totalChapterNum) - } - } - } } From 1de48788fe1d6cc70562f7d2cdc5d8ed9fb1a447 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Dec 2019 10:49:07 +0800 Subject: [PATCH 16/85] up --- .../main/java/io/legado/app/help/BookHelp.kt | 4 ++++ .../legado/app/ui/download/DownloadAdapter.kt | 19 +++++++++++++++++-- .../app/ui/main/explore/ExploreAdapter.kt | 2 -- app/src/main/res/layout/item_find_book.xml | 6 ++---- app/src/main/res/values/strings.xml | 1 + 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/BookHelp.kt b/app/src/main/java/io/legado/app/help/BookHelp.kt index 5070a74dc..1ea320505 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -49,6 +49,10 @@ object BookHelp { file.writeText(content) } + fun getChapterCount(book: Book): Int { + return FileHelp.getFolder(getBookFolder(book)).list()?.size ?: 0 + } + fun hasContent(book: Book, bookChapter: BookChapter): Boolean { val filePath = getChapterPath(book, bookChapter) runCatching { diff --git a/app/src/main/java/io/legado/app/ui/download/DownloadAdapter.kt b/app/src/main/java/io/legado/app/ui/download/DownloadAdapter.kt index c6825041f..25b1b5b35 100644 --- a/app/src/main/java/io/legado/app/ui/download/DownloadAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/download/DownloadAdapter.kt @@ -1,10 +1,12 @@ package io.legado.app.ui.download import android.content.Context +import android.view.View import io.legado.app.R import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.Book +import io.legado.app.help.BookHelp import kotlinx.android.synthetic.main.item_download.view.* @@ -13,9 +15,22 @@ class DownloadAdapter(context: Context) : override fun convert(holder: ItemViewHolder, item: Book, payloads: MutableList) { with(holder.itemView) { - tv_name.text = item.name - tv_author.text = item.author + if (payloads.isEmpty()) { + tv_name.text = item.name + tv_author.text = item.author + upDownloadCount(this, item) + } else { + upDownloadCount(this, item) + } } } + private fun upDownloadCount(view: View, book: Book) { + view.tv_download.text = context.getString( + R.string.download_count, + BookHelp.getChapterCount(book), + book.totalChapterNum + ) + } + } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt b/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt index c0d19851f..144fa4e19 100644 --- a/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt +++ b/app/src/main/java/io/legado/app/ui/main/explore/ExploreAdapter.kt @@ -9,7 +9,6 @@ import io.legado.app.base.adapter.ItemViewHolder import io.legado.app.base.adapter.SimpleRecyclerAdapter import io.legado.app.data.entities.BookSource import io.legado.app.help.coroutine.Coroutine -import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.accentColor import io.legado.app.utils.ACache import io.legado.app.utils.gone @@ -29,7 +28,6 @@ class ExploreAdapter(context: Context, private val scope: CoroutineScope, val ca override fun convert(holder: ItemViewHolder, item: BookSource, payloads: MutableList) { with(holder.itemView) { if (payloads.isEmpty()) { - ATH.applyBackgroundTint(ll_title) tv_name.text = item.bookSourceName ll_title.onClick { val oldEx = exIndex diff --git a/app/src/main/res/layout/item_find_book.xml b/app/src/main/res/layout/item_find_book.xml index 266e69e8d..8a95ed1e2 100644 --- a/app/src/main/res/layout/item_find_book.xml +++ b/app/src/main/res/layout/item_find_book.xml @@ -18,11 +18,9 @@ android:paddingTop="6dp" android:paddingBottom="6dp" android:layout_margin="4dp" - android:background="@color/background" - android:elevation="3dp" + android:background="@color/btn_bg_press" android:orientation="horizontal" - android:gravity="center_vertical" - tools:ignore="UseCompoundDrawables"> + android:gravity="center_vertical"> 开始下载 取消下载 暂无任务 + 已下载 %d/%d 导入选择书籍 更新和搜索线程数,如感觉卡顿请减小线程数,量力而行 切换图标 From abbc64f356340cb70965002e6ed3a55f6e977626 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Dec 2019 10:51:57 +0800 Subject: [PATCH 17/85] up --- app/src/main/java/io/legado/app/service/DownloadService.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/service/DownloadService.kt b/app/src/main/java/io/legado/app/service/DownloadService.kt index d665d6b8f..8f5a6c606 100644 --- a/app/src/main/java/io/legado/app/service/DownloadService.kt +++ b/app/src/main/java/io/legado/app/service/DownloadService.kt @@ -32,7 +32,7 @@ class DownloadService : BaseService() { intent.getIntExtra("start", 0), intent.getIntExtra("end", 0) ) - Action.stop -> stopSelf() + Action.stop -> stopDownload() } } return super.onStartCommand(intent, flags, startId) @@ -75,6 +75,11 @@ class DownloadService : BaseService() { } } + private fun stopDownload() { + tasks.clear() + stopSelf() + } + /** * 更新通知 */ From e568c14b04918c4b5120ba08630323fe7680b85a Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Dec 2019 10:56:32 +0800 Subject: [PATCH 18/85] up --- app/src/main/java/io/legado/app/data/dao/BookDao.kt | 4 ++-- .../main/java/io/legado/app/ui/download/DownloadActivity.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookDao.kt b/app/src/main/java/io/legado/app/data/dao/BookDao.kt index d7fa8e1cf..68de17a66 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookDao.kt @@ -17,8 +17,8 @@ interface BookDao { @Query("SELECT * FROM books WHERE origin = '${BookType.local}' order by durChapterTime desc") fun observeLocal(): LiveData> - @Query("SELECT * FROM books WHERE origin <> '${BookType.local}' order by durChapterTime desc") - fun observeWeb(): LiveData> + @Query("SELECT * FROM books WHERE origin <> '${BookType.local}' and type = 0 order by durChapterTime desc") + fun observeDownload(): LiveData> @Query("SELECT * FROM books WHERE `group` = :group") fun observeByGroup(group: Int): LiveData> diff --git a/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt b/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt index 850aac866..0ca90a472 100644 --- a/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt +++ b/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt @@ -55,7 +55,7 @@ class DownloadActivity : BaseActivity(R.layout.activity_download) { private fun initLiveData() { bookshelfLiveData?.removeObservers(this) - bookshelfLiveData = App.db.bookDao().observeWeb() + bookshelfLiveData = App.db.bookDao().observeDownload() bookshelfLiveData?.observe(this, Observer { adapter.setItems(it) }) From dfbb47b56e4d69e7b54b39c1d2f09dbe66536538 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Dec 2019 11:14:30 +0800 Subject: [PATCH 19/85] up --- app/src/main/java/io/legado/app/constant/Bus.kt | 1 + .../java/io/legado/app/service/DownloadService.kt | 13 +++++++++++++ .../io/legado/app/ui/download/DownloadActivity.kt | 8 ++++++++ 3 files changed, 22 insertions(+) diff --git a/app/src/main/java/io/legado/app/constant/Bus.kt b/app/src/main/java/io/legado/app/constant/Bus.kt index b14c9f538..7795773e6 100644 --- a/app/src/main/java/io/legado/app/constant/Bus.kt +++ b/app/src/main/java/io/legado/app/constant/Bus.kt @@ -19,4 +19,5 @@ object Bus { const val AUDIO_SPEED = "audioSpeed" const val SHOW_RSS = "showRss" const val WEB_SERVICE_STOP = "webServiceStop" + const val UP_DOWNLOAD = "upDownload" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/DownloadService.kt b/app/src/main/java/io/legado/app/service/DownloadService.kt index 8f5a6c606..a1042b4d6 100644 --- a/app/src/main/java/io/legado/app/service/DownloadService.kt +++ b/app/src/main/java/io/legado/app/service/DownloadService.kt @@ -1,16 +1,19 @@ package io.legado.app.service import android.content.Intent +import android.os.Handler import androidx.core.app.NotificationCompat import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseService import io.legado.app.constant.Action import io.legado.app.constant.AppConst +import io.legado.app.constant.Bus import io.legado.app.help.BookHelp import io.legado.app.help.IntentHelp import io.legado.app.help.coroutine.Coroutine import io.legado.app.model.WebBook +import io.legado.app.utils.postEvent import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.asCoroutineDispatcher import java.util.concurrent.Executors @@ -18,10 +21,13 @@ import java.util.concurrent.Executors class DownloadService : BaseService() { private var searchPool = Executors.newFixedThreadPool(16).asCoroutineDispatcher() private var tasks: ArrayList> = arrayListOf() + private val handler = Handler() + private var runnable: Runnable = Runnable { upDownload() } override fun onCreate() { super.onCreate() updateNotification("正在启动下载") + handler.postDelayed(runnable, 1000) } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { @@ -41,6 +47,7 @@ class DownloadService : BaseService() { override fun onDestroy() { tasks.clear() searchPool.close() + handler.removeCallbacks(runnable) super.onDestroy() } @@ -80,6 +87,12 @@ class DownloadService : BaseService() { stopSelf() } + private fun upDownload() { + postEvent(Bus.UP_DOWNLOAD, true) + handler.removeCallbacks(runnable) + handler.postDelayed(runnable, 1000) + } + /** * 更新通知 */ diff --git a/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt b/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt index 0ca90a472..9789bc273 100644 --- a/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt +++ b/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt @@ -9,8 +9,10 @@ import androidx.recyclerview.widget.LinearLayoutManager import io.legado.app.App import io.legado.app.R import io.legado.app.base.BaseActivity +import io.legado.app.constant.Bus import io.legado.app.data.entities.Book import io.legado.app.service.help.Download +import io.legado.app.utils.observeEvent import kotlinx.android.synthetic.main.activity_download.* import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.launch @@ -60,4 +62,10 @@ class DownloadActivity : BaseActivity(R.layout.activity_download) { adapter.setItems(it) }) } + + override fun observeLiveBus() { + observeEvent(Bus.UP_DOWNLOAD) { + adapter.notifyItemRangeChanged(0, adapter.itemCount, true) + } + } } \ No newline at end of file From ea0f25f7352cd7d2b4cf1fb0bd7683831bd4ef60 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Dec 2019 11:18:24 +0800 Subject: [PATCH 20/85] up --- app/src/main/assets/updateLog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index 586a8f614..c79ed4f59 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -4,6 +4,9 @@ * 先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】,提示存储权限,选择允许即可导入成功。 * 注意:由于安卓10更改了权限策略,还需要给「允许安装其他应用」的权限才能导入源。MIUI11也需要此权限。 +**2019/12/28** +* 添加下载界面 + **2019/12/23** * 修复每次打开翻页模式恢复默认的bug * 修复m3u8报错问题 From 7628ed1e5e1c0d090b8d818b47b4e9df85486576 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Dec 2019 11:23:00 +0800 Subject: [PATCH 21/85] up --- app/src/main/java/io/legado/app/constant/PreferKey.kt | 1 + .../io/legado/app/ui/book/read/config/ReadStyleDialog.kt | 6 +++--- .../java/io/legado/app/ui/book/read/page/ContentView.kt | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/constant/PreferKey.kt b/app/src/main/java/io/legado/app/constant/PreferKey.kt index 4217e376d..c777fdb9a 100644 --- a/app/src/main/java/io/legado/app/constant/PreferKey.kt +++ b/app/src/main/java/io/legado/app/constant/PreferKey.kt @@ -15,4 +15,5 @@ object PreferKey { const val cleanCache = "cleanCache" const val lastGroup = "lastGroup" const val pageAnim = "pageAnim" + const val readBookFont = "readBookFont" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt index ea050dac8..098edad43 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt @@ -87,13 +87,13 @@ class ReadStyleDialog : DialogFragment() { } tv_text_font.onClick { FontSelectDialog(requireContext()).apply { - curPath = requireContext().getPrefString("readBookFont") + curPath = requireContext().getPrefString(PreferKey.readBookFont) defaultFont = { - requireContext().putPrefString("readBookFont", "") + requireContext().putPrefString(PreferKey.readBookFont, "") postEvent(Bus.UP_CONFIG, true) } selectFile = { - requireContext().putPrefString("readBookFont", it) + requireContext().putPrefString(PreferKey.readBookFont, it) postEvent(Bus.UP_CONFIG, true) } }.show() diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/ContentView.kt b/app/src/main/java/io/legado/app/ui/book/read/page/ContentView.kt index 41d4b937f..903cc3abc 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/ContentView.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/ContentView.kt @@ -81,7 +81,7 @@ class ContentView : FrameLayout { tv_bottom_right.setTextColor(it) } } - context.getPrefString("readBookFont")?.let { + context.getPrefString(PreferKey.readBookFont)?.let { if (it.isNotEmpty()) { content_text_view.typeface = Typeface.createFromFile(it) } else { From 3b4d0adee962866a9fee5a82a15ef93cc0999fda Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Dec 2019 16:43:57 +0800 Subject: [PATCH 22/85] up --- .../io/legado/app/data/dao/BookGroupDao.kt | 3 +++ .../java/io/legado/app/help/storage/Backup.kt | 18 ++++++++++++++---- .../java/io/legado/app/help/storage/Restore.kt | 14 ++++++++++---- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt b/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt index 0078eb26b..c48bd6e6b 100644 --- a/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt +++ b/app/src/main/java/io/legado/app/data/dao/BookGroupDao.kt @@ -16,6 +16,9 @@ interface BookGroupDao { @get:Query("SELECT MAX(groupId) FROM book_groups") val maxId: Int + @Query("SELECT * FROM book_groups ORDER BY `order`") + fun all(): List + @Insert(onConflict = OnConflictStrategy.REPLACE) fun insert(vararg bookGroup: BookGroup) diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt index 7062d1951..529deb629 100644 --- a/app/src/main/java/io/legado/app/help/storage/Backup.kt +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -27,8 +27,9 @@ object Backup { legadoPath + File.separator + "Export" } - private fun pbackup(path :String = legadoPath){ + private fun pBackup(path: String = legadoPath) { backupBookshelf(path) + backupBookGroup(path) backupBookSource(path) backupRssSource(path) backupReplaceRule(path) @@ -39,7 +40,7 @@ object Backup { fun backup() { doAsync { - pbackup() + pBackup() uiThread { App.INSTANCE.toast(R.string.backup_success) } @@ -48,7 +49,7 @@ object Backup { fun autoBackup() { doAsync { - pbackup() + pBackup() } } @@ -56,13 +57,22 @@ object Backup { App.db.bookDao().allBooks.let { if (it.isNotEmpty()) { val json = GSON.toJson(it) - val file = FileHelp.getFile(path + File.separator + "bookshelf.json") file.writeText(json) } } } + private fun backupBookGroup(path: String) { + App.db.bookGroupDao().all().let { + if (it.isNotEmpty()) { + val json = GSON.toJson(it) + val file = FileHelp.getFile(path + File.separator + "bookGroup.json") + file.writeText(json) + } + } + } + private fun backupBookSource(path: String) { App.db.bookSourceDao().all.let { if (it.isNotEmpty()) { diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index 53b040f28..b2e34783e 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -9,10 +9,7 @@ import com.jayway.jsonpath.ParseContext import io.legado.app.App import io.legado.app.R import io.legado.app.constant.AppConst -import io.legado.app.data.entities.Book -import io.legado.app.data.entities.BookSource -import io.legado.app.data.entities.ReplaceRule -import io.legado.app.data.entities.RssSource +import io.legado.app.data.entities.* import io.legado.app.help.FileHelp import io.legado.app.help.ReadBookConfig import io.legado.app.utils.* @@ -47,6 +44,15 @@ object Restore { } catch (e: Exception) { e.printStackTrace() } + try { + val file = FileHelp.getFile(path + File.separator + "bookGroup.json") + val json = file.readText() + GSON.fromJsonArray(json)?.let { + App.db.bookGroupDao().insert(*it.toTypedArray()) + } + } catch (e: Exception) { + e.printStackTrace() + } try { val file = FileHelp.getFile(path + File.separator + "bookSource.json") val json = file.readText() From 4c9cd3bf0bb4539fd48e03cfcad4a55c6919c8d9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Dec 2019 16:45:04 +0800 Subject: [PATCH 23/85] up --- app/src/main/assets/updateLog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index c79ed4f59..17989e384 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -6,6 +6,7 @@ **2019/12/28** * 添加下载界面 +* 添加分组备份 **2019/12/23** * 修复每次打开翻页模式恢复默认的bug From eea8dae17cbb2c3ed4a3a02dae09e5b0c8dbe247 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Dec 2019 20:10:01 +0800 Subject: [PATCH 24/85] up --- .../io/legado/app/service/DownloadService.kt | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/DownloadService.kt b/app/src/main/java/io/legado/app/service/DownloadService.kt index a1042b4d6..7383f691b 100644 --- a/app/src/main/java/io/legado/app/service/DownloadService.kt +++ b/app/src/main/java/io/legado/app/service/DownloadService.kt @@ -23,6 +23,18 @@ class DownloadService : BaseService() { private var tasks: ArrayList> = arrayListOf() private val handler = Handler() private var runnable: Runnable = Runnable { upDownload() } + private val notificationBuilder by lazy { + val builder = NotificationCompat.Builder(this, AppConst.channelIdDownload) + .setSmallIcon(R.drawable.ic_download) + .setOngoing(true) + .setContentTitle(getString(R.string.download_offline)) + builder.addAction( + R.drawable.ic_stop_black_24dp, + getString(R.string.cancel), + IntentHelp.servicePendingIntent(this, Action.stop) + ) + builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + } override fun onCreate() { super.onCreate() @@ -97,17 +109,8 @@ class DownloadService : BaseService() { * 更新通知 */ private fun updateNotification(content: String) { - val builder = NotificationCompat.Builder(this, AppConst.channelIdDownload) - .setSmallIcon(R.drawable.ic_download) - .setOngoing(true) - .setContentTitle(getString(R.string.download_offline)) - .setContentText(content) - builder.addAction( - R.drawable.ic_stop_black_24dp, - getString(R.string.cancel), - IntentHelp.servicePendingIntent(this, Action.stop) - ) - builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + val builder = notificationBuilder + builder.setContentText(content) val notification = builder.build() startForeground(AppConst.notificationIdDownload, notification) } From fc12579eb0358771c562ce1d520ddd034d846f60 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Dec 2019 20:12:32 +0800 Subject: [PATCH 25/85] up --- app/src/main/java/io/legado/app/service/DownloadService.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/DownloadService.kt b/app/src/main/java/io/legado/app/service/DownloadService.kt index 7383f691b..798fcdfb8 100644 --- a/app/src/main/java/io/legado/app/service/DownloadService.kt +++ b/app/src/main/java/io/legado/app/service/DownloadService.kt @@ -23,6 +23,7 @@ class DownloadService : BaseService() { private var tasks: ArrayList> = arrayListOf() private val handler = Handler() private var runnable: Runnable = Runnable { upDownload() } + private var notificationContent = "正在启动下载" private val notificationBuilder by lazy { val builder = NotificationCompat.Builder(this, AppConst.channelIdDownload) .setSmallIcon(R.drawable.ic_download) @@ -38,7 +39,7 @@ class DownloadService : BaseService() { override fun onCreate() { super.onCreate() - updateNotification("正在启动下载") + updateNotification(notificationContent) handler.postDelayed(runnable, 1000) } @@ -74,7 +75,7 @@ class DownloadService : BaseService() { if (!BookHelp.hasContent(book, chapter)) { webBook.getContent(book, chapter, scope = this, context = searchPool) .onStart { - updateNotification(chapter.title) + notificationContent = chapter.title } .onSuccess(IO) { content -> content?.let { @@ -100,6 +101,7 @@ class DownloadService : BaseService() { } private fun upDownload() { + updateNotification(notificationContent) postEvent(Bus.UP_DOWNLOAD, true) handler.removeCallbacks(runnable) handler.postDelayed(runnable, 1000) From 4aafb528e23b975b05a0a25832d081bf34e3e6ea Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Dec 2019 21:06:12 +0800 Subject: [PATCH 26/85] up --- .../io/legado/app/ui/rss/read/ReadRssActivity.kt | 16 ++++++++++++++++ app/src/main/res/menu/rss_read.xml | 6 ++++++ 2 files changed, 22 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt index 9fc29878b..037364296 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.rss.read import android.annotation.SuppressLint +import android.content.Intent import android.os.Bundle import android.view.KeyEvent import android.view.Menu @@ -15,6 +16,7 @@ import io.legado.app.lib.theme.primaryTextColor import io.legado.app.utils.NetworkUtils import io.legado.app.utils.getViewModel import kotlinx.android.synthetic.main.activity_rss_read.* +import org.jetbrains.anko.toast class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_read), ReadRssViewModel.CallBack { @@ -42,6 +44,9 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.menu_rss_star -> viewModel.star() + R.id.menu_share_it -> viewModel.rssArticle?.let { + shareText("链接分享", it.link) + } } return super.onCompatOptionsItemSelected(item) } @@ -115,4 +120,15 @@ class ReadRssActivity : VMBaseActivity(R.layout.activity_rss_r } return super.onKeyUp(keyCode, event) } + + private fun shareText(title: String, text: String) { + try { + val textIntent = Intent(Intent.ACTION_SEND) + textIntent.type = "text/plain" + textIntent.putExtra(Intent.EXTRA_TEXT, text) + startActivity(Intent.createChooser(textIntent, title)) + } catch (e: Exception) { + toast(R.string.can_not_share) + } + } } \ No newline at end of file diff --git a/app/src/main/res/menu/rss_read.xml b/app/src/main/res/menu/rss_read.xml index 29f3087ba..15463f64d 100644 --- a/app/src/main/res/menu/rss_read.xml +++ b/app/src/main/res/menu/rss_read.xml @@ -8,4 +8,10 @@ android:icon="@drawable/ic_star_border" app:showAsAction="always" /> + + \ No newline at end of file From 807123a23063a7e2436dfa617fd646808300f2be Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Dec 2019 21:30:12 +0800 Subject: [PATCH 27/85] up --- app/src/main/res/drawable/bg_shadow_bottom.png | Bin 3127 -> 0 bytes app/src/main/res/drawable/bg_shadow_bottom.xml | 8 ++++++++ .../main/res/drawable/bg_shadow_bottom_night.png | Bin 418 -> 0 bytes .../main/res/drawable/bg_shadow_bottom_night.xml | 8 ++++++++ app/src/main/res/drawable/bg_shadow_top.png | Bin 340 -> 0 bytes app/src/main/res/drawable/bg_shadow_top.xml | 8 ++++++++ .../main/res/drawable/bg_shadow_top_night.png | Bin 424 -> 0 bytes .../main/res/drawable/bg_shadow_top_night.xml | 8 ++++++++ 8 files changed, 32 insertions(+) delete mode 100644 app/src/main/res/drawable/bg_shadow_bottom.png create mode 100644 app/src/main/res/drawable/bg_shadow_bottom.xml delete mode 100644 app/src/main/res/drawable/bg_shadow_bottom_night.png create mode 100644 app/src/main/res/drawable/bg_shadow_bottom_night.xml delete mode 100644 app/src/main/res/drawable/bg_shadow_top.png create mode 100644 app/src/main/res/drawable/bg_shadow_top.xml delete mode 100644 app/src/main/res/drawable/bg_shadow_top_night.png create mode 100644 app/src/main/res/drawable/bg_shadow_top_night.xml diff --git a/app/src/main/res/drawable/bg_shadow_bottom.png b/app/src/main/res/drawable/bg_shadow_bottom.png deleted file mode 100644 index ac0124b670691689ed19d44fb1498230f91cbf68..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3127 zcmV-749N3|P)KLZ*U+5Lu!Sk^o_Z5E4Meg@_7P6crJiNL9pw)e1;Xm069{HJUZAPk55R%$-RIA z6-eL&AQ0xu!e<4=008gy@A0LT~suv4>S3ILP<0Bm`DLLvaF4FK%)Nj?Pt*r}7;7Xa9z9H|HZjR63e zC`Tj$K)V27Re@400>HumpsYY5E(E}?0f1SyGDiY{y#)Yvj#!WnKwtoXnL;eg03bL5 z07D)V%>y7z1E4U{zu>7~aD})?0RX_umCct+(lZpemCzb@^6=o|A>zVpu|i=NDG+7} zl4`aK{0#b-!z=TL9Wt0BGO&T{GJWpjryhdijfaIQ&2!o}p04JRKYg3k&Tf zVxhe-O!X z{f;To;xw^bEES6JSc$k$B2CA6xl)ltA<32E66t?3@gJ7`36pmX0IY^jz)rRYwaaY4 ze(nJRiw;=Qb^t(r^DT@T3y}a2XEZW-_W%Hszxj_qD**t_m!#tW0KDiJT&R>6OvVTR z07RgHDzHHZ48atvzz&?j9lXF70$~P3Knx_nJP<+#`N z#-MZ2bTkiLfR>_b(HgWKJ%F~Nr_oF3b#wrIijHG|(J>BYjM-sajE6;FiC7vY#};Gd zST$CUHDeuEH+B^pz@B062qXfFfD`NpUW5?BY=V%GM_5c)L#QR}BeW8_2v-S%gfYS= zB9o|3v?Y2H`NVi)In3rTB8+ej^> zQ=~r95NVuDChL%G$=>7$vVg20myx%S50Foi`^m%Pw-h?Xh~i8Mq9jtJloCocWk2Nv zrJpiFnV_ms&8eQ$2&#xWpIS+6pmtC%Q-`S&GF4Q#^mhymh7E(qNMa}%YZ-ePrx>>xFPTiH1=E+A$W$=bG8>s^ zm=Bn5Rah$aDtr}@$`X}2l~$F0mFKEdRdZE8)p@E5RI61Ft6o-prbbn>P~)iy)E2AN zsU20jsWz_8Qg>31P|s0cqrPALg8E|(vWA65poU1JRAaZs8I2(p#xiB`SVGovRs-uS zYnV-9TeA7=Om+qP8+I>yOjAR1s%ETak!GFdam@h^# z)@rS0t$wXH+Irf)+G6c;?H29p+V6F6oj{!|o%K3xI`?%6x;DB|x`n#ibhIR?(H}Q3Gzd138Ei2)WAMz7W9Vy`X}HnwgyEn!VS)>mv$8&{hQn>w4zwy3R}t;BYlZQm5)6pty=DfLrs+A-|>>;~;Q z_F?uV_HFjh9n2gO9o9Q^JA86v({H5aB!kjoO6 zc9$1ZZKsN-Zl8L~mE{`ly3)1N^`o1+o7}D0ZPeY&J;i;i`%NyJ8_8Y6J?}yE@b_5a zam?eLr<8@mESk|3$_SkmS{wQ>%qC18))9_|&j{ZT zes8AvOzF(F2#DZEY>2oYX&IRp`F#{ADl)1r>QS^)ba8a|EY_^#S^HO&t^Rgqwv=MZThqqEWH8 zxJo>d=ABlR_Bh=;eM9Tw|Ih34~oTE|= zX_mAr*D$vzw@+p(E0Yc6dFE}(8oqt`+R{gE3x4zjX+Sb3_cYE^= zgB=w+-tUy`ytONMS8KgRef4hA?t0j zufM;t32jm~jUGrkaOInTZ`zyfns>EuS}G30LFK_G-==(f<51|K&cocp&EJ`SxAh3? zNO>#LI=^+SEu(FqJ)ynt=!~PC9bO$rzPJB=?=j6w@a-(u02P7 zaQ)#(uUl{HW%tYNS3ItC^iAtK(eKlL`f9+{bJzISE?u8_z3;~C8@FyI-5j_jy7l;W z_U#vU3hqqYU3!mrul&B+{ptt$59)uk{;_4iZQ%G|z+lhASr6|H35TBkl>gI*;nGLU zN7W-nBaM%pA0HbH8olyl&XeJ%vZoWz%6?Y=dFykl=imL}`%BMQ{Mhgd`HRoLu6e2R za__6DuR6yg#~-}Tc|Gx_{H@O0eebyMy5GmWADJlpK>kqk(fVV@r_fLLKIeS?{4e)} z^ZO;zpECde03c&XQcVB=dL;k=fP(-4`Tqa_faw4Lbua(`>RI+y?e7jKeZ#YO-C z0c1%;K~#9!?AWnt!!Q_yQ3WDshAdvX1w7>yvUu(LKT?NUAc9ch$Q>k~;qVivI}|={ zop8QAPQahwj{t%IL4Y7Y5FiK;1PB5I0WZb9f{3m=z-YIttUnCB+as7L z2n1sxpd5)HAd5o~kP!q30_s6rT(_fZAt3W_;e_>J=tXNZfw_?Y<~Rg_Km>s}1OYGO5CozS1eC)F=iB2N=Vfx;Uhke! zSP00X2ytE}7(rT%{B!c=ng{}6 + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_shadow_bottom_night.png b/app/src/main/res/drawable/bg_shadow_bottom_night.png deleted file mode 100644 index c3036b0364870453a94ee0d1a7683baa968ff2d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 418 zcmeAS@N?(olHy`uVBq!ia0vp^M}XLlgAGWQtluI6q!^2X+?^QKos)S9a~60+7BevL9R^{>^*yigW;dax8Dr*Mr|L}5_k*}1VCs)c}J((1V_BC&fy!=xl%)ZcZ38L03sg2&?ZIYko+nOkKuXsGt@#a9W&u)` z2vpVwR8|NwZ8FfbIY1?k)&P|}2P)YCQj!W(vJRvKWYTP)k~<(J>wrqW1C>;Olq3U{ z%mXU<2r^|lP{|&UlC?l3?}18wfRv;ImF%1K;eM~%{kb9RvTOPF`2fR}!PC{xWt~$( F699})m_h&m diff --git a/app/src/main/res/drawable/bg_shadow_bottom_night.xml b/app/src/main/res/drawable/bg_shadow_bottom_night.xml new file mode 100644 index 000000000..de0d552f3 --- /dev/null +++ b/app/src/main/res/drawable/bg_shadow_bottom_night.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_shadow_top.png b/app/src/main/res/drawable/bg_shadow_top.png deleted file mode 100644 index cb8fee03db41e424234fce1f138671c15d338c3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 340 zcmeAS@N?(olHy`uVBq!ia0vp^M}XLlg&9b;HLg?#QbGYfA+8+iZY**Ztctck5`t!a zDt86SvXun+1&cEZvGQ`(?r9eRioEu8aSVw#{Pxnt%)<@>t{2;_3^EfW?=(o>IbgKv zfc4+)lcqLF$b711HrgeB`k$;^PmbC)O`RsKMK9M*7FrfRx5%}b_jmF!&+rXxZ#&oc zCq%l4rKtq9tmNs)xbgH_*R?f{vMiN5FY@{cCI-0P*(kepQMt%PkwX_me(>Zvl`!-2 z-U(ovTO@PedWz8eg)F^FZU&+U-)bbq&Qx@r;2~(~mZaGqre!zopr0Bb^kD*ylh diff --git a/app/src/main/res/drawable/bg_shadow_top.xml b/app/src/main/res/drawable/bg_shadow_top.xml new file mode 100644 index 000000000..067790cc9 --- /dev/null +++ b/app/src/main/res/drawable/bg_shadow_top.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_shadow_top_night.png b/app/src/main/res/drawable/bg_shadow_top_night.png deleted file mode 100644 index 7984c35dbd2cdb35c16cf7942de030ed4e225565..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 424 zcmeAS@N?(olHy`uVBq!ia0vp^M}XLlgAGWQtluI6q!^2X+?^QKos)S9a~60+7BevL9R^{>lk;;^Bllfrk9fQG{C_uv)`~2aO-8k* zOuKLEZ#dQRBZsA^?Z& zY!)NMJgG*Xj_Ym;!jEuF4af=70@2Ctw%C zHruCTGf2Zm!4oYOxhyrOgxc2ll=nJ>Et~A-pqOyt)DwQE4W5d7{_#q0_c3_FQ+S6X zCG}I0e9jslpsiL}Kw}TPDWrGo2f4)&X!f5>77-@4>+1|soZgr-sj=_?k*14W!cqZ) zB|PT@Hw1D>1a<5=&$0%n>a`FL7h|(_I736c&T0Oe4XlDe@&eO=q08Xu>gTe~DWM4f Du2h!N diff --git a/app/src/main/res/drawable/bg_shadow_top_night.xml b/app/src/main/res/drawable/bg_shadow_top_night.xml new file mode 100644 index 000000000..3e776dbad --- /dev/null +++ b/app/src/main/res/drawable/bg_shadow_top_night.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file From 148ebfc585df2b503f182602e11d31f01fe2ed1c Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Dec 2019 21:37:13 +0800 Subject: [PATCH 28/85] up --- app/src/main/res/drawable/bg_shadow_bottom.xml | 2 +- app/src/main/res/drawable/bg_shadow_bottom_night.xml | 2 +- app/src/main/res/drawable/bg_shadow_top.xml | 2 +- app/src/main/res/drawable/bg_shadow_top_night.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/drawable/bg_shadow_bottom.xml b/app/src/main/res/drawable/bg_shadow_bottom.xml index 88abc41aa..68063fd27 100644 --- a/app/src/main/res/drawable/bg_shadow_bottom.xml +++ b/app/src/main/res/drawable/bg_shadow_bottom.xml @@ -2,7 +2,7 @@ \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_shadow_bottom_night.xml b/app/src/main/res/drawable/bg_shadow_bottom_night.xml index de0d552f3..85d10b753 100644 --- a/app/src/main/res/drawable/bg_shadow_bottom_night.xml +++ b/app/src/main/res/drawable/bg_shadow_bottom_night.xml @@ -2,7 +2,7 @@ \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_shadow_top.xml b/app/src/main/res/drawable/bg_shadow_top.xml index 067790cc9..98f1df214 100644 --- a/app/src/main/res/drawable/bg_shadow_top.xml +++ b/app/src/main/res/drawable/bg_shadow_top.xml @@ -2,7 +2,7 @@ \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_shadow_top_night.xml b/app/src/main/res/drawable/bg_shadow_top_night.xml index 3e776dbad..2ef90a767 100644 --- a/app/src/main/res/drawable/bg_shadow_top_night.xml +++ b/app/src/main/res/drawable/bg_shadow_top_night.xml @@ -2,7 +2,7 @@ \ No newline at end of file From 1776012f77531aefdb8f8435aad3ee8e167636f3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Dec 2019 21:58:20 +0800 Subject: [PATCH 29/85] up --- app/build.gradle | 6 +++--- .../java/io/legado/app/model/analyzeRule/AnalyzeRule.kt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index d99118fc5..7469f6cf2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -98,7 +98,7 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' implementation 'androidx.viewpager2:viewpager2:1.0.0' - implementation 'com.google.android.material:material:1.2.0-alpha02' + implementation 'com.google.android.material:material:1.2.0-alpha03' implementation 'com.google.android:flexbox:1.1.0' //lifecycle @@ -107,12 +107,12 @@ dependencies { implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" //room - def room_version = '2.2.2' + def room_version = '2.2.3' implementation "androidx.room:room-runtime:$room_version" kapt "androidx.room:room-compiler:$room_version" //paging - implementation 'androidx.paging:paging-runtime:2.1.0' + implementation 'androidx.paging:paging-runtime:2.1.1' //anko def anko_version = '0.10.8' diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index c2ed7c8da..419164917 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -614,7 +614,7 @@ class AnalyzeRule(var book: BaseBook? = null) : JsExtensions { val pattern = Pattern.compile("(第)(.+?)(章)") val matcher = pattern.matcher(s) return if (matcher.find()) { - matcher.group(1) + StringUtils.stringToInt(matcher.group(2)) + matcher.group(3) + matcher.group(1)!! + StringUtils.stringToInt(matcher.group(2)) + matcher.group(3) } else { s } From 24974cfa176231abbd1c7382fd5f5833d577e43f Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Dec 2019 22:10:08 +0800 Subject: [PATCH 30/85] up --- app/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/app/build.gradle b/app/build.gradle index 7469f6cf2..18d4ac8ed 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -37,6 +37,7 @@ android { versionName version testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" project.ext.set("archivesBaseName", name + "_" + version) + multiDexEnabled true } buildTypes { release { From b49a5d7de92bc20edb4a0c0737d1631bdfbddd10 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 28 Dec 2019 22:17:03 +0800 Subject: [PATCH 31/85] up --- .../main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt index 419164917..3aa920237 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeRule.kt @@ -320,7 +320,7 @@ class AnalyzeRule(var book: BaseBook? = null) : JsExtensions { val pattern = Pattern.compile(rule.replaceRegex) val matcher = pattern.matcher(vResult) if (matcher.find()) { - matcher.group(0).replaceFirst(rule.replaceRegex.toRegex(), rule.replacement) + matcher.group(0)!!.replaceFirst(rule.replaceRegex.toRegex(), rule.replacement) } else { "" } From 52c8996af64fc360d7506903444b97f33064b79e Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 29 Dec 2019 19:32:28 +0800 Subject: [PATCH 32/85] up --- .../java/io/legado/app/ui/chapterlist/ChapterListFragment.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt index 8a1990b88..c8860f021 100644 --- a/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt +++ b/app/src/main/java/io/legado/app/ui/chapterlist/ChapterListFragment.kt @@ -13,6 +13,7 @@ import io.legado.app.R import io.legado.app.base.VMBaseFragment import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter +import io.legado.app.lib.theme.backgroundColor import io.legado.app.utils.getViewModelOfActivity import kotlinx.android.synthetic.main.fragment_chapter_list.* import org.jetbrains.anko.sdk27.listeners.onClick @@ -58,6 +59,7 @@ class ChapterListFragment : VMBaseFragment(R.layout.fragme } private fun initView() { + ll_chapter_base_info.setBackgroundColor(backgroundColor) iv_chapter_top.onClick { recycler_view.scrollToPosition(0) } iv_chapter_bottom.onClick { if (adapter.itemCount > 0) { From 4568b39af13f7fd54e08608787abb1aa6d3c8dab Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 29 Dec 2019 19:40:08 +0800 Subject: [PATCH 33/85] up --- .../java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt index 28e022fb5..5475df744 100644 --- a/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt +++ b/app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeByRegex.kt @@ -16,7 +16,7 @@ object AnalyzeByRegex { // 新建容器 val info = arrayListOf() for (groupIndex in 0..resM.groupCount()) { - info.add(resM.group(groupIndex)) + info.add(resM.group(groupIndex)!!) } info } else { @@ -43,7 +43,7 @@ object AnalyzeByRegex { // 新建容器 val info = arrayListOf() for (groupIndex in 0..resM.groupCount()) { - info.add(resM.group(groupIndex)) + info.add(resM.group(groupIndex)!!) } books.add(info) } while (resM.find()) From 6f20ed67e764bf725a85baaae00f17530997e4fb Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 29 Dec 2019 19:41:34 +0800 Subject: [PATCH 34/85] up --- app/src/main/java/io/legado/app/model/rss/RssParser.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/rss/RssParser.kt b/app/src/main/java/io/legado/app/model/rss/RssParser.kt index 7606bd43e..816a3858f 100644 --- a/app/src/main/java/io/legado/app/model/rss/RssParser.kt +++ b/app/src/main/java/io/legado/app/model/rss/RssParser.kt @@ -122,9 +122,9 @@ object RssParser { if (matcherImg.find()) { val imgTag = matcherImg.group(1) val patternLink = "src\\s*=\\s*\"(.+?)\"".toPattern() - val matcherLink = patternLink.matcher(imgTag) + val matcherLink = patternLink.matcher(imgTag!!) if (matcherLink.find()) { - url = matcherLink.group(1).trim() + url = matcherLink.group(1)!!.trim() } } return url From 41258272b742a333a8f4e307775c396e6fe2e7f6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 29 Dec 2019 19:52:50 +0800 Subject: [PATCH 35/85] up --- app/src/main/res/drawable/side_nav_bar.xml | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 app/src/main/res/drawable/side_nav_bar.xml diff --git a/app/src/main/res/drawable/side_nav_bar.xml b/app/src/main/res/drawable/side_nav_bar.xml deleted file mode 100644 index 6d81870b0..000000000 --- a/app/src/main/res/drawable/side_nav_bar.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - \ No newline at end of file From 81ac4d23d268914cf3e42fda1960c9b7cd0326b5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sun, 29 Dec 2019 22:20:39 +0800 Subject: [PATCH 36/85] up --- .../legado/app/ui/book/read/page/PageView.kt | 6 - .../app/ui/book/read/page/curl/CurlMesh.java | 954 ------------------ .../app/ui/book/read/page/curl/CurlPage.kt | 191 ---- .../ui/book/read/page/curl/CurlRenderer.kt | 221 ---- .../app/ui/book/read/page/curl/CurlView.kt | 769 -------------- .../book/read/page/delegate/PageDelegate.kt | 4 +- .../page/delegate/SimulationPageDelegate.kt | 570 +++++++++-- 7 files changed, 487 insertions(+), 2228 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/ui/book/read/page/curl/CurlMesh.java delete mode 100644 app/src/main/java/io/legado/app/ui/book/read/page/curl/CurlPage.kt delete mode 100644 app/src/main/java/io/legado/app/ui/book/read/page/curl/CurlRenderer.kt delete mode 100644 app/src/main/java/io/legado/app/ui/book/read/page/curl/CurlView.kt diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt b/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt index 9d17e0f18..84dafcaa6 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/PageView.kt @@ -9,7 +9,6 @@ import android.widget.FrameLayout import io.legado.app.constant.PreferKey import io.legado.app.help.ReadBookConfig import io.legado.app.service.help.ReadBook -import io.legado.app.ui.book.read.page.curl.CurlView import io.legado.app.ui.book.read.page.delegate.* import io.legado.app.utils.activity import io.legado.app.utils.getPrefInt @@ -26,7 +25,6 @@ class PageView(context: Context, attrs: AttributeSet) : var prevPage: ContentView? = null var curPage: ContentView? = null var nextPage: ContentView? = null - var curlView: CurlView? = null init { callBack = activity as? CallBack @@ -91,10 +89,6 @@ class PageView(context: Context, attrs: AttributeSet) : } fun upPageAnim(pageAnim: Int) { - if (curlView != null) { - removeView(curlView) - curlView = null - } pageDelegate = null pageDelegate = when (pageAnim) { 0 -> CoverPageDelegate(this) diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/curl/CurlMesh.java b/app/src/main/java/io/legado/app/ui/book/read/page/curl/CurlMesh.java deleted file mode 100644 index 65ddbc363..000000000 --- a/app/src/main/java/io/legado/app/ui/book/read/page/curl/CurlMesh.java +++ /dev/null @@ -1,954 +0,0 @@ -package io.legado.app.ui.book.read.page.curl; - -import android.graphics.Bitmap; -import android.graphics.Color; -import android.graphics.PointF; -import android.graphics.RectF; -import android.opengl.GLUtils; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.FloatBuffer; - -import javax.microedition.khronos.opengles.GL10; - -/** - * Class implementing actual curl/page rendering. - * - * @author harism - */ -public class CurlMesh { - - // Flag for rendering some lines used for developing. Shows - // curl position and one for the direction from the - // position given. Comes handy once playing around with different - // ways for following pointer. - private static final boolean DRAW_CURL_POSITION = false; - // Flag for drawing polygon outlines. Using this flag crashes on emulator - // due to reason unknown to me. Leaving it here anyway as seeing polygon - // outlines gives good insight how original rectangle is divided. - private static final boolean DRAW_POLYGON_OUTLINES = false; - // Flag for enabling shadow rendering. - private static final boolean DRAW_SHADOW = true; - // Flag for texture rendering. While this is likely something you - // don't want to do it's been used for development purposes as texture - // rendering is rather slow on emulator. - private static final boolean DRAW_TEXTURE = true; - - // Colors for shadow. Inner one is the color drawn next to surface where - // shadowed area starts and outer one is color shadow ends to. - private static final float[] SHADOW_INNER_COLOR = {0f, 0f, 0f, .5f}; - private static final float[] SHADOW_OUTER_COLOR = {0f, 0f, 0f, .0f}; - - // Let's avoid using 'new' as much as possible. Meaning we introduce arrays - // once here and reuse them on runtime. Doesn't really have very much effect - // but avoids some garbage collections from happening. - private Array mArrDropShadowVertices; - private Array mArrIntersections; - private Array mArrOutputVertices; - private Array mArrRotatedVertices; - private Array mArrScanLines; - private Array mArrSelfShadowVertices; - private Array mArrTempShadowVertices; - private Array mArrTempVertices; - - // Buffers for feeding rasterizer. - private FloatBuffer mBufColors; - private FloatBuffer mBufCurlPositionLines; - private FloatBuffer mBufShadowColors; - private FloatBuffer mBufShadowVertices; - private FloatBuffer mBufTexCoords; - private FloatBuffer mBufVertices; - - private int mCurlPositionLinesCount; - private int mDropShadowCount; - - // Boolean for 'flipping' texture sideways. - private boolean mFlipTexture = false; - // Maximum number of split lines used for creating a curl. - private int mMaxCurlSplits; - - // Bounding rectangle for this mesh. mRectagle[0] = top-left corner, - // mRectangle[1] = bottom-left, mRectangle[2] = top-right and mRectangle[3] - // bottom-right. - private final Vertex[] mRectangle = new Vertex[4]; - private int mSelfShadowCount; - - private boolean mTextureBack = false; - // Texture ids and other variables. - private int[] mTextureIds = null; - private final CurlPage mTexturePage = new CurlPage(); - private final RectF mTextureRectBack = new RectF(); - private final RectF mTextureRectFront = new RectF(); - - private int mVerticesCountBack; - private int mVerticesCountFront; - - /** - * Constructor for mesh object. - * - * @param maxCurlSplits Maximum number curl can be divided into. The bigger the value - * the smoother curl will be. With the cost of having more - * polygons for drawing. - */ - public CurlMesh(int maxCurlSplits) { - // There really is no use for 0 splits. - mMaxCurlSplits = maxCurlSplits < 1 ? 1 : maxCurlSplits; - - mArrScanLines = new Array<>(maxCurlSplits + 2); - mArrOutputVertices = new Array<>(7); - mArrRotatedVertices = new Array<>(4); - mArrIntersections = new Array<>(2); - mArrTempVertices = new Array<>(7 + 4); - for (int i = 0; i < 7 + 4; ++i) { - mArrTempVertices.add(new Vertex()); - } - - if (DRAW_SHADOW) { - mArrSelfShadowVertices = new Array<>( - (mMaxCurlSplits + 2) * 2); - mArrDropShadowVertices = new Array<>( - (mMaxCurlSplits + 2) * 2); - mArrTempShadowVertices = new Array<>( - (mMaxCurlSplits + 2) * 2); - for (int i = 0; i < (mMaxCurlSplits + 2) * 2; ++i) { - mArrTempShadowVertices.add(new ShadowVertex()); - } - } - - // Rectangle consists of 4 vertices. Index 0 = top-left, index 1 = - // bottom-left, index 2 = top-right and index 3 = bottom-right. - for (int i = 0; i < 4; ++i) { - mRectangle[i] = new Vertex(); - } - // Set up shadow penumbra direction to each vertex. We do fake 'self - // shadow' calculations based on this information. - mRectangle[0].mPenumbraX = mRectangle[1].mPenumbraX = mRectangle[1].mPenumbraY = mRectangle[3].mPenumbraY = -1; - mRectangle[0].mPenumbraY = mRectangle[2].mPenumbraX = mRectangle[2].mPenumbraY = mRectangle[3].mPenumbraX = 1; - - if (DRAW_CURL_POSITION) { - mCurlPositionLinesCount = 3; - ByteBuffer hvbb = ByteBuffer - .allocateDirect(mCurlPositionLinesCount * 2 * 2 * 4); - hvbb.order(ByteOrder.nativeOrder()); - mBufCurlPositionLines = hvbb.asFloatBuffer(); - mBufCurlPositionLines.position(0); - } - - // There are 4 vertices from bounding rect, max 2 from adding split line - // to two corners and curl consists of max mMaxCurlSplits lines each - // outputting 2 vertices. - int maxVerticesCount = 4 + 2 + (2 * mMaxCurlSplits); - ByteBuffer vbb = ByteBuffer.allocateDirect(maxVerticesCount * 3 * 4); - vbb.order(ByteOrder.nativeOrder()); - mBufVertices = vbb.asFloatBuffer(); - mBufVertices.position(0); - - if (DRAW_TEXTURE) { - ByteBuffer tbb = ByteBuffer - .allocateDirect(maxVerticesCount * 2 * 4); - tbb.order(ByteOrder.nativeOrder()); - mBufTexCoords = tbb.asFloatBuffer(); - mBufTexCoords.position(0); - } - - ByteBuffer cbb = ByteBuffer.allocateDirect(maxVerticesCount * 4 * 4); - cbb.order(ByteOrder.nativeOrder()); - mBufColors = cbb.asFloatBuffer(); - mBufColors.position(0); - - if (DRAW_SHADOW) { - int maxShadowVerticesCount = (mMaxCurlSplits + 2) * 2 * 2; - ByteBuffer scbb = ByteBuffer - .allocateDirect(maxShadowVerticesCount * 4 * 4); - scbb.order(ByteOrder.nativeOrder()); - mBufShadowColors = scbb.asFloatBuffer(); - mBufShadowColors.position(0); - - ByteBuffer sibb = ByteBuffer - .allocateDirect(maxShadowVerticesCount * 3 * 4); - sibb.order(ByteOrder.nativeOrder()); - mBufShadowVertices = sibb.asFloatBuffer(); - mBufShadowVertices.position(0); - - mDropShadowCount = mSelfShadowCount = 0; - } - } - - /** - * Adds vertex to buffers. - */ - private void addVertex(Vertex vertex) { - mBufVertices.put((float) vertex.mPosX); - mBufVertices.put((float) vertex.mPosY); - mBufVertices.put((float) vertex.mPosZ); - mBufColors.put(vertex.mColorFactor * Color.red(vertex.mColor) / 255f); - mBufColors.put(vertex.mColorFactor * Color.green(vertex.mColor) / 255f); - mBufColors.put(vertex.mColorFactor * Color.blue(vertex.mColor) / 255f); - mBufColors.put(Color.alpha(vertex.mColor) / 255f); - if (DRAW_TEXTURE) { - mBufTexCoords.put((float) vertex.mTexX); - mBufTexCoords.put((float) vertex.mTexY); - } - } - - /** - * Sets curl for this mesh. - * - * @param curlPos Position for curl 'center'. Can be any point on line collinear - * to curl. - * @param curlDir Curl direction, should be normalized. - * @param radius Radius of curl. - */ - public synchronized void curl(PointF curlPos, PointF curlDir, double radius) { - - // First add some 'helper' lines used for development. - if (DRAW_CURL_POSITION) { - mBufCurlPositionLines.position(0); - - mBufCurlPositionLines.put(curlPos.x); - mBufCurlPositionLines.put(curlPos.y - 1.0f); - mBufCurlPositionLines.put(curlPos.x); - mBufCurlPositionLines.put(curlPos.y + 1.0f); - mBufCurlPositionLines.put(curlPos.x - 1.0f); - mBufCurlPositionLines.put(curlPos.y); - mBufCurlPositionLines.put(curlPos.x + 1.0f); - mBufCurlPositionLines.put(curlPos.y); - - mBufCurlPositionLines.put(curlPos.x); - mBufCurlPositionLines.put(curlPos.y); - mBufCurlPositionLines.put(curlPos.x + curlDir.x * 2); - mBufCurlPositionLines.put(curlPos.y + curlDir.y * 2); - - mBufCurlPositionLines.position(0); - } - - // Actual 'curl' implementation starts here. - mBufVertices.position(0); - mBufColors.position(0); - if (DRAW_TEXTURE) { - mBufTexCoords.position(0); - } - - // Calculate curl angle from direction. - double curlAngle = Math.acos(curlDir.x); - curlAngle = curlDir.y > 0 ? -curlAngle : curlAngle; - - // Initiate rotated rectangle which's is translated to curlPos and - // rotated so that curl direction heads to right (1,0). Vertices are - // ordered in ascending order based on x -coordinate at the same time. - // And using y -coordinate in very rare case in which two vertices have - // same x -coordinate. - mArrTempVertices.addAll(mArrRotatedVertices); - mArrRotatedVertices.clear(); - for (int i = 0; i < 4; ++i) { - Vertex v = mArrTempVertices.remove(0); - v.set(mRectangle[i]); - v.translate(-curlPos.x, -curlPos.y); - v.rotateZ(-curlAngle); - int j = 0; - for (; j < mArrRotatedVertices.size(); ++j) { - Vertex v2 = mArrRotatedVertices.get(j); - if (v.mPosX > v2.mPosX) { - break; - } - if (v.mPosX == v2.mPosX && v.mPosY > v2.mPosY) { - break; - } - } - mArrRotatedVertices.add(j, v); - } - - // Rotated rectangle lines/vertex indices. We need to find bounding - // lines for rotated rectangle. After sorting vertices according to - // their x -coordinate we don't have to worry about vertices at indices - // 0 and 1. But due to inaccuracy it's possible vertex 3 is not the - // opposing corner from vertex 0. So we are calculating distance from - // vertex 0 to vertices 2 and 3 - and altering line indices if needed. - // Also vertices/lines are given in an order first one has x -coordinate - // at least the latter one. This property is used in getIntersections to - // see if there is an intersection. - int[][] lines = {{0, 1}, {0, 2}, {1, 3}, {2, 3}}; - { - // TODO: There really has to be more 'easier' way of doing this - - // not including extensive use of sqrt. - Vertex v0 = mArrRotatedVertices.get(0); - Vertex v2 = mArrRotatedVertices.get(2); - Vertex v3 = mArrRotatedVertices.get(3); - double dist2 = Math.sqrt((v0.mPosX - v2.mPosX) - * (v0.mPosX - v2.mPosX) + (v0.mPosY - v2.mPosY) - * (v0.mPosY - v2.mPosY)); - double dist3 = Math.sqrt((v0.mPosX - v3.mPosX) - * (v0.mPosX - v3.mPosX) + (v0.mPosY - v3.mPosY) - * (v0.mPosY - v3.mPosY)); - if (dist2 > dist3) { - lines[1][1] = 3; - lines[2][1] = 2; - } - } - - mVerticesCountFront = mVerticesCountBack = 0; - - if (DRAW_SHADOW) { - mArrTempShadowVertices.addAll(mArrDropShadowVertices); - mArrTempShadowVertices.addAll(mArrSelfShadowVertices); - mArrDropShadowVertices.clear(); - mArrSelfShadowVertices.clear(); - } - - // Length of 'curl' curve. - double curlLength = Math.PI * radius; - // Calculate scan lines. - // TODO: Revisit this code one day. There is room for optimization here. - mArrScanLines.clear(); - if (mMaxCurlSplits > 0) { - mArrScanLines.add((double) 0); - } - for (int i = 1; i < mMaxCurlSplits; ++i) { - mArrScanLines.add((-curlLength * i) / (mMaxCurlSplits - 1)); - } - // As mRotatedVertices is ordered regarding x -coordinate, adding - // this scan line produces scan area picking up vertices which are - // rotated completely. One could say 'until infinity'. - mArrScanLines.add(mArrRotatedVertices.get(3).mPosX - 1); - - // Start from right most vertex. Pretty much the same as first scan area - // is starting from 'infinity'. - double scanXmax = mArrRotatedVertices.get(0).mPosX + 1; - - for (int i = 0; i < mArrScanLines.size(); ++i) { - // Once we have scanXmin and scanXmax we have a scan area to start - // working with. - double scanXmin = mArrScanLines.get(i); - // First iterate 'original' rectangle vertices within scan area. - for (int j = 0; j < mArrRotatedVertices.size(); ++j) { - Vertex v = mArrRotatedVertices.get(j); - // Test if vertex lies within this scan area. - // TODO: Frankly speaking, can't remember why equality check was - // added to both ends. Guessing it was somehow related to case - // where radius=0f, which, given current implementation, could - // be handled much more effectively anyway. - if (v.mPosX >= scanXmin && v.mPosX <= scanXmax) { - // Pop out a vertex from temp vertices. - Vertex n = mArrTempVertices.remove(0); - n.set(v); - // This is done solely for triangulation reasons. Given a - // rotated rectangle it has max 2 vertices having - // intersection. - Array intersections = getIntersections( - mArrRotatedVertices, lines, n.mPosX); - // In a sense one could say we're adding vertices always in - // two, positioned at the ends of intersecting line. And for - // triangulation to work properly they are added based on y - // -coordinate. And this if-else is doing it for us. - if (intersections.size() == 1 - && intersections.get(0).mPosY > v.mPosY) { - // In case intersecting vertex is higher add it first. - mArrOutputVertices.addAll(intersections); - mArrOutputVertices.add(n); - } else if (intersections.size() <= 1) { - // Otherwise add original vertex first. - mArrOutputVertices.add(n); - mArrOutputVertices.addAll(intersections); - } else { - // There should never be more than 1 intersecting - // vertex. But if it happens as a fallback simply skip - // everything. - mArrTempVertices.add(n); - mArrTempVertices.addAll(intersections); - } - } - } - - // Search for scan line intersections. - Array intersections = getIntersections(mArrRotatedVertices, - lines, scanXmin); - - // We expect to get 0 or 2 vertices. In rare cases there's only one - // but in general given a scan line intersecting rectangle there - // should be 2 intersecting vertices. - if (intersections.size() == 2) { - // There were two intersections, add them based on y - // -coordinate, higher first, lower last. - Vertex v1 = intersections.get(0); - Vertex v2 = intersections.get(1); - if (v1.mPosY < v2.mPosY) { - mArrOutputVertices.add(v2); - mArrOutputVertices.add(v1); - } else { - mArrOutputVertices.addAll(intersections); - } - } else if (intersections.size() != 0) { - // This happens in a case in which there is a original vertex - // exactly at scan line or something went very much wrong if - // there are 3+ vertices. What ever the reason just return the - // vertices to temp vertices for later use. In former case it - // was handled already earlier once iterating through - // mRotatedVertices, in latter case it's better to avoid doing - // anything with them. - mArrTempVertices.addAll(intersections); - } - - // Add vertices found during this iteration to vertex etc buffers. - while (mArrOutputVertices.size() > 0) { - Vertex v = mArrOutputVertices.remove(0); - mArrTempVertices.add(v); - - // Local texture front-facing flag. - boolean textureFront; - - // Untouched vertices. - if (i == 0) { - textureFront = true; - mVerticesCountFront++; - } - // 'Completely' rotated vertices. - else if (i == mArrScanLines.size() - 1 || curlLength == 0) { - v.mPosX = -(curlLength + v.mPosX); - v.mPosZ = 2 * radius; - v.mPenumbraX = -v.mPenumbraX; - - textureFront = false; - mVerticesCountBack++; - } - // Vertex lies within 'curl'. - else { - // Even though it's not obvious from the if-else clause, - // here v.mPosX is between [-curlLength, 0]. And we can do - // calculations around a half cylinder. - double rotY = Math.PI * (v.mPosX / curlLength); - v.mPosX = radius * Math.sin(rotY); - v.mPosZ = radius - (radius * Math.cos(rotY)); - v.mPenumbraX *= Math.cos(rotY); - // Map color multiplier to [.1f, 1f] range. - v.mColorFactor = (float) (.1f + .9f * Math.sqrt(Math - .sin(rotY) + 1)); - - if (v.mPosZ >= radius) { - textureFront = false; - mVerticesCountBack++; - } else { - textureFront = true; - mVerticesCountFront++; - } - } - - // We use local textureFront for flipping backside texture - // locally. Plus additionally if mesh is in flip texture mode, - // we'll make the procedure "backwards". Also, until this point, - // texture coordinates are within [0, 1] range so we'll adjust - // them to final texture coordinates too. - if (textureFront != mFlipTexture) { - v.mTexX *= mTextureRectFront.right; - v.mTexY *= mTextureRectFront.bottom; - v.mColor = mTexturePage.getColor(CurlPage.SIDE_FRONT); - } else { - v.mTexX *= mTextureRectBack.right; - v.mTexY *= mTextureRectBack.bottom; - v.mColor = mTexturePage.getColor(CurlPage.SIDE_BACK); - } - - // Move vertex back to 'world' coordinates. - v.rotateZ(curlAngle); - v.translate(curlPos.x, curlPos.y); - addVertex(v); - - // Drop shadow is cast 'behind' the curl. - if (DRAW_SHADOW && v.mPosZ > 0 && v.mPosZ <= radius) { - ShadowVertex sv = mArrTempShadowVertices.remove(0); - sv.mPosX = v.mPosX; - sv.mPosY = v.mPosY; - sv.mPosZ = v.mPosZ; - sv.mPenumbraX = (v.mPosZ / 2) * -curlDir.x; - sv.mPenumbraY = (v.mPosZ / 2) * -curlDir.y; - sv.mPenumbraColor = v.mPosZ / radius; - int idx = (mArrDropShadowVertices.size() + 1) / 2; - mArrDropShadowVertices.add(idx, sv); - } - // Self shadow is cast partly over mesh. - if (DRAW_SHADOW && v.mPosZ > radius) { - ShadowVertex sv = mArrTempShadowVertices.remove(0); - sv.mPosX = v.mPosX; - sv.mPosY = v.mPosY; - sv.mPosZ = v.mPosZ; - sv.mPenumbraX = ((v.mPosZ - radius) / 3) * v.mPenumbraX; - sv.mPenumbraY = ((v.mPosZ - radius) / 3) * v.mPenumbraY; - sv.mPenumbraColor = (v.mPosZ - radius) / (2 * radius); - int idx = (mArrSelfShadowVertices.size() + 1) / 2; - mArrSelfShadowVertices.add(idx, sv); - } - } - - // Switch scanXmin as scanXmax for next iteration. - scanXmax = scanXmin; - } - - mBufVertices.position(0); - mBufColors.position(0); - if (DRAW_TEXTURE) { - mBufTexCoords.position(0); - } - - // Add shadow Vertices. - if (DRAW_SHADOW) { - mBufShadowColors.position(0); - mBufShadowVertices.position(0); - mDropShadowCount = 0; - - for (int i = 0; i < mArrDropShadowVertices.size(); ++i) { - ShadowVertex sv = mArrDropShadowVertices.get(i); - mBufShadowVertices.put((float) sv.mPosX); - mBufShadowVertices.put((float) sv.mPosY); - mBufShadowVertices.put((float) sv.mPosZ); - mBufShadowVertices.put((float) (sv.mPosX + sv.mPenumbraX)); - mBufShadowVertices.put((float) (sv.mPosY + sv.mPenumbraY)); - mBufShadowVertices.put((float) sv.mPosZ); - for (int j = 0; j < 4; ++j) { - double color = SHADOW_OUTER_COLOR[j] - + (SHADOW_INNER_COLOR[j] - SHADOW_OUTER_COLOR[j]) - * sv.mPenumbraColor; - mBufShadowColors.put((float) color); - } - mBufShadowColors.put(SHADOW_OUTER_COLOR); - mDropShadowCount += 2; - } - mSelfShadowCount = 0; - for (int i = 0; i < mArrSelfShadowVertices.size(); ++i) { - ShadowVertex sv = mArrSelfShadowVertices.get(i); - mBufShadowVertices.put((float) sv.mPosX); - mBufShadowVertices.put((float) sv.mPosY); - mBufShadowVertices.put((float) sv.mPosZ); - mBufShadowVertices.put((float) (sv.mPosX + sv.mPenumbraX)); - mBufShadowVertices.put((float) (sv.mPosY + sv.mPenumbraY)); - mBufShadowVertices.put((float) sv.mPosZ); - for (int j = 0; j < 4; ++j) { - double color = SHADOW_OUTER_COLOR[j] - + (SHADOW_INNER_COLOR[j] - SHADOW_OUTER_COLOR[j]) - * sv.mPenumbraColor; - mBufShadowColors.put((float) color); - } - mBufShadowColors.put(SHADOW_OUTER_COLOR); - mSelfShadowCount += 2; - } - mBufShadowColors.position(0); - mBufShadowVertices.position(0); - } - } - - /** - * Calculates intersections for given scan line. - */ - private Array getIntersections(Array vertices, - int[][] lineIndices, double scanX) { - mArrIntersections.clear(); - // Iterate through rectangle lines each re-presented as a pair of - // vertices. - for (int[] lineIndex : lineIndices) { - Vertex v1 = vertices.get(lineIndex[0]); - Vertex v2 = vertices.get(lineIndex[1]); - // Here we expect that v1.mPosX >= v2.mPosX and wont do intersection - // test the opposite way. - if (v1.mPosX > scanX && v2.mPosX < scanX) { - // There is an intersection, calculate coefficient telling 'how - // far' scanX is from v2. - double c = (scanX - v2.mPosX) / (v1.mPosX - v2.mPosX); - Vertex n = mArrTempVertices.remove(0); - n.set(v2); - n.mPosX = scanX; - n.mPosY += (v1.mPosY - v2.mPosY) * c; - if (DRAW_TEXTURE) { - n.mTexX += (v1.mTexX - v2.mTexX) * c; - n.mTexY += (v1.mTexY - v2.mTexY) * c; - } - if (DRAW_SHADOW) { - n.mPenumbraX += (v1.mPenumbraX - v2.mPenumbraX) * c; - n.mPenumbraY += (v1.mPenumbraY - v2.mPenumbraY) * c; - } - mArrIntersections.add(n); - } - } - return mArrIntersections; - } - - /** - * Getter for textures page for this mesh. - */ - public synchronized CurlPage getTexturePage() { - return mTexturePage; - } - - /** - * Renders our page curl mesh. - */ - public synchronized void onDrawFrame(GL10 gl) { - // First allocate texture if there is not one yet. - if (DRAW_TEXTURE && mTextureIds == null) { - // Generate texture. - mTextureIds = new int[2]; - gl.glGenTextures(2, mTextureIds, 0); - for (int textureId : mTextureIds) { - // Set texture attributes. - gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId); - gl.glTexParameterf(GL10.GL_TEXTURE_2D, - GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); - gl.glTexParameterf(GL10.GL_TEXTURE_2D, - GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_NEAREST); - gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, - GL10.GL_CLAMP_TO_EDGE); - gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, - GL10.GL_CLAMP_TO_EDGE); - } - } - - if (DRAW_TEXTURE && mTexturePage.getTexturesChanged()) { - gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIds[0]); - Bitmap texture = mTexturePage.getTexture(mTextureRectFront, - CurlPage.SIDE_FRONT); - GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, texture, 0); - texture.recycle(); - - mTextureBack = mTexturePage.hasBackTexture(); - if (mTextureBack) { - gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIds[1]); - texture = mTexturePage.getTexture(mTextureRectBack, - CurlPage.SIDE_BACK); - GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, texture, 0); - texture.recycle(); - } else { - mTextureRectBack.set(mTextureRectFront); - } - - mTexturePage.recycle(); - reset(); - } - - // Some 'global' settings. - gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); - - // TODO: Drop shadow drawing is done temporarily here to hide some - // problems with its calculation. - if (DRAW_SHADOW) { - gl.glDisable(GL10.GL_TEXTURE_2D); - gl.glEnable(GL10.GL_BLEND); - gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); - gl.glEnableClientState(GL10.GL_COLOR_ARRAY); - gl.glColorPointer(4, GL10.GL_FLOAT, 0, mBufShadowColors); - gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mBufShadowVertices); - gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, mDropShadowCount); - gl.glDisableClientState(GL10.GL_COLOR_ARRAY); - gl.glDisable(GL10.GL_BLEND); - } - - if (DRAW_TEXTURE) { - gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); - gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mBufTexCoords); - } - gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mBufVertices); - // Enable color array. - gl.glEnableClientState(GL10.GL_COLOR_ARRAY); - gl.glColorPointer(4, GL10.GL_FLOAT, 0, mBufColors); - - // Draw front facing blank vertices. - gl.glDisable(GL10.GL_TEXTURE_2D); - gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, mVerticesCountFront); - - // Draw front facing texture. - if (DRAW_TEXTURE) { - gl.glEnable(GL10.GL_BLEND); - gl.glEnable(GL10.GL_TEXTURE_2D); - - if (!mFlipTexture || !mTextureBack) { - gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIds[0]); - } else { - gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIds[1]); - } - - gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); - gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, mVerticesCountFront); - - gl.glDisable(GL10.GL_BLEND); - gl.glDisable(GL10.GL_TEXTURE_2D); - } - - int backStartIdx = Math.max(0, mVerticesCountFront - 2); - int backCount = mVerticesCountFront + mVerticesCountBack - backStartIdx; - - // Draw back facing blank vertices. - gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, backStartIdx, backCount); - - // Draw back facing texture. - if (DRAW_TEXTURE) { - gl.glEnable(GL10.GL_BLEND); - gl.glEnable(GL10.GL_TEXTURE_2D); - - if (mFlipTexture || !mTextureBack) { - gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIds[0]); - } else { - gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIds[1]); - } - - gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); - gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, backStartIdx, backCount); - - gl.glDisable(GL10.GL_BLEND); - gl.glDisable(GL10.GL_TEXTURE_2D); - } - - // Disable textures and color array. - gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); - gl.glDisableClientState(GL10.GL_COLOR_ARRAY); - - if (DRAW_POLYGON_OUTLINES) { - gl.glEnable(GL10.GL_BLEND); - gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); - gl.glLineWidth(1.0f); - gl.glColor4f(0.5f, 0.5f, 1.0f, 1.0f); - gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mBufVertices); - gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, mVerticesCountFront); - gl.glDisable(GL10.GL_BLEND); - } - - if (DRAW_CURL_POSITION) { - gl.glEnable(GL10.GL_BLEND); - gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); - gl.glLineWidth(1.0f); - gl.glColor4f(1.0f, 0.5f, 0.5f, 1.0f); - gl.glVertexPointer(2, GL10.GL_FLOAT, 0, mBufCurlPositionLines); - gl.glDrawArrays(GL10.GL_LINES, 0, mCurlPositionLinesCount * 2); - gl.glDisable(GL10.GL_BLEND); - } - - if (DRAW_SHADOW) { - gl.glEnable(GL10.GL_BLEND); - gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); - gl.glEnableClientState(GL10.GL_COLOR_ARRAY); - gl.glColorPointer(4, GL10.GL_FLOAT, 0, mBufShadowColors); - gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mBufShadowVertices); - gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, mDropShadowCount, - mSelfShadowCount); - gl.glDisableClientState(GL10.GL_COLOR_ARRAY); - gl.glDisable(GL10.GL_BLEND); - } - - gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); - } - - /** - * Resets mesh to 'initial' state. Meaning this mesh will draw a plain - * textured rectangle after call to this method. - */ - public synchronized void reset() { - mBufVertices.position(0); - mBufColors.position(0); - if (DRAW_TEXTURE) { - mBufTexCoords.position(0); - } - for (int i = 0; i < 4; ++i) { - Vertex tmp = mArrTempVertices.get(0); - tmp.set(mRectangle[i]); - - if (mFlipTexture) { - tmp.mTexX *= mTextureRectBack.right; - tmp.mTexY *= mTextureRectBack.bottom; - tmp.mColor = mTexturePage.getColor(CurlPage.SIDE_BACK); - } else { - tmp.mTexX *= mTextureRectFront.right; - tmp.mTexY *= mTextureRectFront.bottom; - tmp.mColor = mTexturePage.getColor(CurlPage.SIDE_FRONT); - } - - addVertex(tmp); - } - mVerticesCountFront = 4; - mVerticesCountBack = 0; - mBufVertices.position(0); - mBufColors.position(0); - if (DRAW_TEXTURE) { - mBufTexCoords.position(0); - } - - mDropShadowCount = mSelfShadowCount = 0; - } - - /** - * Resets allocated texture id forcing creation of new one. After calling - * this method you most likely want to set bitmap too as it's lost. This - * method should be called only once e.g GL context is re-created as this - * method does not release previous texture id, only makes sure new one is - * requested on next render. - */ - public synchronized void resetTexture() { - mTextureIds = null; - } - - /** - * If true, flips texture sideways. - */ - public synchronized void setFlipTexture(boolean flipTexture) { - mFlipTexture = flipTexture; - if (flipTexture) { - setTexCoords(1f, 0f, 0f, 1f); - } else { - setTexCoords(0f, 0f, 1f, 1f); - } - } - - /** - * Update mesh bounds. - */ - public void setRect(RectF r) { - mRectangle[0].mPosX = r.left; - mRectangle[0].mPosY = r.top; - mRectangle[1].mPosX = r.left; - mRectangle[1].mPosY = r.bottom; - mRectangle[2].mPosX = r.right; - mRectangle[2].mPosY = r.top; - mRectangle[3].mPosX = r.right; - mRectangle[3].mPosY = r.bottom; - } - - /** - * Sets texture coordinates to mRectangle vertices. - */ - private synchronized void setTexCoords(float left, float top, float right, - float bottom) { - mRectangle[0].mTexX = left; - mRectangle[0].mTexY = top; - mRectangle[1].mTexX = left; - mRectangle[1].mTexY = bottom; - mRectangle[2].mTexX = right; - mRectangle[2].mTexY = top; - mRectangle[3].mTexX = right; - mRectangle[3].mTexY = bottom; - } - - /** - * Simple fixed size array implementation. - */ - private class Array { - private Object[] mArray; - private int mCapacity; - private int mSize; - - Array(int capacity) { - mCapacity = capacity; - mArray = new Object[capacity]; - } - - public void add(int index, T item) { - if (index < 0 || index > mSize || mSize >= mCapacity) { - throw new IndexOutOfBoundsException(); - } - System.arraycopy(mArray, index, mArray, index + 1, mSize - index); - mArray[index] = item; - ++mSize; - } - - public void add(T item) { - if (mSize >= mCapacity) { - throw new IndexOutOfBoundsException(); - } - mArray[mSize++] = item; - } - - public void addAll(Array array) { - if (mSize + array.size() > mCapacity) { - throw new IndexOutOfBoundsException(); - } - for (int i = 0; i < array.size(); ++i) { - mArray[mSize++] = array.get(i); - } - } - - public void clear() { - mSize = 0; - } - - @SuppressWarnings("unchecked") - public T get(int index) { - if (index < 0 || index >= mSize) { - throw new IndexOutOfBoundsException(); - } - return (T) mArray[index]; - } - - @SuppressWarnings("unchecked") - public T remove(int index) { - if (index < 0 || index >= mSize) { - throw new IndexOutOfBoundsException(); - } - T item = (T) mArray[index]; - if (mSize - 1 - index >= 0) - System.arraycopy(mArray, index + 1, mArray, index, mSize - 1 - index); - --mSize; - return item; - } - - public int size() { - return mSize; - } - - } - - /** - * Holder for shadow vertex information. - */ - private class ShadowVertex { - double mPenumbraColor; - double mPenumbraX; - double mPenumbraY; - double mPosX; - double mPosY; - double mPosZ; - } - - /** - * Holder for vertex information. - */ - private class Vertex { - int mColor; - float mColorFactor; - double mPenumbraX; - double mPenumbraY; - double mPosX; - double mPosY; - double mPosZ; - double mTexX; - double mTexY; - - Vertex() { - mPosX = mPosY = mPosZ = mTexX = mTexY = 0; - mColorFactor = 1.0f; - } - - void rotateZ(double theta) { - double cos = Math.cos(theta); - double sin = Math.sin(theta); - double x = mPosX * cos + mPosY * sin; - double y = mPosX * -sin + mPosY * cos; - mPosX = x; - mPosY = y; - double px = mPenumbraX * cos + mPenumbraY * sin; - double py = mPenumbraX * -sin + mPenumbraY * cos; - mPenumbraX = px; - mPenumbraY = py; - } - - public void set(Vertex vertex) { - mPosX = vertex.mPosX; - mPosY = vertex.mPosY; - mPosZ = vertex.mPosZ; - mTexX = vertex.mTexX; - mTexY = vertex.mTexY; - mPenumbraX = vertex.mPenumbraX; - mPenumbraY = vertex.mPenumbraY; - mColor = vertex.mColor; - mColorFactor = vertex.mColorFactor; - } - - public void translate(double dx, double dy) { - mPosX += dx; - mPosY += dy; - } - } -} diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/curl/CurlPage.kt b/app/src/main/java/io/legado/app/ui/book/read/page/curl/CurlPage.kt deleted file mode 100644 index 88f2fb16c..000000000 --- a/app/src/main/java/io/legado/app/ui/book/read/page/curl/CurlPage.kt +++ /dev/null @@ -1,191 +0,0 @@ -package io.legado.app.ui.book.read.page.curl - -import android.graphics.Bitmap -import android.graphics.Canvas -import android.graphics.Color -import android.graphics.RectF - -/** - * Storage class for page textures, blend colors and possibly some other values - * in the future. - * - * @author harism - */ -class CurlPage { - - private var mColorBack: Int = 0 - private var mColorFront: Int = 0 - private var mTextureBack: Bitmap? = null - private var mTextureFront: Bitmap? = null - /** - * Returns true if textures have changed. - */ - var texturesChanged: Boolean = false - private set - - /** - * Default constructor. - */ - init { - reset() - } - - /** - * Getter for color. - */ - fun getColor(side: Int): Int { - return when (side) { - SIDE_FRONT -> mColorFront - else -> mColorBack - } - } - - /** - * Calculates the next highest power of two for a given integer. - */ - private fun getNextHighestPO2(n: Int): Int { - var n1 = n - n1 -= 1 - n1 = n1 or (n1 shr 1) - n1 = n1 or (n1 shr 2) - n1 = n1 or (n1 shr 4) - n1 = n1 or (n1 shr 8) - n1 = n1 or (n1 shr 16) - n1 = n1 or (n1 shr 32) - return n1 + 1 - } - - /** - * Generates nearest power of two sized Bitmap for give Bitmap. Returns this - * new Bitmap using default return statement + original texture coordinates - * are stored into RectF. - */ - private fun getTexture(bitmap: Bitmap, textureRect: RectF): Bitmap { - // Bitmap original size. - val w = bitmap.width - val h = bitmap.height - // Bitmap size expanded to next power of two. This is done due to - // the requirement on many devices, texture width and height should - // be power of two. - val newW = getNextHighestPO2(w) - val newH = getNextHighestPO2(h) - - // TODO: Is there another way to create a bigger Bitmap and copy - // original Bitmap to it more efficiently? Immutable bitmap anyone? - val bitmapTex = Bitmap.createBitmap(newW, newH, bitmap.config) - val c = Canvas(bitmapTex) - c.drawBitmap(bitmap, 0f, 0f, null) - - // Calculate final texture coordinates. - val texX = w.toFloat() / newW - val texY = h.toFloat() / newH - textureRect.set(0f, 0f, texX, texY) - - return bitmapTex - } - - /** - * Getter for textures. Creates Bitmap sized to nearest power of two, copies - * original Bitmap into it and returns it. RectF given as parameter is - * filled with actual texture coordinates in this new upscaled texture - * Bitmap. - */ - fun getTexture(textureRect: RectF, side: Int): Bitmap { - return when (side) { - SIDE_FRONT -> getTexture(mTextureFront!!, textureRect) - else -> getTexture(mTextureBack!!, textureRect) - } - } - - /** - * Returns true if back siding texture exists and it differs from front - * facing one. - */ - fun hasBackTexture(): Boolean { - return mTextureFront != mTextureBack - } - - /** - * Recycles and frees underlying Bitmaps. - */ - fun recycle() { - if (mTextureFront != null) { - mTextureFront!!.recycle() - } - mTextureFront = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565) - mTextureFront!!.eraseColor(mColorFront) - if (mTextureBack != null) { - mTextureBack!!.recycle() - } - mTextureBack = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565) - mTextureBack!!.eraseColor(mColorBack) - texturesChanged = false - } - - /** - * Resets this CurlPage into its initial state. - */ - fun reset() { - mColorBack = Color.WHITE - mColorFront = Color.WHITE - recycle() - } - - /** - * Setter blend color. - */ - fun setColor(color: Int, side: Int) { - when (side) { - SIDE_FRONT -> mColorFront = color - SIDE_BACK -> mColorBack = color - else -> { - mColorBack = color - mColorFront = mColorBack - } - } - } - - /** - * Setter for textures. - */ - fun setTexture(texture: Bitmap?, side: Int) { - var texture1 = texture - if (texture1 == null) { - texture1 = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565) - if (side == SIDE_BACK) { - texture1!!.eraseColor(mColorBack) - } else { - texture1!!.eraseColor(mColorFront) - } - } - when (side) { - SIDE_FRONT -> { - if (mTextureFront != null) - mTextureFront!!.recycle() - mTextureFront = texture1 - } - SIDE_BACK -> { - if (mTextureBack != null) - mTextureBack!!.recycle() - mTextureBack = texture1 - } - SIDE_BOTH -> { - if (mTextureFront != null) - mTextureFront!!.recycle() - if (mTextureBack != null) - mTextureBack!!.recycle() - mTextureBack = texture1 - mTextureFront = mTextureBack - } - } - texturesChanged = true - } - - companion object { - - const val SIDE_BACK = 2 - const val SIDE_BOTH = 3 - const val SIDE_FRONT = 1 - } - -} diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/curl/CurlRenderer.kt b/app/src/main/java/io/legado/app/ui/book/read/page/curl/CurlRenderer.kt deleted file mode 100644 index 6d44ee1ee..000000000 --- a/app/src/main/java/io/legado/app/ui/book/read/page/curl/CurlRenderer.kt +++ /dev/null @@ -1,221 +0,0 @@ -package io.legado.app.ui.book.read.page.curl - -import android.graphics.Color -import android.graphics.PointF -import android.graphics.RectF -import android.opengl.GLSurfaceView -import android.opengl.GLU -import java.util.* -import javax.microedition.khronos.egl.EGLConfig -import javax.microedition.khronos.opengles.GL10 - -/** - * Actual renderer class. - * - * @author harism - */ -class CurlRenderer(private val mObserver: Observer) : GLSurfaceView.Renderer { - // Background fill color. - private var mBackgroundColor: Int = 0 - // Curl meshes used for static and dynamic rendering. - private val mCurlMeshes: Vector = Vector() - private val mMargins = RectF() - // Page rectangles. - private val mPageRectLeft: RectF = RectF() - private val mPageRectRight: RectF = RectF() - // View mode. - private var mViewMode = SHOW_ONE_PAGE - // Screen size. - private var mViewportWidth: Int = 0 - private var mViewportHeight: Int = 0 - // Rect for render area. - private val mViewRect = RectF() - - /** - * Adds CurlMesh to this renderer. - */ - @Synchronized - fun addCurlMesh(mesh: CurlMesh) { - removeCurlMesh(mesh) - mCurlMeshes.add(mesh) - } - - /** - * Returns rect reserved for left or right page. Value page should be - * PAGE_LEFT or PAGE_RIGHT. - */ - fun getPageRect(page: Int): RectF? { - if (page == PAGE_LEFT) { - return mPageRectLeft - } else if (page == PAGE_RIGHT) { - return mPageRectRight - } - return null - } - - @Synchronized - override fun onDrawFrame(gl: GL10) { - - mObserver.onDrawFrame() - - gl.glClearColor( - Color.red(mBackgroundColor) / 255f, - Color.green(mBackgroundColor) / 255f, - Color.blue(mBackgroundColor) / 255f, - Color.alpha(mBackgroundColor) / 255f - ) - gl.glClear(GL10.GL_COLOR_BUFFER_BIT) - gl.glLoadIdentity() - - if (!mObserver.canDraw) { - return - } - - for (i in mCurlMeshes.indices) { - mCurlMeshes[i].onDrawFrame(gl) - } - } - - override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) { - gl.glViewport(0, 0, width, height) - mViewportWidth = width - mViewportHeight = height - - val ratio = width.toFloat() / height - mViewRect.top = 1.0f - mViewRect.bottom = -1.0f - mViewRect.left = -ratio - mViewRect.right = ratio - updatePageRect() - - gl.glMatrixMode(GL10.GL_PROJECTION) - gl.glLoadIdentity() - GLU.gluOrtho2D( - gl, mViewRect.left, mViewRect.right, - mViewRect.bottom, mViewRect.top - ) - - gl.glMatrixMode(GL10.GL_MODELVIEW) - gl.glLoadIdentity() - } - - override fun onSurfaceCreated(gl: GL10, config: EGLConfig) { - gl.glClearColor(0f, 0f, 0f, 1f) - gl.glShadeModel(GL10.GL_SMOOTH) - gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST) - gl.glHint(GL10.GL_LINE_SMOOTH_HINT, GL10.GL_NICEST) - gl.glHint(GL10.GL_POLYGON_SMOOTH_HINT, GL10.GL_NICEST) - gl.glEnable(GL10.GL_LINE_SMOOTH) - gl.glDisable(GL10.GL_DEPTH_TEST) - gl.glDisable(GL10.GL_CULL_FACE) - - mObserver.onSurfaceCreated() - } - - /** - * Removes CurlMesh from this renderer. - */ - @Synchronized - fun removeCurlMesh(mesh: CurlMesh) { - mCurlMeshes.remove(mesh) - } - - /** - * Sets visible page count to one or two. Should be either SHOW_ONE_PAGE or - * SHOW_TWO_PAGES. - */ - @Synchronized - fun setViewMode(viewMode: Int) { - if (viewMode == SHOW_ONE_PAGE) { - mViewMode = viewMode - updatePageRect() - } else if (viewMode == SHOW_TWO_PAGES) { - mViewMode = viewMode - updatePageRect() - } - } - - /** - * Translates screen coordinates into view coordinates. - */ - fun translate(pt: PointF) { - pt.x = mViewRect.left + mViewRect.width() * pt.x / mViewportWidth - pt.y = mViewRect.top - -mViewRect.height() * pt.y / mViewportHeight - } - - /** - * Recalculates page rectangles. - */ - private fun updatePageRect() { - if (mViewRect.width() == 0f || mViewRect.height() == 0f) { - return - } else if (mViewMode == SHOW_ONE_PAGE) { - mPageRectRight.set(mViewRect) - mPageRectRight.left += mViewRect.width() * mMargins.left - mPageRectRight.right -= mViewRect.width() * mMargins.right - mPageRectRight.top += mViewRect.height() * mMargins.top - mPageRectRight.bottom -= mViewRect.height() * mMargins.bottom - - mPageRectLeft.set(mPageRectRight) - mPageRectLeft.offset(-mPageRectRight.width(), 0f) - - val bitmapW = (mPageRectRight.width() * mViewportWidth / mViewRect - .width()).toInt() - val bitmapH = (mPageRectRight.height() * mViewportHeight / mViewRect - .height()).toInt() - mObserver.onPageSizeChanged(bitmapW, bitmapH) - } else if (mViewMode == SHOW_TWO_PAGES) { - mPageRectRight.set(mViewRect) - mPageRectRight.left += mViewRect.width() * mMargins.left - mPageRectRight.right -= mViewRect.width() * mMargins.right - mPageRectRight.top += mViewRect.height() * mMargins.top - mPageRectRight.bottom -= mViewRect.height() * mMargins.bottom - - mPageRectLeft.set(mPageRectRight) - mPageRectLeft.right = (mPageRectLeft.right + mPageRectLeft.left) / 2 - mPageRectRight.left = mPageRectLeft.right - - val bitmapW = (mPageRectRight.width() * mViewportWidth / mViewRect - .width()).toInt() - val bitmapH = (mPageRectRight.height() * mViewportHeight / mViewRect - .height()).toInt() - mObserver.onPageSizeChanged(bitmapW, bitmapH) - } - } - - /** - * Observer for waiting render engine/state updates. - */ - interface Observer { - /** - * Called from onDrawFrame called before rendering is started. This is - * intended to be used for animation purposes. - */ - fun onDrawFrame() - - /** - * Called once page size is changed. Width and height tell the page size - * in pixels making it possible to update textures accordingly. - */ - fun onPageSizeChanged(width: Int, height: Int) - - /** - * Called from onSurfaceCreated to enable texture re-initialization etc - * what needs to be done when this happens. - */ - fun onSurfaceCreated() - - var canDraw: Boolean - } - - companion object { - - // Constant for requesting left page rect. - const val PAGE_LEFT = 1 - // Constant for requesting right page rect. - const val PAGE_RIGHT = 2 - // Constants for changing view mode. - const val SHOW_ONE_PAGE = 1 - const val SHOW_TWO_PAGES = 2 - } -} diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/curl/CurlView.kt b/app/src/main/java/io/legado/app/ui/book/read/page/curl/CurlView.kt deleted file mode 100644 index ecd5d410d..000000000 --- a/app/src/main/java/io/legado/app/ui/book/read/page/curl/CurlView.kt +++ /dev/null @@ -1,769 +0,0 @@ -package io.legado.app.ui.book.read.page.curl - -import android.content.Context -import android.graphics.PixelFormat -import android.graphics.PointF -import android.opengl.GLSurfaceView -import android.util.AttributeSet -import android.view.MotionEvent -import android.view.View -import kotlin.math.max -import kotlin.math.min -import kotlin.math.sin -import kotlin.math.sqrt - -/** - * OpenGL ES View. - * - * @author harism - */ -class CurlView : GLSurfaceView, View.OnTouchListener, CurlRenderer.Observer { - var callBack: CallBack? = null - private var mAllowLastPageCurl = true - - private var mAnimate = false - private val mAnimationDurationTime: Long = 300 - private val mAnimationSource = PointF() - private var mAnimationStartTime: Long = 0 - private val mAnimationTarget = PointF() - private var mAnimationTargetEvent: Int = 0 - - private val mCurlDir = PointF() - - private val mCurlPos = PointF() - private var mCurlState = CURL_NONE - // Current bitmap index. This is always showed as front of right page. - private var mCurrentIndex = 0 - - // Start position for dragging. - private val mDragStartPos = PointF() - - private var mEnableTouchPressure = false - // Bitmap size. These are updated from renderer once it's initialized. - private var mPageBitmapHeight = -1 - - private var mPageBitmapWidth = -1 - // Page meshes. Left and right meshes are 'static' while curl is used to - // show page flipping. - private var mPageCurl: CurlMesh - private var mPageLeft: CurlMesh - private var mPageRight: CurlMesh - - private val mPointerPos = PointerPosition() - - private var mRenderer: CurlRenderer = CurlRenderer(this) - private var mRenderLeftPage = true - private var mSizeChangedObserver: SizeChangedObserver? = null - - // One page is the default. - private var mViewMode = SHOW_ONE_PAGE - - var mPageProvider: PageProvider? = null - set(value) { - field = value - mCurrentIndex = 0 - updatePages() - requestRender() - } - - /** - * Get current page index. Page indices are zero based values presenting - * page being shown on right side of the book. - */ - /** - * Set current page index. Page indices are zero based values presenting - * page being shown on right side of the book. E.g if you set value to 4; - * right side front facing bitmap will be with index 4, back facing 5 and - * for left side page index 3 is front facing, and index 2 back facing (once - * page is on left side it's flipped over). - * - * - * Current index is rounded to closest value divisible with 2. - */ - var currentIndex: Int - get() = mCurrentIndex - set(index) { - mCurrentIndex = if (mPageProvider == null || index < 0) { - 0 - } else { - if (mAllowLastPageCurl) { - min(index, mPageProvider!!.pageCount) - } else { - min(index, mPageProvider!!.pageCount - 1) - } - } - updatePages() - requestRender() - } - - /** - * Default constructor. - */ - constructor(ctx: Context) : super(ctx) - - /** - * Default constructor. - */ - constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) - - /** - * Default constructor. - */ - constructor(ctx: Context, attrs: AttributeSet, defStyle: Int) : this(ctx, attrs) - - /** - * Initialize method. - */ - init { - setEGLConfigChooser(8, 8, 8, 8, 16, 0) - holder.setFormat(PixelFormat.TRANSLUCENT) - setZOrderOnTop(true) - - setRenderer(mRenderer) - renderMode = RENDERMODE_WHEN_DIRTY - setOnTouchListener(this) - - // Even though left and right pages are static we have to allocate room - // for curl on them too as we are switching meshes. Another way would be - // to swap texture ids only. - mPageLeft = CurlMesh(10) - mPageRight = CurlMesh(10) - mPageCurl = CurlMesh(10) - mPageLeft.setFlipTexture(true) - mPageRight.setFlipTexture(false) - } - - override var canDraw: Boolean = false - - override fun onDrawFrame() { - // We are not animating. - if (!mAnimate) { - return - } - - val currentTime = System.currentTimeMillis() - // If animation is done. - if (currentTime >= mAnimationStartTime + mAnimationDurationTime) { - if (mAnimationTargetEvent == SET_CURL_TO_RIGHT) { - // Switch curled page to right. - val right = mPageCurl - val curl = mPageRight - right.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!!) - right.setFlipTexture(false) - right.reset() - mRenderer.removeCurlMesh(curl) - mPageCurl = curl - mPageRight = right - // If we were curling left page update current index. - if (mCurlState == CURL_LEFT) { - --mCurrentIndex - callBack?.pageChange(-1) - } - canDraw = false - } else if (mAnimationTargetEvent == SET_CURL_TO_LEFT) { - // Switch curled page to left. - val left = mPageCurl - val curl = mPageLeft - left.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)!!) - left.setFlipTexture(true) - left.reset() - mRenderer.removeCurlMesh(curl) - if (!mRenderLeftPage) { - mRenderer.removeCurlMesh(left) - } - mPageCurl = curl - mPageLeft = left - // If we were curling right page update current index. - if (mCurlState == CURL_RIGHT) { - ++mCurrentIndex - callBack?.pageChange(1) - } - canDraw = false - } - mCurlState = CURL_NONE - mAnimate = false - requestRender() - } else { - mPointerPos.mPos.set(mAnimationSource) - var t = 1f - (currentTime - mAnimationStartTime).toFloat() / mAnimationDurationTime - t = 1f - t * t * t * (3 - 2 * t) - mPointerPos.mPos.x += (mAnimationTarget.x - mAnimationSource.x) * t - mPointerPos.mPos.y += (mAnimationTarget.y - mAnimationSource.y) * t - updateCurlPos(mPointerPos) - } - } - - - override fun onPageSizeChanged(width: Int, height: Int) { - mPageBitmapWidth = width - mPageBitmapHeight = height - updatePages() - requestRender() - } - - public override fun onSizeChanged(w: Int, h: Int, ow: Int, oh: Int) { - super.onSizeChanged(w, h, ow, oh) - requestRender() - if (mSizeChangedObserver != null) { - mSizeChangedObserver!!.onSizeChanged(w, h) - } - } - - override fun onSurfaceCreated() { - // In case surface is recreated, let page meshes drop allocated texture - // ids and ask for new ones. There's no need to set textures here as - // onPageSizeChanged should be called later on. - mPageLeft.resetTexture() - mPageRight.resetTexture() - mPageCurl.resetTexture() - } - - override fun onTouch(view: View, me: MotionEvent): Boolean { - // No dragging during animation at the moment. - if (mAnimate || mPageProvider == null) { - return false - } - - // We need page rects quite extensively so get them for later use. - val rightRect = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT) - val leftRect = mRenderer.getPageRect(CurlRenderer.PAGE_LEFT) - - // Store pointer position. - mPointerPos.mPos.set(me.x, me.y) - mRenderer.translate(mPointerPos.mPos) - if (mEnableTouchPressure) { - mPointerPos.mPressure = me.pressure - } else { - mPointerPos.mPressure = 0.8f - } - - when (me.action) { - MotionEvent.ACTION_DOWN -> { - run { - - // Once we receive pointer down event its position is mapped to - // right or left edge of page and that'll be the position from where - // user is holding the paper to make curl happen. - mDragStartPos.set(mPointerPos.mPos) - - // First we make sure it's not over or below page. Pages are - // supposed to be same height so it really doesn't matter do we use - // left or right one. - if (mDragStartPos.y > rightRect!!.top) { - mDragStartPos.y = rightRect.top - } else if (mDragStartPos.y < rightRect.bottom) { - mDragStartPos.y = rightRect.bottom - } - - // Then we have to make decisions for the user whether curl is going - // to happen from left or right, and on which page. - if (mViewMode == SHOW_TWO_PAGES) { - // If we have an open book and pointer is on the left from right - // page we'll mark drag position to left edge of left page. - // Additionally checking mCurrentIndex is higher than zero tells - // us there is a visible page at all. - if (mDragStartPos.x < rightRect.left && mCurrentIndex > 0) { - mDragStartPos.x = leftRect!!.left - startCurl(CURL_LEFT) - } else if (mDragStartPos.x >= rightRect.left && mCurrentIndex < mPageProvider!!.pageCount) { - mDragStartPos.x = rightRect.right - if (!mAllowLastPageCurl && mCurrentIndex >= mPageProvider!!.pageCount - 1) { - return false - } - startCurl(CURL_RIGHT) - }// Otherwise check pointer is on right page's side. - } else if (mViewMode == SHOW_ONE_PAGE) { - val halfX = (rightRect.right + rightRect.left) / 2 - if (mDragStartPos.x < halfX && mCurrentIndex > 0) { - mDragStartPos.x = rightRect.left - startCurl(CURL_LEFT) - } else if (mDragStartPos.x >= halfX && mCurrentIndex < mPageProvider!!.pageCount) { - mDragStartPos.x = rightRect.right - if (!mAllowLastPageCurl && mCurrentIndex >= mPageProvider!!.pageCount - 1) { - return false - } - startCurl(CURL_RIGHT) - } - } - // If we have are in curl state, let this case clause flow through - // to next one. We have pointer position and drag position defined - // and this will create first render request given these points. - if (mCurlState == CURL_NONE) { - return false - } - } - updateCurlPos(mPointerPos) - } - MotionEvent.ACTION_MOVE -> { - updateCurlPos(mPointerPos) - } - MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> { - if (mCurlState == CURL_LEFT || mCurlState == CURL_RIGHT) { - // Animation source is the point from where animation starts. - // Also it's handled in a way we actually simulate touch events - // meaning the output is exactly the same as if user drags the - // page to other side. While not producing the best looking - // result (which is easier done by altering curl position and/or - // direction directly), this is done in a hope it made code a - // bit more readable and easier to maintain. - mAnimationSource.set(mPointerPos.mPos) - mAnimationStartTime = System.currentTimeMillis() - - // Given the explanation, here we decide whether to simulate - // drag to left or right end. - if (mViewMode == SHOW_ONE_PAGE && mPointerPos.mPos.x > (rightRect!!.left + rightRect.right) / 2 || mViewMode == SHOW_TWO_PAGES && mPointerPos.mPos.x > rightRect!!.left) { - // On right side target is always right page's right border. - mAnimationTarget.set(mDragStartPos) - mAnimationTarget.x = mRenderer - .getPageRect(CurlRenderer.PAGE_RIGHT)!!.right - mAnimationTargetEvent = SET_CURL_TO_RIGHT - } else { - // On left side target depends on visible pages. - mAnimationTarget.set(mDragStartPos) - if (mCurlState == CURL_RIGHT || mViewMode == SHOW_TWO_PAGES) { - mAnimationTarget.x = leftRect!!.left - } else { - mAnimationTarget.x = rightRect!!.left - } - mAnimationTargetEvent = SET_CURL_TO_LEFT - } - mAnimate = true - requestRender() - } - } - } - - return true - } - - /** - * Allow the last page to curl. - */ - fun setAllowLastPageCurl(allowLastPageCurl: Boolean) { - mAllowLastPageCurl = allowLastPageCurl - } - - /** - * Sets mPageCurl curl position. - */ - private fun setCurlPos(curlPos: PointF, curlDir: PointF, radius: Double) { - - // First reposition curl so that page doesn't 'rip off' from book. - if (mCurlState == CURL_RIGHT || mCurlState == CURL_LEFT && mViewMode == SHOW_ONE_PAGE) { - val pageRect = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT) - if (curlPos.x >= pageRect!!.right) { - mPageCurl.reset() - requestRender() - return - } - if (curlPos.x < pageRect.left) { - curlPos.x = pageRect.left - } - if (curlDir.y != 0f) { - val diffX = curlPos.x - pageRect.left - val leftY = curlPos.y + diffX * curlDir.x / curlDir.y - if (curlDir.y < 0 && leftY < pageRect.top) { - curlDir.x = curlPos.y - pageRect.top - curlDir.y = pageRect.left - curlPos.x - } else if (curlDir.y > 0 && leftY > pageRect.bottom) { - curlDir.x = pageRect.bottom - curlPos.y - curlDir.y = curlPos.x - pageRect.left - } - } - } else if (mCurlState == CURL_LEFT) { - val pageRect = mRenderer.getPageRect(CurlRenderer.PAGE_LEFT) - if (curlPos.x <= pageRect!!.left) { - mPageCurl.reset() - requestRender() - return - } - if (curlPos.x > pageRect.right) { - curlPos.x = pageRect.right - } - if (curlDir.y != 0f) { - val diffX = curlPos.x - pageRect.right - val rightY = curlPos.y + diffX * curlDir.x / curlDir.y - if (curlDir.y < 0 && rightY < pageRect.top) { - curlDir.x = pageRect.top - curlPos.y - curlDir.y = curlPos.x - pageRect.right - } else if (curlDir.y > 0 && rightY > pageRect.bottom) { - curlDir.x = curlPos.y - pageRect.bottom - curlDir.y = pageRect.right - curlPos.x - } - } - } - - // Finally normalize direction vector and do rendering. - val dist = sqrt((curlDir.x * curlDir.x + curlDir.y * curlDir.y).toDouble()) - if (dist != 0.0) { - curlDir.x /= dist.toFloat() - curlDir.y /= dist.toFloat() - mPageCurl.curl(curlPos, curlDir, radius) - } else { - mPageCurl.reset() - } - - requestRender() - } - - /** - * If set to true, touch event pressure information is used to adjust curl - * radius. The more you press, the flatter the curl becomes. This is - * somewhat experimental and results may vary significantly between devices. - * On emulator pressure information seems to be flat 1.0f which is maximum - * value and therefore not very much of use. - */ - fun setEnableTouchPressure(enableTouchPressure: Boolean) { - mEnableTouchPressure = enableTouchPressure - } - - /** - * Setter for whether left side page is rendered. This is useful mostly for - * situations where right (main) page is aligned to left side of screen and - * left page is not visible anyway. - */ - fun setRenderLeftPage(renderLeftPage: Boolean) { - mRenderLeftPage = renderLeftPage - } - - /** - * Sets SizeChangedObserver for this View. Call back method is called from - * this View's onSizeChanged method. - */ - fun setSizeChangedObserver(observer: SizeChangedObserver) { - mSizeChangedObserver = observer - } - - /** - * Sets view mode. Value can be either SHOW_ONE_PAGE or SHOW_TWO_PAGES. In - * former case right page is made size of display, and in latter case two - * pages are laid on visible area. - */ - fun setViewMode(viewMode: Int) { - when (viewMode) { - SHOW_ONE_PAGE -> { - mViewMode = viewMode - mPageLeft.setFlipTexture(true) - mRenderer.setViewMode(CurlRenderer.SHOW_ONE_PAGE) - } - SHOW_TWO_PAGES -> { - mViewMode = viewMode - mPageLeft.setFlipTexture(false) - mRenderer.setViewMode(CurlRenderer.SHOW_TWO_PAGES) - } - } - } - - /** - * Switches meshes and loads new bitmaps if available. Updated to support 2 - * pages in landscape - */ - private fun startCurl(page: Int) { - when (page) { - - // Once right side page is curled, first right page is assigned into - // curled page. And if there are more bitmaps available new bitmap is - // loaded into right side mesh. - CURL_RIGHT -> { - // Remove meshes from renderer. - mRenderer.removeCurlMesh(mPageLeft) - mRenderer.removeCurlMesh(mPageRight) - mRenderer.removeCurlMesh(mPageCurl) - - // We are curling right page. - val curl = mPageRight - mPageRight = mPageCurl - mPageCurl = curl - - if (mCurrentIndex > 0) { - mPageLeft.setFlipTexture(true) - mPageLeft.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)!!) - mPageLeft.reset() - if (mRenderLeftPage) { - mRenderer.addCurlMesh(mPageLeft) - } - } - if (mCurrentIndex < mPageProvider!!.pageCount - 1) { - updatePage(mPageRight.texturePage, mCurrentIndex + 1) - mPageRight.setRect( - mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!! - ) - mPageRight.setFlipTexture(false) - mPageRight.reset() - mRenderer.addCurlMesh(mPageRight) - } - - // Add curled page to renderer. - mPageCurl.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!!) - mPageCurl.setFlipTexture(false) - mPageCurl.reset() - mRenderer.addCurlMesh(mPageCurl) - - mCurlState = CURL_RIGHT - } - - // On left side curl, left page is assigned to curled page. And if - // there are more bitmaps available before currentIndex, new bitmap - // is loaded into left page. - CURL_LEFT -> { - // Remove meshes from renderer. - mRenderer.removeCurlMesh(mPageLeft) - mRenderer.removeCurlMesh(mPageRight) - mRenderer.removeCurlMesh(mPageCurl) - - // We are curling left page. - val curl = mPageLeft - mPageLeft = mPageCurl - mPageCurl = curl - - if (mCurrentIndex > 1) { - updatePage(mPageLeft.texturePage, mCurrentIndex - 2) - mPageLeft.setFlipTexture(true) - mPageLeft - .setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)!!) - mPageLeft.reset() - if (mRenderLeftPage) { - mRenderer.addCurlMesh(mPageLeft) - } - } - - // If there is something to show on right page add it to renderer. - if (mCurrentIndex < mPageProvider!!.pageCount) { - mPageRight.setFlipTexture(false) - mPageRight.setRect( - mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!! - ) - mPageRight.reset() - mRenderer.addCurlMesh(mPageRight) - } - - // How dragging previous page happens depends on view mode. - if (mViewMode == SHOW_ONE_PAGE || mCurlState == CURL_LEFT && mViewMode == SHOW_TWO_PAGES) { - mPageCurl.setRect( - mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!! - ) - mPageCurl.setFlipTexture(false) - } else { - mPageCurl.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)!!) - mPageCurl.setFlipTexture(true) - } - mPageCurl.reset() - mRenderer.addCurlMesh(mPageCurl) - - mCurlState = CURL_LEFT - } - } - } - - /** - * Updates curl position. - */ - private fun updateCurlPos(pointerPos: PointerPosition) { - - // Default curl radius. - var radius = (mRenderer.getPageRect(CURL_RIGHT)!!.width() / 3).toDouble() - // TODO: This is not an optimal solution. Based on feedback received so - // far; pressure is not very accurate, it may be better not to map - // coefficient to range [0f, 1f] but something like [.2f, 1f] instead. - // Leaving it as is until get my hands on a real device. On emulator - // this doesn't work anyway. - radius *= max(1f - pointerPos.mPressure, 0f).toDouble() - // NOTE: Here we set pointerPos to mCurlPos. It might be a bit confusing - // later to see e.g "mCurlPos.x - mDragStartPos.x" used. But it's - // actually pointerPos we are doing calculations against. Why? Simply to - // optimize code a bit with the cost of making it unreadable. Otherwise - // we had to this in both of the next if-else branches. - mCurlPos.set(pointerPos.mPos) - - // If curl happens on right page, or on left page on two page mode, - // we'll calculate curl position from pointerPos. - if (mCurlState == CURL_RIGHT || mCurlState == CURL_LEFT && mViewMode == SHOW_TWO_PAGES) { - - mCurlDir.x = mCurlPos.x - mDragStartPos.x - mCurlDir.y = mCurlPos.y - mDragStartPos.y - val dist = - sqrt((mCurlDir.x * mCurlDir.x + mCurlDir.y * mCurlDir.y).toDouble()).toFloat() - - // Adjust curl radius so that if page is dragged far enough on - // opposite side, radius gets closer to zero. - val pageWidth = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!! - .width() - var curlLen = radius * Math.PI - if (dist > pageWidth * 2 - curlLen) { - curlLen = max(pageWidth * 2 - dist, 0f).toDouble() - radius = curlLen / Math.PI - } - - // Actual curl position calculation. - if (dist >= curlLen) { - val translate = (dist - curlLen) / 2 - if (mViewMode == SHOW_TWO_PAGES) { - mCurlPos.x -= (mCurlDir.x * translate / dist).toFloat() - } else { - val pageLeftX = mRenderer - .getPageRect(CurlRenderer.PAGE_RIGHT)!!.left - radius = max( - min((mCurlPos.x - pageLeftX).toDouble(), radius), - 0.0 - ) - } - mCurlPos.y -= (mCurlDir.y * translate / dist).toFloat() - } else { - val angle = Math.PI * sqrt(dist / curlLen) - val translate = radius * sin(angle) - mCurlPos.x += (mCurlDir.x * translate / dist).toFloat() - mCurlPos.y += (mCurlDir.y * translate / dist).toFloat() - } - } else if (mCurlState == CURL_LEFT) { - - // Adjust radius regarding how close to page edge we are. - val pageLeftX = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!!.left - radius = max(min((mCurlPos.x - pageLeftX).toDouble(), radius), 0.0) - - val pageRightX = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!!.right - mCurlPos.x -= min((pageRightX - mCurlPos.x).toDouble(), radius).toFloat() - mCurlDir.x = mCurlPos.x + mDragStartPos.x - mCurlDir.y = mCurlPos.y - mDragStartPos.y - }// Otherwise we'll let curl follow pointer position. - - setCurlPos(mCurlPos, mCurlDir, radius) - } - - /** - * Updates given CurlPage via PageProvider for page located at index. - */ - private fun updatePage(page: CurlPage, index: Int) { - // First reset page to initial state. - page.reset() - // Ask page provider to fill it up with bitmaps and colors. - mPageProvider!!.updatePage( - page, mPageBitmapWidth, mPageBitmapHeight, - index - ) - } - - /** - * Updates bitmaps for page meshes. - */ - fun updatePages() { - if (mPageProvider == null || mPageBitmapWidth <= 0 - || mPageBitmapHeight <= 0 - ) { - return - } - - // Remove meshes from renderer. - mRenderer.removeCurlMesh(mPageLeft) - mRenderer.removeCurlMesh(mPageRight) - mRenderer.removeCurlMesh(mPageCurl) - - var leftIdx = mCurrentIndex - 1 - var rightIdx = mCurrentIndex - var curlIdx = -1 - if (mCurlState == CURL_LEFT) { - curlIdx = leftIdx - --leftIdx - } else if (mCurlState == CURL_RIGHT) { - curlIdx = rightIdx - ++rightIdx - } - - if (rightIdx >= 0 && rightIdx < mPageProvider!!.pageCount) { - updatePage(mPageRight.texturePage, rightIdx) - mPageRight.setFlipTexture(false) - mPageRight.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!!) - mPageRight.reset() - mRenderer.addCurlMesh(mPageRight) - } - if (leftIdx >= 0 && leftIdx < mPageProvider!!.pageCount) { - updatePage(mPageLeft.texturePage, leftIdx) - mPageLeft.setFlipTexture(true) - mPageLeft.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)!!) - mPageLeft.reset() - if (mRenderLeftPage) { - mRenderer.addCurlMesh(mPageLeft) - } - } - if (curlIdx >= 0 && curlIdx < mPageProvider!!.pageCount) { - updatePage(mPageCurl.texturePage, curlIdx) - - if (mCurlState == CURL_RIGHT) { - mPageCurl.setFlipTexture(true) - mPageCurl.setRect( - mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)!! - ) - } else { - mPageCurl.setFlipTexture(false) - mPageCurl - .setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)!!) - } - - mPageCurl.reset() - mRenderer.addCurlMesh(mPageCurl) - } - } - - /** - * Provider for feeding 'book' with bitmaps which are used for rendering - * pages. - */ - interface PageProvider { - - /** - * Return number of pages available. - */ - val pageCount: Int - - /** - * Called once new bitmaps/textures are needed. Width and height are in - * pixels telling the size it will be drawn on screen and following them - * ensures that aspect ratio remains. But it's possible to return bitmap - * of any size though. You should use provided CurlPage for storing page - * information for requested page number.

- *

- * Index is a number between 0 and getBitmapCount() - 1. - */ - fun updatePage(page: CurlPage, width: Int, height: Int, index: Int) - } - - /** - * Simple holder for pointer position. - */ - private inner class PointerPosition { - internal var mPos = PointF() - internal var mPressure: Float = 0.toFloat() - } - - /** - * Observer interface for handling CurlView size changes. - */ - interface SizeChangedObserver { - - /** - * Called once CurlView size changes. - */ - fun onSizeChanged(width: Int, height: Int) - } - - interface CallBack { - fun pageChange(change: Int) - } - - companion object { - - // Curl state. We are flipping none, left or right page. - private const val CURL_LEFT = 1 - private const val CURL_NONE = 0 - private const val CURL_RIGHT = 2 - - // Constants for mAnimationTargetEvent. - private const val SET_CURL_TO_LEFT = 1 - private const val SET_CURL_TO_RIGHT = 2 - - // Shows one page at the center of view. - const val SHOW_ONE_PAGE = 1 - // Shows two pages side by side. - const val SHOW_TWO_PAGES = 2 - } - -} diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/PageDelegate.kt b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/PageDelegate.kt index c9e0ca546..3f78253b6 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/PageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/PageDelegate.kt @@ -69,7 +69,7 @@ abstract class PageDelegate(protected val pageView: PageView) { var isRunning = false var isStarted = false - protected fun setStartPoint(x: Float, y: Float, invalidate: Boolean = true) { + open fun setStartPoint(x: Float, y: Float, invalidate: Boolean = true) { startX = x startY = y @@ -78,7 +78,7 @@ abstract class PageDelegate(protected val pageView: PageView) { } } - protected fun setTouchPoint(x: Float, y: Float, invalidate: Boolean = true) { + open fun setTouchPoint(x: Float, y: Float, invalidate: Boolean = true) { touchX = x touchY = y diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt index eb58e616c..0f2c62475 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt @@ -1,126 +1,526 @@ package io.legado.app.ui.book.read.page.delegate -import android.graphics.Canvas -import android.view.MotionEvent +import android.graphics.* +import android.graphics.drawable.GradientDrawable +import android.os.Build import io.legado.app.ui.book.read.page.PageView -import io.legado.app.ui.book.read.page.curl.CurlPage -import io.legado.app.ui.book.read.page.curl.CurlView -import io.legado.app.utils.screenshot -import kotlin.math.abs +import kotlin.math.* -class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView), - CurlView.CallBack { +class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageView) { - var curlView: CurlView? = null + private var mCornerX = 1 // 拖拽点对应的页脚 + + private var mCornerY = 1 + private val mPath0: Path = Path() + private val mPath1: Path = Path() + // 贝塞尔曲线起始点 + private val mBezierStart1 = PointF() + // 贝塞尔曲线控制点 + private val mBezierControl1 = PointF() + // 贝塞尔曲线顶点 + private val mBezierVertex1 = PointF() + // 贝塞尔曲线结束点 + private var mBezierEnd1 = PointF() + + // 另一条贝塞尔曲线 + private val mBezierStart2 = PointF() + + private val mBezierControl2 = PointF() + private val mBezierVertex2 = PointF() + private var mBezierEnd2 = PointF() + + private var mMiddleX = 0f + private var mMiddleY = 0f + private var mDegrees = 0f + private var mTouchToCornerDis = 0f + private var mColorMatrixFilter: ColorMatrixColorFilter? = null + private val mMatrix: Matrix = Matrix() + private val mMatrixArray = floatArrayOf(0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 1.0f) + + // 是否属于右上左下 + private var mIsRT_LB = false + private var mMaxLength = 0f + // 背面颜色组 + private var mBackShadowColors: IntArray? = null + // 前面颜色组 + private var mFrontShadowColors: IntArray? = null + // 有阴影的GradientDrawable + private var mBackShadowDrawableLR: GradientDrawable? = null + private var mBackShadowDrawableRL: GradientDrawable? = null + private var mFolderShadowDrawableLR: GradientDrawable? = null + private var mFolderShadowDrawableRL: GradientDrawable? = null + + private var mFrontShadowDrawableHBT: GradientDrawable? = null + private var mFrontShadowDrawableHTB: GradientDrawable? = null + private var mFrontShadowDrawableVLR: GradientDrawable? = null + private var mFrontShadowDrawableVRL: GradientDrawable? = null + + private val mPaint: Paint = Paint() init { - pageView.curlView ?: let { - curlView = CurlView(pageView.context) - pageView.curlView = curlView - pageView.addView(curlView) - curlView?.mPageProvider = PageProvider() - curlView?.setSizeChangedObserver(SizeChangedObserver()) - curlView?.callBack = this - } + mMaxLength = hypot(pageView.width.toDouble(), pageView.height.toDouble()).toFloat() + mPaint.style = Paint.Style.FILL + //设置颜色数组 + createDrawable() + val cm = ColorMatrix() + val array = floatArrayOf( + 1f, 0f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, + 0f, 0f, 1f, 0f, 0f, 0f, 0f, 0f, 1f, 0f + ) + cm.set(array) + mColorMatrixFilter = ColorMatrixColorFilter(cm) } - override fun onTouch(event: MotionEvent): Boolean { - when (event.action) { - MotionEvent.ACTION_DOWN -> { - curlView?.currentIndex = 1 - } + override fun setStartPoint(x: Float, y: Float, invalidate: Boolean) { + super.setStartPoint(x, y, invalidate) + calcCornerXY(x, y) + } + + override fun setTouchPoint(x: Float, y: Float, invalidate: Boolean) { + super.setTouchPoint(x, y, invalidate) + //触摸y中间位置吧y变成屏幕高度 + //触摸y中间位置吧y变成屏幕高度 + if (startY > pageView.height / 3.0 + && startY < pageView.height * 2 / 3.0 + || direction == Direction.PREV + ) { + touchY = pageView.height.toFloat() + } + + if (startY > pageView.height / 3.0 + && startY < pageView.height / 2.0 + && direction == Direction.NEXT + ) { + touchY = 1f } - curlView?.dispatchTouchEvent(event) - return super.onTouch(event) } override fun onScrollStart() { - } + val distanceX: Float + when (direction) { + Direction.NEXT -> distanceX = + if (isCancel) { + var dis = viewWidth - startX + touchX + if (dis > viewWidth) { + dis = viewWidth.toFloat() + } + viewWidth - dis + } else { + -(touchX + (viewWidth - startX)) + } + else -> distanceX = + if (isCancel) { + -(touchX - startX) + } else { + viewWidth - (touchX - startX) + } + } - override fun onDraw(canvas: Canvas) { + startScroll(touchX.toInt(), 0, distanceX.toInt(), 0) } override fun onScrollStop() { + curPage?.x = 0.toFloat() + if (!isCancel) { + pageView.fillPage(direction) + } } - override fun onScroll( - e1: MotionEvent, - e2: MotionEvent, - distanceX: Float, - distanceY: Float - ): Boolean { - if (!isMoved) { - val event = e1.toAction(MotionEvent.ACTION_UP) - curPage?.dispatchTouchEvent(event) - event.recycle() - if (abs(distanceX) > abs(distanceY)) { - if (distanceX < 0) { - //如果上一页不存在 - if (!hasPrev()) { - noNext = true - return true - } - //上一页截图 - bitmap = prevPage?.screenshot() - } else { - //如果不存在表示没有下一页了 - if (!hasNext()) { - noNext = true - return true - } - //下一页截图 - bitmap = nextPage?.screenshot() - } - isMoved = true + override fun onDraw(canvas: Canvas) { + bitmap?.let { + if (direction === Direction.NEXT) { + calcPoints() + drawCurrentPageArea(canvas, it, mPath0!!) //绘制翻页时的正面页 +// drawNextPageAreaAndShadow(canvas, it) + drawCurrentPageShadow(canvas) + drawCurrentBackArea(canvas, it) + } else { + calcPoints() + drawCurrentPageArea(canvas, it, mPath0!!) +// drawNextPageAreaAndShadow(canvas, it) + drawCurrentPageShadow(canvas) + drawCurrentBackArea(canvas, it) } } - if (isMoved) { - curlView?.canDraw = true - isCancel = if (pageView.isScrollDelegate) { - if (direction == Direction.NEXT) distanceY < 0 else distanceY > 0 + } + + /** + * 创建阴影的GradientDrawable + */ + private fun createDrawable() { + val color = intArrayOf(0x333333, -0x4fcccccd) + mFolderShadowDrawableRL = GradientDrawable( + GradientDrawable.Orientation.RIGHT_LEFT, color + ).apply { gradientType = GradientDrawable.LINEAR_GRADIENT } + mFolderShadowDrawableLR = GradientDrawable( + GradientDrawable.Orientation.LEFT_RIGHT, color + ).apply { gradientType = GradientDrawable.LINEAR_GRADIENT } + mBackShadowColors = intArrayOf(-0xeeeeef, 0x111111) + mBackShadowDrawableRL = GradientDrawable( + GradientDrawable.Orientation.RIGHT_LEFT, mBackShadowColors + ).apply { gradientType = GradientDrawable.LINEAR_GRADIENT } + mBackShadowDrawableLR = GradientDrawable( + GradientDrawable.Orientation.LEFT_RIGHT, mBackShadowColors + ).apply { gradientType = GradientDrawable.LINEAR_GRADIENT } + mFrontShadowColors = intArrayOf(-0x7feeeeef, 0x111111) + mFrontShadowDrawableVLR = GradientDrawable( + GradientDrawable.Orientation.LEFT_RIGHT, mFrontShadowColors + ).apply { gradientType = GradientDrawable.LINEAR_GRADIENT } + mFrontShadowDrawableVRL = GradientDrawable( + GradientDrawable.Orientation.RIGHT_LEFT, mFrontShadowColors + ).apply { gradientType = GradientDrawable.LINEAR_GRADIENT } + mFrontShadowDrawableHTB = GradientDrawable( + GradientDrawable.Orientation.TOP_BOTTOM, mFrontShadowColors + ).apply { gradientType = GradientDrawable.LINEAR_GRADIENT } + mFrontShadowDrawableHBT = GradientDrawable( + GradientDrawable.Orientation.BOTTOM_TOP, mFrontShadowColors + ).apply { gradientType = GradientDrawable.LINEAR_GRADIENT } + } + + /** + * 绘制翻起页背面 + */ + private fun drawCurrentBackArea( + canvas: Canvas, + bitmap: Bitmap + ) { + val i = (mBezierStart1.x + mBezierControl1.x).toInt() / 2 + val f1 = abs(i - mBezierControl1.x) + val i1 = (mBezierStart2.y + mBezierControl2.y).toInt() / 2 + val f2 = abs(i1 - mBezierControl2.y) + val f3 = min(f1, f2) + mPath1.reset() + mPath1.moveTo(mBezierVertex2.x, mBezierVertex2.y) + mPath1.lineTo(mBezierVertex1.x, mBezierVertex1.y) + mPath1.lineTo(mBezierEnd1.x, mBezierEnd1.y) + mPath1.lineTo(touchX, touchY) + mPath1.lineTo(mBezierEnd2.x, mBezierEnd2.y) + mPath1.close() + val mFolderShadowDrawable: GradientDrawable + val left: Int + val right: Int + if (mIsRT_LB) { + left = (mBezierStart1.x - 1).toInt() + right = (mBezierStart1.x + f3 + 1).toInt() + mFolderShadowDrawable = mFolderShadowDrawableLR!! + } else { + left = (mBezierStart1.x - f3 - 1).toInt() + right = (mBezierStart1.x + 1).toInt() + mFolderShadowDrawable = mFolderShadowDrawableRL!! + } + canvas.save() + try { + canvas.clipPath(mPath0) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + canvas.clipPath(mPath1) } else { - if (direction == Direction.NEXT) distanceX < 0 else distanceX > 0 + canvas.clipPath(mPath1, Region.Op.INTERSECT) } - isRunning = true - //设置触摸点 - setTouchPoint(e2.x, e2.y) + } catch (ignored: Exception) { } - return isMoved + mPaint!!.colorFilter = mColorMatrixFilter + val dis = hypot( + mCornerX - mBezierControl1.x.toDouble(), + mBezierControl2.y - mCornerY.toDouble() + ).toFloat() + val f8 = (mCornerX - mBezierControl1.x) / dis + val f9 = (mBezierControl2.y - mCornerY) / dis + mMatrixArray[0] = 1 - 2 * f9 * f9 + mMatrixArray[1] = 2 * f8 * f9 + mMatrixArray[3] = mMatrixArray[1] + mMatrixArray[4] = 1 - 2 * f8 * f8 + mMatrix.reset() + mMatrix.setValues(mMatrixArray) + mMatrix.preTranslate(-mBezierControl1.x, -mBezierControl1.y) + mMatrix.postTranslate(mBezierControl1.x, mBezierControl1.y) + canvas.drawBitmap(bitmap, mMatrix, mPaint) + mPaint.colorFilter = null + canvas.rotate(mDegrees, mBezierStart1.x, mBezierStart1.y) + mFolderShadowDrawable.setBounds( + left, mBezierStart1.y.toInt(), right, + (mBezierStart1.y + mMaxLength).toInt() + ) + mFolderShadowDrawable.draw(canvas) + canvas.restore() } - override fun onPageUp() { - curlView?.updatePages() - curlView?.requestRender() + /** + * 绘制翻起页的阴影 + */ + private fun drawCurrentPageShadow(canvas: Canvas) { + val degree: Double = if (mIsRT_LB) { + (Math.PI / 4 - atan2(mBezierControl1.y - touchX, touchY - mBezierControl1.x)) + } else { + (Math.PI / 4 - atan2(touchY - mBezierControl1.y, touchX - mBezierControl1.x)) + } + // 翻起页阴影顶点与touch点的距离 + val d1 = 25.toFloat() * 1.414 * cos(degree) + val d2 = 25.toFloat() * 1.414 * sin(degree) + val x = (touchX + d1).toFloat() + val y: Float + y = if (mIsRT_LB) { + (touchY + d2).toFloat() + } else { + (touchY - d2).toFloat() + } + mPath1.reset() + mPath1.moveTo(x, y) + mPath1.lineTo(touchX, touchY) + mPath1.lineTo(mBezierControl1.x, mBezierControl1.y) + mPath1.lineTo(mBezierStart1.x, mBezierStart1.y) + mPath1.close() + canvas.save() + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + canvas.clipOutPath(mPath0) + } else { + canvas.clipPath(mPath0, Region.Op.XOR) + } + canvas.clipPath(mPath1, Region.Op.INTERSECT) + } catch (ignored: java.lang.Exception) { + } + var leftX: Int + var rightX: Int + var mCurrentPageShadow: GradientDrawable + if (mIsRT_LB) { + leftX = mBezierControl1.x.toInt() + rightX = mBezierControl1.x.toInt() + 25 + mCurrentPageShadow = mFrontShadowDrawableVLR!! + } else { + leftX = (mBezierControl1.x - 25).toInt() + rightX = mBezierControl1.x.toInt() + 1 + mCurrentPageShadow = mFrontShadowDrawableVRL!! + } + var rotateDegrees: Float = + Math.toDegrees(atan2(touchX - mBezierControl1.x, mBezierControl1.y - touchY).toDouble()) + .toFloat() + canvas.rotate(rotateDegrees, mBezierControl1.x, mBezierControl1.y) + mCurrentPageShadow.setBounds( + leftX, + (mBezierControl1.y - mMaxLength).toInt(), rightX, + mBezierControl1.y.toInt() + ) + mCurrentPageShadow.draw(canvas) + canvas.restore() + mPath1.reset() + mPath1.moveTo(x, y) + mPath1.lineTo(touchX, touchY) + mPath1.lineTo(mBezierControl2.x, mBezierControl2.y) + mPath1.lineTo(mBezierStart2.x, mBezierStart2.y) + mPath1.close() + canvas.save() + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + canvas.clipOutPath(mPath0) + } else { + canvas.clipPath(mPath0, Region.Op.XOR) + } + canvas.clipPath(mPath1) + } catch (ignored: java.lang.Exception) { + } + if (mIsRT_LB) { + leftX = mBezierControl2.y.toInt() + rightX = (mBezierControl2.y + 25).toInt() + mCurrentPageShadow = mFrontShadowDrawableHTB!! + } else { + leftX = (mBezierControl2.y - 25).toInt() + rightX = (mBezierControl2.y + 1).toInt() + mCurrentPageShadow = mFrontShadowDrawableHBT!! + } + rotateDegrees = Math.toDegrees( + atan2(mBezierControl2.y - touchY, mBezierControl2.x - touchX).toDouble() + ).toFloat() + canvas.rotate(rotateDegrees, mBezierControl2.x, mBezierControl2.y) + val temp: Float = + if (mBezierControl2.y < 0) mBezierControl2.y - pageView.height else mBezierControl2.y + val hmg = hypot(mBezierControl2.x.toDouble(), temp.toDouble()).toInt() + if (hmg > mMaxLength) mCurrentPageShadow + .setBounds( + (mBezierControl2.x - 25).toInt() - hmg, leftX, + (mBezierControl2.x + mMaxLength).toInt() - hmg, + rightX + ) else mCurrentPageShadow.setBounds( + (mBezierControl2.x - mMaxLength).toInt(), leftX, + mBezierControl2.x.toInt(), rightX + ) + mCurrentPageShadow.draw(canvas) + canvas.restore() } - override fun pageChange(change: Int) { - pageView.post { - if (change > 0) { - pageView.moveToNextPage() + private fun drawNextPageAreaAndShadow( + canvas: Canvas, + bitmap: Bitmap + ) { + mPath1.reset() + mPath1.moveTo(mBezierStart1.x, mBezierStart1.y) + mPath1.lineTo(mBezierVertex1.x, mBezierVertex1.y) + mPath1.lineTo(mBezierVertex2.x, mBezierVertex2.y) + mPath1.lineTo(mBezierStart2.x, mBezierStart2.y) + mPath1.lineTo(mCornerX.toFloat(), mCornerY.toFloat()) + mPath1.close() + mDegrees = Math.toDegrees( + atan2( + (mBezierControl1.x - mCornerX).toDouble(), + mBezierControl2.y - mCornerY.toDouble() + ) + ).toFloat() + val leftX: Int + val rightY: Int + val mBackShadowDrawable: GradientDrawable + if (mIsRT_LB) { //左下及右上 + leftX = mBezierStart1.x.toInt() + rightY = (mBezierStart1.x + mTouchToCornerDis / 4).toInt() + mBackShadowDrawable = mBackShadowDrawableLR!! + } else { + leftX = (mBezierStart1.x - mTouchToCornerDis / 4).toInt() + rightY = mBezierStart1.x.toInt() + mBackShadowDrawable = mBackShadowDrawableRL!! + } + canvas.save() + try { + canvas.clipPath(mPath0) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + canvas.clipPath(mPath1) } else { - pageView.moveToPrevPage() + canvas.clipPath(mPath1, Region.Op.INTERSECT) } + //canvas.clipPath(mPath1, Region.Op.INTERSECT); + } catch (ignored: java.lang.Exception) { } + canvas.drawBitmap(bitmap, 0f, 0f, null) + canvas.rotate(mDegrees, mBezierStart1.x, mBezierStart1.y) + mBackShadowDrawable.setBounds( + leftX, mBezierStart1.y.toInt(), rightY, + (mMaxLength + mBezierStart1.y).toInt() + ) //左上及右下角的xy坐标值,构成一个矩形 + mBackShadowDrawable.draw(canvas) + canvas.restore() } - private inner class PageProvider : CurlView.PageProvider { + private fun drawCurrentPageArea( + canvas: Canvas, + bitmap: Bitmap, + path: Path + ) { + mPath0.reset() + mPath0.moveTo(mBezierStart1.x, mBezierStart1.y) + mPath0.quadTo( + mBezierControl1.x, mBezierControl1.y, mBezierEnd1.x, + mBezierEnd1.y + ) + mPath0.lineTo(touchX, touchY) + mPath0.lineTo(mBezierEnd2.x, mBezierEnd2.y) + mPath0.quadTo( + mBezierControl2.x, mBezierControl2.y, mBezierStart2.x, + mBezierStart2.y + ) + mPath0.lineTo(mCornerX.toFloat(), mCornerY.toFloat()) + mPath0.close() + canvas.save() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + canvas.clipOutPath(path) + } else { + canvas.clipPath(path, Region.Op.XOR) + } + canvas.drawBitmap(bitmap, 0f, 0f, null) + try { + canvas.restore() + } catch (e: java.lang.Exception) { + e.printStackTrace() + } + } - override val pageCount: Int - get() = 3 + /** + * 计算拖拽点对应的拖拽脚 + */ + private fun calcCornerXY(x: Float, y: Float) { + if (x <= pageView.width / 2.0) { + mCornerX = 0 + } else { + mCornerX = pageView.width + } + if (y <= pageView.height / 2.0) { + mCornerY = 0 + } else { + mCornerY = pageView.height + } + mIsRT_LB = (mCornerX == 0 && mCornerY == pageView.height + || mCornerX == pageView.width && mCornerY == 0) + } - override fun updatePage(page: CurlPage, width: Int, height: Int, index: Int) { - when (index) { - 0 -> page.setTexture(prevPage?.screenshot(), CurlPage.SIDE_BOTH) - 1 -> page.setTexture(curPage?.screenshot(), CurlPage.SIDE_BOTH) - 2 -> page.setTexture(nextPage?.screenshot(), CurlPage.SIDE_BOTH) + private fun calcPoints() { + mMiddleX = (touchX + mCornerX) / 2 + mMiddleY = (touchY + mCornerY) / 2 + mBezierControl1.x = + mMiddleX - (mCornerY - mMiddleY) * (mCornerY - mMiddleY) / (mCornerX - mMiddleX) + mBezierControl1.y = mCornerY.toFloat() + mBezierControl2.x = mCornerX.toFloat() + val f4 = mCornerY - mMiddleY + if (f4 == 0f) { + mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / 0.1f + } else { + mBezierControl2.y = + mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / (mCornerY - mMiddleY) + } + mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x) / 2 + mBezierStart1.y = mCornerY.toFloat() + // 当mBezierStart1.x < 0或者mBezierStart1.x > 480时 + // 如果继续翻页,会出现BUG故在此限制 + if (touchX > 0 && touchX < pageView.width) { + if (mBezierStart1.x < 0 || mBezierStart1.x > pageView.width) { + if (mBezierStart1.x < 0) mBezierStart1.x = pageView.width - mBezierStart1.x + val f1: Float = abs(mCornerX - touchX) + val f2: Float = pageView.width * f1 / mBezierStart1.x + touchX = abs(mCornerX - f2) + val f3: Float = abs(mCornerX - touchX) * abs(mCornerY - touchX) / f1 + touchX = abs(mCornerY - f3) + mMiddleX = (touchX + mCornerX) / 2 + mMiddleY = (touchY + mCornerY) / 2 + mBezierControl1.x = + mMiddleX - (mCornerY - mMiddleY) * (mCornerY - mMiddleY) / (mCornerX - mMiddleX) + mBezierControl1.y = mCornerY.toFloat() + mBezierControl2.x = mCornerX.toFloat() + val f5 = mCornerY - mMiddleY + if (f5 == 0f) { + mBezierControl2.y = + mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / 0.1f + } else { + mBezierControl2.y = + mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / (mCornerY - mMiddleY) + } + mBezierStart1.x = (mBezierControl1.x + - (mCornerX - mBezierControl1.x) / 2) } } + mBezierStart2.x = mCornerX.toFloat() + mBezierStart2.y = mBezierControl2.y - (mCornerY - mBezierControl2.y) / 2 + mTouchToCornerDis = hypot(touchX - mCornerX, touchY - mCornerY) + mBezierEnd1 = getCross( + PointF(touchX, touchY), mBezierControl1, mBezierStart1, + mBezierStart2 + ) + mBezierEnd2 = getCross( + PointF(touchX, touchY), mBezierControl2, mBezierStart1, + mBezierStart2 + ) + mBezierVertex1.x = (mBezierStart1.x + 2 * mBezierControl1.x + mBezierEnd1.x) / 4 + mBezierVertex1.y = (2 * mBezierControl1.y + mBezierStart1.y + mBezierEnd1.y) / 4 + mBezierVertex2.x = (mBezierStart2.x + 2 * mBezierControl2.x + mBezierEnd2.x) / 4 + mBezierVertex2.y = (2 * mBezierControl2.y + mBezierStart2.y + mBezierEnd2.y) / 4 } - // 定义书籍尺寸的变化监听器 - private inner class SizeChangedObserver : CurlView.SizeChangedObserver { - override fun onSizeChanged(width: Int, height: Int) { - curlView?.setViewMode(CurlView.SHOW_ONE_PAGE) - } + /** + * 求解直线P1P2和直线P3P4的交点坐标 + */ + private fun getCross(P1: PointF, P2: PointF, P3: PointF, P4: PointF): PointF { + val crossP = PointF() + // 二元函数通式: y=ax+b + val a1 = (P2.y - P1.y) / (P2.x - P1.x) + val b1 = (P1.x * P2.y - P2.x * P1.y) / (P1.x - P2.x) + val a2 = (P4.y - P3.y) / (P4.x - P3.x) + val b2 = (P3.x * P4.y - P4.x * P3.y) / (P3.x - P4.x) + crossP.x = (b2 - b1) / (a1 - a2) + crossP.y = a1 * crossP.x + b1 + return crossP } } \ No newline at end of file From e707336f0185a22f55e10f98a8babf08f7965cfd Mon Sep 17 00:00:00 2001 From: Celeter Date: Mon, 30 Dec 2019 16:05:47 +0800 Subject: [PATCH 37/85] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B9=A6=E6=BA=90?= =?UTF-8?q?=E8=B0=83=E8=AF=95=E5=92=8CRSS=20=E3=83=BB=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=E9=A1=B5=E5=92=8C=E6=AD=A3=E6=96=87=E9=A1=B5?= =?UTF-8?q?=E8=B0=83=E8=AF=95=20=E3=83=BB=E4=BF=AE=E6=94=B9RSS=E7=9A=84?= =?UTF-8?q?=E4=BC=9A=E6=A0=B9=E6=8D=AE=E6=98=AF=E5=90=A6=E5=AD=98=E5=9C=A8?= =?UTF-8?q?style=E6=9D=A5=E8=87=AA=E5=8A=A8=E5=A2=9E=E5=8A=A0img=E3=80=81v?= =?UTF-8?q?ideo=E3=80=81body=E7=9A=84style?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/io/legado/app/model/Debug.kt | 18 ++++++++++++++++ .../app/ui/rss/read/ReadRssViewModel.kt | 21 ++++++++++--------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/model/Debug.kt b/app/src/main/java/io/legado/app/model/Debug.kt index fee62972e..7d7ec3627 100644 --- a/app/src/main/java/io/legado/app/model/Debug.kt +++ b/app/src/main/java/io/legado/app/model/Debug.kt @@ -111,6 +111,24 @@ object Debug { log(webBook.sourceUrl, "⇒开始访问发现页:$url") exploreDebug(webBook, url) } + key.startsWith("++")-> { + val url = key.substring(2) + val book = Book() + book.origin = webBook.sourceUrl + book.tocUrl = url + log(webBook.sourceUrl, "⇒开始访目录页:$url") + tocDebug(webBook, book) + } + key.startsWith("--")-> { + val url = key.substring(2) + val book = Book() + book.origin = webBook.sourceUrl + log(webBook.sourceUrl, "⇒开始访正文页:$url") + val chapter = BookChapter() + chapter.title = "调试" + chapter.url = url + contentDebug(webBook, book, chapter, null) + } else -> { log(webBook.sourceUrl, "⇒开始搜索关键字:$key") searchDebug(webBook, key) diff --git a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt index 8c6f56279..98355d7d8 100644 --- a/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt @@ -78,16 +78,17 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application) { } fun clHtml(content: String): String { - return """ - - - - - - - $content - - """ + return if (content.contains("$content + """ + } } interface CallBack { From d12c176eff69839101ada17ee4f9bf765bdf67a5 Mon Sep 17 00:00:00 2001 From: Celeter Date: Mon, 30 Dec 2019 16:36:00 +0800 Subject: [PATCH 38/85] up --- app/src/main/assets/updateLog.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index 17989e384..06c0bcaac 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -4,6 +4,24 @@ * 先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】,提示存储权限,选择允许即可导入成功。 * 注意:由于安卓10更改了权限策略,还需要给「允许安装其他应用」的权限才能导入源。MIUI11也需要此权限。 +**2019/12/30** +* 修改书源调试 + - 调试搜索>>输入关键字,如:`系统` + - 调试发现>>输入发现URL,如:`月票榜::https://www.qidian.com/rank/yuepiao?page={{page}}` + - 调试详情页>>输入详情页URL,如:`https://m.qidian.com/book/1015609210` + - 调试目录页>>输入目录页URL,如:`++https://www.zhaishuyuan.com/read/30394` + - 调试正文页>>输入正文页URL,如:`--https://www.zhaishuyuan.com/chapter/30394/20940996` + +* 修改订阅中自动添加style的情景 + 订阅源的内容规则中存在` + ``` + **2019/12/28** * 添加下载界面 * 添加分组备份 From 083113ceec715d158f6ffd693517a56719719a8b Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 30 Dec 2019 20:53:50 +0800 Subject: [PATCH 39/85] up --- .../ui/book/read/page/delegate/SimulationPageDelegate.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt index 0f2c62475..d120f7d2c 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt @@ -130,13 +130,13 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi bitmap?.let { if (direction === Direction.NEXT) { calcPoints() - drawCurrentPageArea(canvas, it, mPath0!!) //绘制翻页时的正面页 + drawCurrentPageArea(canvas, it, mPath0) //绘制翻页时的正面页 // drawNextPageAreaAndShadow(canvas, it) drawCurrentPageShadow(canvas) drawCurrentBackArea(canvas, it) } else { calcPoints() - drawCurrentPageArea(canvas, it, mPath0!!) + drawCurrentPageArea(canvas, it, mPath0) // drawNextPageAreaAndShadow(canvas, it) drawCurrentPageShadow(canvas) drawCurrentBackArea(canvas, it) @@ -218,7 +218,7 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi } } catch (ignored: Exception) { } - mPaint!!.colorFilter = mColorMatrixFilter + mPaint.colorFilter = mColorMatrixFilter val dis = hypot( mCornerX - mBezierControl1.x.toDouble(), mBezierControl2.y - mCornerY.toDouble() From 09243b6faa44dc4977ad59cebc119f047a0c2063 Mon Sep 17 00:00:00 2001 From: kunfei Date: Mon, 30 Dec 2019 20:57:58 +0800 Subject: [PATCH 40/85] up --- .../read/page/delegate/SimulationPageDelegate.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt index d120f7d2c..8d7112056 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt @@ -434,15 +434,15 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi * 计算拖拽点对应的拖拽脚 */ private fun calcCornerXY(x: Float, y: Float) { - if (x <= pageView.width / 2.0) { - mCornerX = 0 + mCornerX = if (x <= pageView.width / 2.0) { + 0 } else { - mCornerX = pageView.width + pageView.width } - if (y <= pageView.height / 2.0) { - mCornerY = 0 + mCornerY = if (y <= pageView.height / 2.0) { + 0 } else { - mCornerY = pageView.height + pageView.height } mIsRT_LB = (mCornerX == 0 && mCornerY == pageView.height || mCornerX == pageView.width && mCornerY == 0) From 35efe8768dc1cc9d36ac2e9660541206b564444b Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 31 Dec 2019 11:30:46 +0800 Subject: [PATCH 41/85] up --- .../app/ui/book/read/page/delegate/SimulationPageDelegate.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt index 8d7112056..ac3f00283 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/SimulationPageDelegate.kt @@ -131,13 +131,13 @@ class SimulationPageDelegate(pageView: PageView) : HorizontalPageDelegate(pageVi if (direction === Direction.NEXT) { calcPoints() drawCurrentPageArea(canvas, it, mPath0) //绘制翻页时的正面页 -// drawNextPageAreaAndShadow(canvas, it) + drawNextPageAreaAndShadow(canvas, it) drawCurrentPageShadow(canvas) drawCurrentBackArea(canvas, it) } else { calcPoints() drawCurrentPageArea(canvas, it, mPath0) -// drawNextPageAreaAndShadow(canvas, it) + drawNextPageAreaAndShadow(canvas, it) drawCurrentPageShadow(canvas) drawCurrentBackArea(canvas, it) } From dafbb6d895e1e5b11d1f21a64283881688dad8cb Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 31 Dec 2019 15:05:20 +0800 Subject: [PATCH 42/85] up --- .../ui/book/read/page/delegate/HorizontalPageDelegate.kt | 6 +----- .../app/ui/book/read/page/delegate/ScrollPageDelegate.kt | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/HorizontalPageDelegate.kt b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/HorizontalPageDelegate.kt index ef43b929e..ebb76100c 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/HorizontalPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/HorizontalPageDelegate.kt @@ -39,11 +39,7 @@ abstract class HorizontalPageDelegate(pageView: PageView) : PageDelegate(pageVie } } if (isMoved) { - isCancel = if (pageView.isScrollDelegate) { - if (direction == Direction.NEXT) distanceY < 0 else distanceY > 0 - } else { - if (direction == Direction.NEXT) distanceX < 0 else distanceX > 0 - } + isCancel = if (direction == Direction.NEXT) distanceX < 0 else distanceX > 0 isRunning = true //设置触摸点 setTouchPoint(e2.x, e2.y) diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/ScrollPageDelegate.kt b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/ScrollPageDelegate.kt index bf8a51a02..5b25392a2 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/delegate/ScrollPageDelegate.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/delegate/ScrollPageDelegate.kt @@ -109,11 +109,7 @@ class ScrollPageDelegate(pageView: PageView) : PageDelegate(pageView) { curPage?.dispatchTouchEvent(e2) } if (isMoved) { - isCancel = if (pageView.isScrollDelegate) { - if (direction == Direction.NEXT) distanceY < 0 else distanceY > 0 - } else { - if (direction == Direction.NEXT) distanceX < 0 else distanceX > 0 - } + isCancel = if (direction == Direction.NEXT) distanceY < 0 else distanceY > 0 isRunning = true //设置触摸点 setTouchPoint(e2.x, e2.y) From cea6795de7e121cad86391e5b5e1c8cfc4e86f2f Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 31 Dec 2019 16:14:26 +0800 Subject: [PATCH 43/85] up --- .../io/legado/app/ui/book/source/manage/BookSourceViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt index 982476466..67b22be3f 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt @@ -194,7 +194,7 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application) else -> "格式不对" } }.onError { - finally(it.localizedMessage) + finally(it.localizedMessage ?: "") }.onSuccess { finally(it ?: "导入完成") } From dab8cb781b25584de81adc55cc49537e1e71e68c Mon Sep 17 00:00:00 2001 From: kunfei Date: Tue, 31 Dec 2019 17:18:08 +0800 Subject: [PATCH 44/85] up --- .../io/legado/app/ui/main/MainViewModel.kt | 26 +++++++++++++++++++ .../io/legado/app/ui/main/rss/RssFragment.kt | 5 ++++ 2 files changed, 31 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt index 647b0bac2..6f282ef09 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt @@ -4,7 +4,14 @@ import android.app.Application import io.legado.app.App import io.legado.app.base.BaseViewModel import io.legado.app.constant.Bus +import io.legado.app.data.api.IHttpGetApi +import io.legado.app.data.entities.RssSource +import io.legado.app.help.http.HttpHelper +import io.legado.app.help.storage.Restore import io.legado.app.model.WebBook +import io.legado.app.utils.GSON +import io.legado.app.utils.NetworkUtils +import io.legado.app.utils.fromJsonObject import io.legado.app.utils.postEvent import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.delay @@ -48,4 +55,23 @@ class MainViewModel(application: Application) : BaseViewModel(application) { } } + fun initRss() { + execute { + val url = "https://gitee.com/alanskycn/yuedu/raw/master/JS/RSS/rssSource" + NetworkUtils.getBaseUrl(url)?.let { + val response = HttpHelper.getApiService(it).get(url, mapOf()).execute() + response.body()?.let { body -> + val sources = mutableListOf() + val items: List> = Restore.jsonPath.parse(body).read("$") + for (item in items) { + val jsonItem = Restore.jsonPath.parse(item) + GSON.fromJsonObject(jsonItem.jsonString())?.let { source -> + sources.add(source) + } + } + App.db.rssSourceDao().insert(*sources.toTypedArray()) + } + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt index 13ac93c20..0ec49f315 100644 --- a/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/rss/RssFragment.kt @@ -11,8 +11,10 @@ import io.legado.app.R import io.legado.app.base.BaseFragment import io.legado.app.data.entities.RssSource import io.legado.app.lib.theme.ATH +import io.legado.app.ui.main.MainViewModel import io.legado.app.ui.rss.article.RssArticlesActivity import io.legado.app.ui.rss.source.manage.RssSourceActivity +import io.legado.app.utils.getViewModelOfActivity import io.legado.app.utils.startActivity import kotlinx.android.synthetic.main.fragment_rss.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -50,6 +52,9 @@ class RssFragment : BaseFragment(R.layout.fragment_rss), private fun initData() { App.db.rssSourceDao().liveEnabled().observe(viewLifecycleOwner, Observer { + if (it.isEmpty()) { + getViewModelOfActivity(MainViewModel::class.java).initRss() + } adapter.setItems(it) }) } From 788f5ce365fef4927f26ed389f33631d0386f756 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 1 Jan 2020 12:42:34 +0800 Subject: [PATCH 45/85] up --- app/src/main/java/io/legado/app/ui/main/MainViewModel.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt index 6f282ef09..27b37fe1a 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainViewModel.kt @@ -59,7 +59,8 @@ class MainViewModel(application: Application) : BaseViewModel(application) { execute { val url = "https://gitee.com/alanskycn/yuedu/raw/master/JS/RSS/rssSource" NetworkUtils.getBaseUrl(url)?.let { - val response = HttpHelper.getApiService(it).get(url, mapOf()).execute() + val response = + HttpHelper.getApiService(it).getAsync(url, mapOf()).await() response.body()?.let { body -> val sources = mutableListOf() val items: List> = Restore.jsonPath.parse(body).read("$") From 8d8a2321787456ba8afda38e14281dd82da9cd2b Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 1 Jan 2020 12:43:40 +0800 Subject: [PATCH 46/85] up --- .../rss/source/manage/RssSourceViewModel.kt | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt index 0e458b3aa..6ee254029 100644 --- a/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/rss/source/manage/RssSourceViewModel.kt @@ -60,19 +60,20 @@ class RssSourceViewModel(application: Application) : BaseViewModel(application) } } - fun exportSelection(ids: LinkedHashSet) { - execute { - App.db.rssSourceDao().getRssSources(*ids.toTypedArray()).let { - val json = GSON.toJson(it) - val file = FileHelp.getFile(Backup.exportPath + File.separator + "exportRssSource.json") - file.writeText(json) - } - }.onSuccess { - context.toast("成功导出至\n${Backup.exportPath}") - }.onError { - context.toast("导出失败\n${it.localizedMessage}") - } - } + fun exportSelection(ids: LinkedHashSet) { + execute { + App.db.rssSourceDao().getRssSources(*ids.toTypedArray()).let { + val json = GSON.toJson(it) + val file = + FileHelp.getFile(Backup.exportPath + File.separator + "exportRssSource.json") + file.writeText(json) + } + }.onSuccess { + context.toast("成功导出至\n${Backup.exportPath}") + }.onError { + context.toast("导出失败\n${it.localizedMessage}") + } + } fun addGroup(group: String) { execute { @@ -165,7 +166,7 @@ class RssSourceViewModel(application: Application) : BaseViewModel(application) else -> "格式不对" } }.onError { - finally(it.localizedMessage) + finally(it.localizedMessage ?: "") }.onSuccess { finally(it ?: "导入完成") } From 9258598adc7aa86ad3b504e13a87111355eec9ea Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 1 Jan 2020 17:45:10 +0800 Subject: [PATCH 47/85] up --- app/src/main/res/menu/download.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/menu/download.xml b/app/src/main/res/menu/download.xml index 50dfdbeaa..cf4375f09 100644 --- a/app/src/main/res/menu/download.xml +++ b/app/src/main/res/menu/download.xml @@ -5,6 +5,7 @@
\ No newline at end of file From d81bb4c403d79c40784f4ace780b378b50cc9e63 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 1 Jan 2020 17:58:00 +0800 Subject: [PATCH 48/85] up --- .../java/io/legado/app/service/DownloadService.kt | 1 + .../io/legado/app/ui/download/DownloadActivity.kt | 14 ++++++++++++-- app/src/main/res/menu/download.xml | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/DownloadService.kt b/app/src/main/java/io/legado/app/service/DownloadService.kt index 798fcdfb8..d8bfae260 100644 --- a/app/src/main/java/io/legado/app/service/DownloadService.kt +++ b/app/src/main/java/io/legado/app/service/DownloadService.kt @@ -62,6 +62,7 @@ class DownloadService : BaseService() { searchPool.close() handler.removeCallbacks(runnable) super.onDestroy() + postEvent(Bus.UP_DOWNLOAD, false) } private fun download(bookUrl: String?, start: Int, end: Int) { diff --git a/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt b/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt index 9789bc273..a2ff5d99e 100644 --- a/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt +++ b/app/src/main/java/io/legado/app/ui/download/DownloadActivity.kt @@ -12,6 +12,7 @@ import io.legado.app.base.BaseActivity import io.legado.app.constant.Bus import io.legado.app.data.entities.Book import io.legado.app.service.help.Download +import io.legado.app.utils.applyTint import io.legado.app.utils.observeEvent import kotlinx.android.synthetic.main.activity_download.* import kotlinx.coroutines.Dispatchers.IO @@ -22,6 +23,7 @@ class DownloadActivity : BaseActivity(R.layout.activity_download) { lateinit var adapter: DownloadAdapter private var bookshelfLiveData: LiveData>? = null + private var menu: Menu? = null override fun onActivityCreated(savedInstanceState: Bundle?) { initRecyclerView() @@ -30,12 +32,13 @@ class DownloadActivity : BaseActivity(R.layout.activity_download) { override fun onCompatCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.download, menu) + this.menu = menu return super.onCompatCreateOptionsMenu(menu) } override fun onCompatOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { - R.id.menu_download_start -> launch(IO) { + R.id.menu_download -> launch(IO) { App.db.bookDao().webBooks.forEach { book -> Download.start( this@DownloadActivity, @@ -65,7 +68,14 @@ class DownloadActivity : BaseActivity(R.layout.activity_download) { override fun observeLiveBus() { observeEvent(Bus.UP_DOWNLOAD) { - adapter.notifyItemRangeChanged(0, adapter.itemCount, true) + if (it) { + menu?.findItem(R.id.menu_download)?.setIcon(R.drawable.ic_stop_black_24dp) + menu?.applyTint(this) + adapter.notifyItemRangeChanged(0, adapter.itemCount, true) + } else { + menu?.findItem(R.id.menu_download)?.setIcon(R.drawable.ic_play_24dp) + menu?.applyTint(this) + } } } } \ No newline at end of file diff --git a/app/src/main/res/menu/download.xml b/app/src/main/res/menu/download.xml index cf4375f09..452269d37 100644 --- a/app/src/main/res/menu/download.xml +++ b/app/src/main/res/menu/download.xml @@ -3,7 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> From 6326a28a1c35af709a70c195ad0cca99be34e373 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 1 Jan 2020 18:08:02 +0800 Subject: [PATCH 49/85] up --- .../legado/app/ui/book/source/manage/BookSourceViewModel.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt index 67b22be3f..6ae3bd977 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/manage/BookSourceViewModel.kt @@ -149,9 +149,11 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application) importSource(file.readText(), finally) } else { withContext(Dispatchers.Main) { - finally("文件无法打开") + finally("打开文件出错") } } + }.onError { + finally(it.localizedMessage ?: "打开文件出错") } } From 549156d6526ed8187e092f2fdaaaaf5ef22348b1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 1 Jan 2020 18:09:02 +0800 Subject: [PATCH 50/85] up --- .../io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt index fa6ca7ea4..aeb83a093 100644 --- a/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/source/edit/BookSourceEditActivity.kt @@ -91,7 +91,7 @@ class BookSourceEditActivity : GSON.toJson(getSource())?.let { sourceStr -> try { val textIntent = Intent(Intent.ACTION_SEND) - textIntent.setType("text/plain") + textIntent.type = "text/plain" textIntent.putExtra(Intent.EXTRA_TEXT, sourceStr) startActivity(Intent.createChooser(textIntent, "Source Share")) } catch (e: Exception) { From 7aa349bf39cdae94f4942763b184a1ea96183ccb Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 1 Jan 2020 18:36:24 +0800 Subject: [PATCH 51/85] up --- app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/pref_config_web_dav.xml | 40 +++++++++++--------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2d0ecb87c..2d16b399c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -96,6 +96,7 @@ 自动下载最新章节 更新书籍时自动下载最新章节 备份与恢复 + WebDav设置 WebDav设置/导入旧版本数据 备份 恢复 diff --git a/app/src/main/res/xml/pref_config_web_dav.xml b/app/src/main/res/xml/pref_config_web_dav.xml index 42733f458..0b4a84e09 100644 --- a/app/src/main/res/xml/pref_config_web_dav.xml +++ b/app/src/main/res/xml/pref_config_web_dav.xml @@ -2,23 +2,29 @@ - - - - - + + + + + + + + + From dadce9f8a70ef556894f95265f4248f98f88d049 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 1 Jan 2020 18:42:33 +0800 Subject: [PATCH 52/85] up --- app/src/main/res/values-night/colors.xml | 8 +++++--- app/src/main/res/values/colors.xml | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml index f9c4c4f7c..4933cfa2b 100644 --- a/app/src/main/res/values-night/colors.xml +++ b/app/src/main/res/values-night/colors.xml @@ -13,9 +13,11 @@ #30ffffff #363636 - #804D4D4D - #80686868 - #80C7C7C7 + + #634D4D4D + #63686868 + #63C7C7C7 + #66666666 #737373 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index da1e3c9b0..d150286a4 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -23,9 +23,9 @@ #d3321b - #80ACACAC - #80858585 - #802C2C2C + #63ACACAC + #63858585 + #632C2C2C #737373 #adadad From 66ff502e1f6f5e4af63a0156b35af54ca008a0ac Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 1 Jan 2020 19:27:45 +0800 Subject: [PATCH 53/85] up --- .../app/ui/config/WebDavConfigFragment.kt | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt index 9eb761712..2cb612578 100644 --- a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt @@ -1,5 +1,6 @@ package io.legado.app.ui.config +import android.content.Intent import android.os.Build import android.os.Bundle import android.text.InputType @@ -26,6 +27,8 @@ import io.legado.app.utils.getPrefString class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener { + private val oldDataRequestCode = 23156 + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { fun bindPreferenceSummaryToValue(preference: Preference?) { preference?.apply { @@ -105,7 +108,18 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference WebDavHelp.showRestoreDialog(requireContext()) } .request() - "import_old" -> needInstallApps { + "import_old" -> importOldData() + } + return super.onPreferenceTreeClick(preference) + } + + private fun importOldData() { + try { + val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + startActivityForResult(intent, oldDataRequestCode) + } catch (e: Exception) { + needInstallApps { alert(title = "导入") { message = "是否导入旧版本数据" yesButton { @@ -122,7 +136,6 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference }.show().applyTint() } } - return super.onPreferenceTreeClick(preference) } private fun needInstallApps(callback: () -> Unit) { @@ -147,4 +160,13 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference callback() } } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + when (requestCode) { + oldDataRequestCode -> { + + } + } + } } \ No newline at end of file From d41a19bb1329d090b64ee6bf99e010f26ec3de82 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 1 Jan 2020 20:28:32 +0800 Subject: [PATCH 54/85] up --- .../java/io/legado/app/ui/config/WebDavConfigFragment.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt index 2cb612578..88b5109f3 100644 --- a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt @@ -1,5 +1,6 @@ package io.legado.app.ui.config +import android.app.Activity.RESULT_OK import android.content.Intent import android.os.Build import android.os.Bundle @@ -164,8 +165,10 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) when (requestCode) { - oldDataRequestCode -> { + oldDataRequestCode -> if (resultCode == RESULT_OK) { + data?.data?.let { + } } } } From b6691472bf336d42d10fedda01bbdd7e5595051e Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 1 Jan 2020 21:18:17 +0800 Subject: [PATCH 55/85] up --- .../app/ui/config/WebDavConfigFragment.kt | 3 ++ .../java/io/legado/app/utils/DocumentUtils.kt | 31 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 app/src/main/java/io/legado/app/utils/DocumentUtils.kt diff --git a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt index 88b5109f3..3cfe0af2e 100644 --- a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt @@ -6,6 +6,7 @@ import android.os.Build import android.os.Bundle import android.text.InputType import android.view.View +import androidx.documentfile.provider.DocumentFile import androidx.preference.EditTextPreference import androidx.preference.ListPreference import androidx.preference.Preference @@ -167,7 +168,9 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference when (requestCode) { oldDataRequestCode -> if (resultCode == RESULT_OK) { data?.data?.let { + DocumentFile.fromTreeUri(requireContext(), it)?.listFiles()?.forEach { + } } } } diff --git a/app/src/main/java/io/legado/app/utils/DocumentUtils.kt b/app/src/main/java/io/legado/app/utils/DocumentUtils.kt new file mode 100644 index 000000000..276cfa473 --- /dev/null +++ b/app/src/main/java/io/legado/app/utils/DocumentUtils.kt @@ -0,0 +1,31 @@ +package io.legado.app.utils + +import android.content.Context +import android.net.Uri + +object DocumentUtils { + + fun readText(context: Context, uri: Uri): String? { + readBytes(context, uri)?.let { + return String(it) + } + return null + } + + fun readBytes(context: Context, uri: Uri): ByteArray? { + try { + context.contentResolver.openInputStream(uri)?.let { + val len: Int = it.available() + val buffer = ByteArray(len) + it.read(buffer) + it.close() + return buffer + } + } catch (e: Exception) { + e.printStackTrace() + } + return null + } + + +} \ No newline at end of file From 45d74ba7c1b9a32e580922e0fd33289f7fe76a14 Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 1 Jan 2020 21:23:22 +0800 Subject: [PATCH 56/85] up --- .../java/io/legado/app/utils/DocumentUtils.kt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/app/src/main/java/io/legado/app/utils/DocumentUtils.kt b/app/src/main/java/io/legado/app/utils/DocumentUtils.kt index 276cfa473..e10170892 100644 --- a/app/src/main/java/io/legado/app/utils/DocumentUtils.kt +++ b/app/src/main/java/io/legado/app/utils/DocumentUtils.kt @@ -5,6 +5,23 @@ import android.net.Uri object DocumentUtils { + fun writeText(context: Context, data: String, fileUri: Uri): Boolean { + return writeBytes(context, data.toByteArray(), fileUri) + } + + fun writeBytes(context: Context, data: ByteArray, fileUri: Uri): Boolean { + try { + context.contentResolver.openOutputStream(fileUri)?.let { + it.write(data) + it.close() + return true + } + } catch (e: java.lang.Exception) { + e.printStackTrace() + } + return false + } + fun readText(context: Context, uri: Uri): String? { readBytes(context, uri)?.let { return String(it) From a64d5b8cfb38654bde3c5f3f665cc6838521dbea Mon Sep 17 00:00:00 2001 From: kunfei Date: Wed, 1 Jan 2020 21:52:13 +0800 Subject: [PATCH 57/85] up --- .../io/legado/app/help/storage/OldRule.kt | 1 + .../io/legado/app/help/storage/Restore.kt | 157 ++++++++++-------- .../app/ui/config/WebDavConfigFragment.kt | 25 ++- 3 files changed, 108 insertions(+), 75 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/storage/OldRule.kt b/app/src/main/java/io/legado/app/help/storage/OldRule.kt index 0c9baa659..14b4a9c53 100644 --- a/app/src/main/java/io/legado/app/help/storage/OldRule.kt +++ b/app/src/main/java/io/legado/app/help/storage/OldRule.kt @@ -205,4 +205,5 @@ object OldRule { return GSON.toJson(map) } + } diff --git a/app/src/main/java/io/legado/app/help/storage/Restore.kt b/app/src/main/java/io/legado/app/help/storage/Restore.kt index b2e34783e..920d61c0d 100644 --- a/app/src/main/java/io/legado/app/help/storage/Restore.kt +++ b/app/src/main/java/io/legado/app/help/storage/Restore.kt @@ -111,47 +111,12 @@ object Restore { fun importYueDuData(context: Context) { GlobalScope.launch(IO) { try {// 导入书架 - val shelfFile = FileHelp.getFile(Backup.defaultPath + File.separator + "myBookShelf.json") - val books = mutableListOf() - val items: List> = jsonPath.parse(shelfFile.readText()).read("$") - val existingBooks = App.db.bookDao().allBookUrls.toSet() - for (item in items) { - val jsonItem = jsonPath.parse(item) - val book = Book() - book.bookUrl = jsonItem.readString("$.noteUrl") ?: "" - if (book.bookUrl.isBlank()) continue - book.name = jsonItem.readString("$.bookInfoBean.name") ?: "" - if (book.bookUrl in existingBooks) { - Log.d(AppConst.APP_TAG, "Found existing book: ${book.name}") - continue - } - book.origin = jsonItem.readString("$.tag") ?: "" - book.originName = jsonItem.readString("$.bookInfoBean.origin") ?: "" - book.author = jsonItem.readString("$.bookInfoBean.author") ?: "" - book.type = - if (jsonItem.readString("$.bookInfoBean.bookSourceType") == "AUDIO") 1 else 0 - book.tocUrl = jsonItem.readString("$.bookInfoBean.chapterUrl") ?: book.bookUrl - book.coverUrl = jsonItem.readString("$.bookInfoBean.coverUrl") - book.customCoverUrl = jsonItem.readString("$.customCoverPath") - book.lastCheckTime = jsonItem.readLong("$.bookInfoBean.finalRefreshData") ?: 0 - book.canUpdate = jsonItem.readBool("$.allowUpdate") == true - book.totalChapterNum = jsonItem.readInt("$.chapterListSize") ?: 0 - book.durChapterIndex = jsonItem.readInt("$.durChapter") ?: 0 - book.durChapterTitle = jsonItem.readString("$.durChapterName") - book.durChapterPos = jsonItem.readInt("$.durChapterPage") ?: 0 - book.durChapterTime = jsonItem.readLong("$.finalDate") ?: 0 - book.group = jsonItem.readInt("$.group") ?: 0 - book.intro = jsonItem.readString("$.bookInfoBean.introduce") - book.latestChapterTitle = jsonItem.readString("$.lastChapterName") - book.lastCheckCount = jsonItem.readInt("$.newChapters") ?: 0 - book.order = jsonItem.readInt("$.serialNumber") ?: 0 - book.useReplaceRule = jsonItem.readBool("$.useReplaceRule") == true - book.variable = jsonItem.readString("$.variable") - books.add(book) - } - App.db.bookDao().insert(*books.toTypedArray()) + val shelfFile = + FileHelp.getFile(Backup.defaultPath + File.separator + "myBookShelf.json") + val json = shelfFile.readText() + val importCount = importOldBookshelf(json) withContext(Main) { - context.toast("成功导入书籍${books.size}") + context.toast("成功导入书籍${importCount}") } } catch (e: Exception) { withContext(Main) { @@ -162,17 +127,10 @@ object Restore { try {// Book source val sourceFile = FileHelp.getFile(Backup.defaultPath + File.separator + "myBookSource.json") - val bookSources = mutableListOf() - val items: List> = jsonPath.parse(sourceFile.readText()).read("$") - for (item in items) { - val jsonItem = jsonPath.parse(item) - OldRule.jsonToBookSource(jsonItem.jsonString())?.let { - bookSources.add(it) - } - } - App.db.bookSourceDao().insert(*bookSources.toTypedArray()) + val json = sourceFile.readText() + val importCount = importOldSource(json) withContext(Main) { - context.toast("成功导入书源${bookSources.size}") + context.toast("成功导入书源${importCount}") } } catch (e: Exception) { withContext(Main) { @@ -183,26 +141,10 @@ object Restore { try {// Replace rules val ruleFile = FileHelp.getFile(Backup.defaultPath + File.separator + "myBookReplaceRule.json") - val replaceRules = mutableListOf() - val items: List> = jsonPath.parse(ruleFile.readText()).read("$") - val existingRules = App.db.replaceRuleDao().all.map { it.pattern }.toSet() - for ((index: Int, item: Map) in items.withIndex()) { - val jsonItem = jsonPath.parse(item) - val rule = ReplaceRule() - rule.id = jsonItem.readLong("$.id") ?: System.currentTimeMillis().plus(index) - rule.pattern = jsonItem.readString("$.regex") ?: "" - if (rule.pattern.isEmpty() || rule.pattern in existingRules) continue - rule.name = jsonItem.readString("$.replaceSummary") ?: "" - rule.replacement = jsonItem.readString("$.replacement") ?: "" - rule.isRegex = jsonItem.readBool("$.isRegex") == true - rule.scope = jsonItem.readString("$.useTo") - rule.isEnabled = jsonItem.readBool("$.enable") == true - rule.order = jsonItem.readInt("$.serialNumber") ?: index - replaceRules.add(rule) - } - App.db.replaceRuleDao().insert(*replaceRules.toTypedArray()) + val json = ruleFile.readText() + val importCount = importOldReplaceRule(json) withContext(Main) { - context.toast("成功导入替换规则${replaceRules.size}") + context.toast("成功导入替换规则${importCount}") } } catch (e: Exception) { withContext(Main) { @@ -211,4 +153,81 @@ object Restore { } } } + + fun importOldBookshelf(json: String): Int { + val books = mutableListOf() + val items: List> = jsonPath.parse(json).read("$") + val existingBooks = App.db.bookDao().allBookUrls.toSet() + for (item in items) { + val jsonItem = jsonPath.parse(item) + val book = Book() + book.bookUrl = jsonItem.readString("$.noteUrl") ?: "" + if (book.bookUrl.isBlank()) continue + book.name = jsonItem.readString("$.bookInfoBean.name") ?: "" + if (book.bookUrl in existingBooks) { + Log.d(AppConst.APP_TAG, "Found existing book: ${book.name}") + continue + } + book.origin = jsonItem.readString("$.tag") ?: "" + book.originName = jsonItem.readString("$.bookInfoBean.origin") ?: "" + book.author = jsonItem.readString("$.bookInfoBean.author") ?: "" + book.type = + if (jsonItem.readString("$.bookInfoBean.bookSourceType") == "AUDIO") 1 else 0 + book.tocUrl = jsonItem.readString("$.bookInfoBean.chapterUrl") ?: book.bookUrl + book.coverUrl = jsonItem.readString("$.bookInfoBean.coverUrl") + book.customCoverUrl = jsonItem.readString("$.customCoverPath") + book.lastCheckTime = jsonItem.readLong("$.bookInfoBean.finalRefreshData") ?: 0 + book.canUpdate = jsonItem.readBool("$.allowUpdate") == true + book.totalChapterNum = jsonItem.readInt("$.chapterListSize") ?: 0 + book.durChapterIndex = jsonItem.readInt("$.durChapter") ?: 0 + book.durChapterTitle = jsonItem.readString("$.durChapterName") + book.durChapterPos = jsonItem.readInt("$.durChapterPage") ?: 0 + book.durChapterTime = jsonItem.readLong("$.finalDate") ?: 0 + book.group = jsonItem.readInt("$.group") ?: 0 + book.intro = jsonItem.readString("$.bookInfoBean.introduce") + book.latestChapterTitle = jsonItem.readString("$.lastChapterName") + book.lastCheckCount = jsonItem.readInt("$.newChapters") ?: 0 + book.order = jsonItem.readInt("$.serialNumber") ?: 0 + book.useReplaceRule = jsonItem.readBool("$.useReplaceRule") == true + book.variable = jsonItem.readString("$.variable") + books.add(book) + } + App.db.bookDao().insert(*books.toTypedArray()) + return books.size + } + + fun importOldSource(json: String): Int { + val bookSources = mutableListOf() + val items: List> = jsonPath.parse(json).read("$") + for (item in items) { + val jsonItem = jsonPath.parse(item) + OldRule.jsonToBookSource(jsonItem.jsonString())?.let { + bookSources.add(it) + } + } + App.db.bookSourceDao().insert(*bookSources.toTypedArray()) + return bookSources.size + } + + fun importOldReplaceRule(json: String): Int { + val replaceRules = mutableListOf() + val items: List> = jsonPath.parse(json).read("$") + val existingRules = App.db.replaceRuleDao().all.map { it.pattern }.toSet() + for ((index: Int, item: Map) in items.withIndex()) { + val jsonItem = jsonPath.parse(item) + val rule = ReplaceRule() + rule.id = jsonItem.readLong("$.id") ?: System.currentTimeMillis().plus(index) + rule.pattern = jsonItem.readString("$.regex") ?: "" + if (rule.pattern.isEmpty() || rule.pattern in existingRules) continue + rule.name = jsonItem.readString("$.replaceSummary") ?: "" + rule.replacement = jsonItem.readString("$.replacement") ?: "" + rule.isRegex = jsonItem.readBool("$.isRegex") == true + rule.scope = jsonItem.readString("$.useTo") + rule.isEnabled = jsonItem.readBool("$.enable") == true + rule.order = jsonItem.readInt("$.serialNumber") ?: index + replaceRules.add(rule) + } + App.db.replaceRuleDao().insert(*replaceRules.toTypedArray()) + return replaceRules.size + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt index 3cfe0af2e..0ccf98f7c 100644 --- a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt @@ -23,6 +23,7 @@ import io.legado.app.lib.dialogs.noButton import io.legado.app.lib.dialogs.yesButton import io.legado.app.lib.theme.ATH import io.legado.app.lib.theme.accentColor +import io.legado.app.utils.DocumentUtils import io.legado.app.utils.LogUtils import io.legado.app.utils.applyTint import io.legado.app.utils.getPrefString @@ -142,7 +143,7 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference private fun needInstallApps(callback: () -> Unit) { - fun canRequestPackageInstalls() :Boolean { + fun canRequestPackageInstalls(): Boolean { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { return requireContext().packageManager.canRequestPackageInstalls() } @@ -158,7 +159,7 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference } }.show().applyTint() } else { - LogUtils.d("xxx","import old") + LogUtils.d("xxx", "import old") callback() } } @@ -166,13 +167,25 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) when (requestCode) { - oldDataRequestCode -> if (resultCode == RESULT_OK) { - data?.data?.let { - DocumentFile.fromTreeUri(requireContext(), it)?.listFiles()?.forEach { - + oldDataRequestCode -> if (resultCode == RESULT_OK) data?.data?.let { uri -> + DocumentFile.fromTreeUri(requireContext(), uri)?.listFiles()?.forEach { + when (it.name) { + "myBookShelf.json" -> + DocumentUtils.readText(requireContext(), it.uri)?.let { json -> + Restore.importOldBookshelf(json) + } + "myBookSource.json" -> + DocumentUtils.readText(requireContext(), it.uri)?.let { json -> + Restore.importOldSource(json) + } + "myBookReplaceRule.json" -> + DocumentUtils.readText(requireContext(), it.uri)?.let { json -> + Restore.importOldReplaceRule(json) + } } } } + } } } \ No newline at end of file From d3541b7e536e24be7642f8554868a39045ee38de Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 2 Jan 2020 10:34:42 +0800 Subject: [PATCH 58/85] up --- .../legado/app/base/BasePreferenceFragment.kt | 27 +++++++ .../app/ui/config/WebDavConfigFragment.kt | 78 ++++++++++++++----- 2 files changed, 86 insertions(+), 19 deletions(-) create mode 100644 app/src/main/java/io/legado/app/base/BasePreferenceFragment.kt diff --git a/app/src/main/java/io/legado/app/base/BasePreferenceFragment.kt b/app/src/main/java/io/legado/app/base/BasePreferenceFragment.kt new file mode 100644 index 000000000..b2c07d63f --- /dev/null +++ b/app/src/main/java/io/legado/app/base/BasePreferenceFragment.kt @@ -0,0 +1,27 @@ +package io.legado.app.base + +import android.os.Bundle +import androidx.preference.PreferenceFragmentCompat +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlin.coroutines.CoroutineContext + + +abstract class BasePreferenceFragment : PreferenceFragmentCompat(), CoroutineScope { + + lateinit var job: Job + + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + override fun onCreate(savedInstanceState: Bundle?) { + job = Job() + super.onCreate(savedInstanceState) + } + + override fun onDestroy() { + super.onDestroy() + job.cancel() + } +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt index 0ccf98f7c..68fc6780a 100644 --- a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt @@ -2,6 +2,7 @@ package io.legado.app.ui.config import android.app.Activity.RESULT_OK import android.content.Intent +import android.net.Uri import android.os.Build import android.os.Bundle import android.text.InputType @@ -10,8 +11,8 @@ import androidx.documentfile.provider.DocumentFile import androidx.preference.EditTextPreference import androidx.preference.ListPreference import androidx.preference.Preference -import androidx.preference.PreferenceFragmentCompat import io.legado.app.R +import io.legado.app.base.BasePreferenceFragment import io.legado.app.help.IntentHelp import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat @@ -27,8 +28,13 @@ import io.legado.app.utils.DocumentUtils import io.legado.app.utils.LogUtils import io.legado.app.utils.applyTint import io.legado.app.utils.getPrefString +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.jetbrains.anko.toast -class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener { +class WebDavConfigFragment : BasePreferenceFragment(), Preference.OnPreferenceChangeListener { private val oldDataRequestCode = 23156 @@ -141,6 +147,54 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference } } + private fun importOldData(uri: Uri) { + launch(IO) { + DocumentFile.fromTreeUri(requireContext(), uri)?.listFiles()?.forEach { + when (it.name) { + "myBookShelf.json" -> + try { + DocumentUtils.readText(requireContext(), it.uri)?.let { json -> + val importCount = Restore.importOldBookshelf(json) + withContext(Dispatchers.Main) { + requireContext().toast("成功导入书籍${importCount}") + } + } + } catch (e: java.lang.Exception) { + withContext(Dispatchers.Main) { + requireContext().toast("导入书籍失败\n${e.localizedMessage}") + } + } + "myBookSource.json" -> + try { + DocumentUtils.readText(requireContext(), it.uri)?.let { json -> + val importCount = Restore.importOldSource(json) + withContext(Dispatchers.Main) { + requireContext().toast("成功导入书源${importCount}") + } + } + } catch (e: Exception) { + withContext(Dispatchers.Main) { + requireContext().toast("导入源失败\n${e.localizedMessage}") + } + } + "myBookReplaceRule.json" -> + try { + DocumentUtils.readText(requireContext(), it.uri)?.let { json -> + val importCount = Restore.importOldReplaceRule(json) + withContext(Dispatchers.Main) { + requireContext().toast("成功导入替换规则${importCount}") + } + } + } catch (e: Exception) { + withContext(Dispatchers.Main) { + requireContext().toast("导入替换规则失败\n${e.localizedMessage}") + } + } + } + } + } + } + private fun needInstallApps(callback: () -> Unit) { fun canRequestPackageInstalls(): Boolean { @@ -167,24 +221,10 @@ class WebDavConfigFragment : PreferenceFragmentCompat(), Preference.OnPreference override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) when (requestCode) { - oldDataRequestCode -> if (resultCode == RESULT_OK) data?.data?.let { uri -> - DocumentFile.fromTreeUri(requireContext(), uri)?.listFiles()?.forEach { - when (it.name) { - "myBookShelf.json" -> - DocumentUtils.readText(requireContext(), it.uri)?.let { json -> - Restore.importOldBookshelf(json) - } - "myBookSource.json" -> - DocumentUtils.readText(requireContext(), it.uri)?.let { json -> - Restore.importOldSource(json) - } - "myBookReplaceRule.json" -> - DocumentUtils.readText(requireContext(), it.uri)?.let { json -> - Restore.importOldReplaceRule(json) - } - } + oldDataRequestCode -> + if (resultCode == RESULT_OK) data?.data?.let { uri -> + importOldData(uri) } - } } } From b972679f6a14375065652284a16adeef1a98b598 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 2 Jan 2020 16:16:41 +0800 Subject: [PATCH 59/85] up --- .../legado/app/base/BasePreferenceFragment.kt | 27 ----- .../java/io/legado/app/constant/PreferKey.kt | 1 + .../ui/book/read/config/ReadStyleDialog.kt | 17 +-- .../app/ui/config/WebDavConfigFragment.kt | 22 +++- .../app/ui/widget/font/FontSelectDialog.kt | 108 +++++++++++------- .../java/io/legado/app/utils/DocumentUtils.kt | 4 + .../main/res/layout/dialog_font_select.xml | 16 ++- 7 files changed, 102 insertions(+), 93 deletions(-) delete mode 100644 app/src/main/java/io/legado/app/base/BasePreferenceFragment.kt diff --git a/app/src/main/java/io/legado/app/base/BasePreferenceFragment.kt b/app/src/main/java/io/legado/app/base/BasePreferenceFragment.kt deleted file mode 100644 index b2c07d63f..000000000 --- a/app/src/main/java/io/legado/app/base/BasePreferenceFragment.kt +++ /dev/null @@ -1,27 +0,0 @@ -package io.legado.app.base - -import android.os.Bundle -import androidx.preference.PreferenceFragmentCompat -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlin.coroutines.CoroutineContext - - -abstract class BasePreferenceFragment : PreferenceFragmentCompat(), CoroutineScope { - - lateinit var job: Job - - override val coroutineContext: CoroutineContext - get() = job + Dispatchers.Main - - override fun onCreate(savedInstanceState: Bundle?) { - job = Job() - super.onCreate(savedInstanceState) - } - - override fun onDestroy() { - super.onDestroy() - job.cancel() - } -} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/constant/PreferKey.kt b/app/src/main/java/io/legado/app/constant/PreferKey.kt index c777fdb9a..bc74ed1ab 100644 --- a/app/src/main/java/io/legado/app/constant/PreferKey.kt +++ b/app/src/main/java/io/legado/app/constant/PreferKey.kt @@ -16,4 +16,5 @@ object PreferKey { const val lastGroup = "lastGroup" const val pageAnim = "pageAnim" const val readBookFont = "readBookFont" + const val fontFolder = "fontFolder" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt index 098edad43..e19231b4a 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt @@ -20,7 +20,10 @@ import io.legado.app.lib.theme.primaryColor import io.legado.app.ui.book.read.Help import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.ui.widget.font.FontSelectDialog -import io.legado.app.utils.* +import io.legado.app.utils.getPrefInt +import io.legado.app.utils.postEvent +import io.legado.app.utils.progressAdd +import io.legado.app.utils.putPrefInt import kotlinx.android.synthetic.main.activity_book_read.* import kotlinx.android.synthetic.main.dialog_read_book_style.* import org.jetbrains.anko.sdk27.listeners.onCheckedChange @@ -86,17 +89,7 @@ class ReadStyleDialog : DialogFragment() { postEvent(Bus.UP_CONFIG, false) } tv_text_font.onClick { - FontSelectDialog(requireContext()).apply { - curPath = requireContext().getPrefString(PreferKey.readBookFont) - defaultFont = { - requireContext().putPrefString(PreferKey.readBookFont, "") - postEvent(Bus.UP_CONFIG, true) - } - selectFile = { - requireContext().putPrefString(PreferKey.readBookFont, it) - postEvent(Bus.UP_CONFIG, true) - } - }.show() + FontSelectDialog().show(childFragmentManager, "fontSelectDialog") } tv_text_indent.onClick { selector( diff --git a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt index 68fc6780a..28f9c825d 100644 --- a/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/WebDavConfigFragment.kt @@ -11,8 +11,8 @@ import androidx.documentfile.provider.DocumentFile import androidx.preference.EditTextPreference import androidx.preference.ListPreference import androidx.preference.Preference +import androidx.preference.PreferenceFragmentCompat import io.legado.app.R -import io.legado.app.base.BasePreferenceFragment import io.legado.app.help.IntentHelp import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat @@ -28,17 +28,22 @@ import io.legado.app.utils.DocumentUtils import io.legado.app.utils.LogUtils import io.legado.app.utils.applyTint import io.legado.app.utils.getPrefString -import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import org.jetbrains.anko.toast +import kotlin.coroutines.CoroutineContext -class WebDavConfigFragment : BasePreferenceFragment(), Preference.OnPreferenceChangeListener { - +class WebDavConfigFragment : PreferenceFragmentCompat(), + Preference.OnPreferenceChangeListener, + CoroutineScope { + lateinit var job: Job private val oldDataRequestCode = 23156 + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + job = Job() fun bindPreferenceSummaryToValue(preference: Preference?) { preference?.apply { onPreferenceChangeListener = this@WebDavConfigFragment @@ -76,6 +81,11 @@ class WebDavConfigFragment : BasePreferenceFragment(), Preference.OnPreferenceCh ATH.applyEdgeEffectColor(listView) } + override fun onDestroy() { + super.onDestroy() + job.cancel() + } + override fun onPreferenceChange(preference: Preference?, newValue: Any?): Boolean { when { preference?.key == "web_dav_password" -> if (newValue == null) { diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index b276072b4..f95923f1e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -1,68 +1,83 @@ package io.legado.app.ui.widget.font import android.annotation.SuppressLint -import android.content.Context -import android.os.Environment +import android.app.Activity.RESULT_OK +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.util.DisplayMetrics import android.view.LayoutInflater import android.view.View -import androidx.appcompat.app.AlertDialog +import android.view.ViewGroup +import androidx.documentfile.provider.DocumentFile +import androidx.fragment.app.DialogFragment import androidx.recyclerview.widget.LinearLayoutManager +import io.legado.app.App import io.legado.app.R -import io.legado.app.lib.dialogs.AlertBuilder -import io.legado.app.lib.dialogs.alert -import io.legado.app.utils.applyTint -import io.legado.app.utils.invisible -import io.legado.app.utils.visible -import kotlinx.android.synthetic.main.dialog_font_select.view.* +import io.legado.app.constant.PreferKey +import io.legado.app.help.FileHelp +import io.legado.app.utils.DocumentUtils +import io.legado.app.utils.getPrefString +import kotlinx.android.synthetic.main.dialog_font_select.* import java.io.File -class FontSelectDialog(context: Context) : FontAdapter.CallBack { - - private val defaultFolder = - Environment.getExternalStorageDirectory().absolutePath + File.separator + "Fonts" +class FontSelectDialog : DialogFragment(), FontAdapter.CallBack { + private val fontFolderRequestCode = 35485 private lateinit var adapter: FontAdapter - private var builder: AlertBuilder - private var dialog: AlertDialog? = null - @SuppressLint("InflateParams") - private var view: View = LayoutInflater.from(context).inflate(R.layout.dialog_font_select, null) var curPath: String? = null - var fontFolder: String? = null + val fontFolder = App.INSTANCE.filesDir.absolutePath + File.separator + "Fonts" + File.separator var defaultFont: (() -> Unit)? = null var selectFile: ((path: String) -> Unit)? = null - init { - builder = context.alert(title = context.getString(R.string.select_font)) { - customView = view - positiveButton(R.string.default_font) { defaultFont?.invoke() } - negativeButton(R.string.cancel) - } - initData() + override fun onStart() { + super.onStart() + val dm = DisplayMetrics() + activity?.windowManager?.defaultDisplay?.getMetrics(dm) + dialog?.window?.setLayout((dm.widthPixels * 0.9).toInt(), (dm.heightPixels * 0.9).toInt()) } - fun show() { - dialog = builder.show().applyTint() + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + return inflater.inflate(R.layout.dialog_font_select, container) } - private fun initData() = with(view) { - adapter = FontAdapter(context, this@FontSelectDialog) + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + tool_bar.setTitle(R.string.select_font) + adapter = FontAdapter(requireContext(), this) recycler_view.layoutManager = LinearLayoutManager(context) recycler_view.adapter = adapter - val files = getFontFiles() - if (files.isNullOrEmpty()) { - tv_no_data.visible() - } else { - tv_no_data.invisible() - adapter.setItems(files.toList()) + + val fontPath = getPrefString(PreferKey.fontFolder) + if (fontPath.isNullOrEmpty()) { + try { + val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + startActivityForResult(intent, fontFolderRequestCode) + } catch (e: java.lang.Exception) { + + } + } + } + + @SuppressLint("DefaultLocale") + private fun getFontFiles(uri: Uri) { + DocumentFile.fromTreeUri(requireContext(), uri)?.listFiles()?.forEach { file -> + if (file.name?.toLowerCase()?.matches(".*\\.[ot]tf".toRegex()) == true) { + DocumentUtils.readBytes(App.INSTANCE, file.uri)?.let { + FileHelp.getFile(fontFolder + file.name).writeBytes(it) + } + } } } @SuppressLint("DefaultLocale") private fun getFontFiles(): Array? { - val path = if (fontFolder.isNullOrEmpty()) { - defaultFolder - } else fontFolder return try { - val file = File(path) + val file = File(fontFolder) file.listFiles { pathName -> pathName.name.toLowerCase().matches(".*\\.[ot]tf".toRegex()) } @@ -83,4 +98,19 @@ class FontSelectDialog(context: Context) : FontAdapter.CallBack { override fun curFilePath(): String { return curPath ?: "" } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + when (requestCode) { + fontFolderRequestCode -> if (resultCode == RESULT_OK) { + data?.data?.let { uri -> + getFontFiles(uri) + } + } + } + } + + interface CallBack { + fun selectFile(uri: Uri) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/utils/DocumentUtils.kt b/app/src/main/java/io/legado/app/utils/DocumentUtils.kt index e10170892..dcb128a8e 100644 --- a/app/src/main/java/io/legado/app/utils/DocumentUtils.kt +++ b/app/src/main/java/io/legado/app/utils/DocumentUtils.kt @@ -5,10 +5,12 @@ import android.net.Uri object DocumentUtils { + @JvmStatic fun writeText(context: Context, data: String, fileUri: Uri): Boolean { return writeBytes(context, data.toByteArray(), fileUri) } + @JvmStatic fun writeBytes(context: Context, data: ByteArray, fileUri: Uri): Boolean { try { context.contentResolver.openOutputStream(fileUri)?.let { @@ -22,6 +24,7 @@ object DocumentUtils { return false } + @JvmStatic fun readText(context: Context, uri: Uri): String? { readBytes(context, uri)?.let { return String(it) @@ -29,6 +32,7 @@ object DocumentUtils { return null } + @JvmStatic fun readBytes(context: Context, uri: Uri): ByteArray? { try { context.contentResolver.openInputStream(uri)?.let { diff --git a/app/src/main/res/layout/dialog_font_select.xml b/app/src/main/res/layout/dialog_font_select.xml index 08e33c0a9..60f080003 100644 --- a/app/src/main/res/layout/dialog_font_select.xml +++ b/app/src/main/res/layout/dialog_font_select.xml @@ -1,20 +1,18 @@ - - - + android:layout_height="match_parent" /> - \ No newline at end of file + \ No newline at end of file From 82dce02541c09c561bfe1d540ae355b84a4e4df0 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 2 Jan 2020 16:35:55 +0800 Subject: [PATCH 60/85] up --- .../main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index f95923f1e..5934bd08f 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -25,7 +25,8 @@ class FontSelectDialog : DialogFragment(), FontAdapter.CallBack { private val fontFolderRequestCode = 35485 private lateinit var adapter: FontAdapter var curPath: String? = null - val fontFolder = App.INSTANCE.filesDir.absolutePath + File.separator + "Fonts" + File.separator + private val fontFolder = + App.INSTANCE.filesDir.absolutePath + File.separator + "Fonts" + File.separator var defaultFont: (() -> Unit)? = null var selectFile: ((path: String) -> Unit)? = null From e49a512185399b887b37747827441ed8a7eba1b7 Mon Sep 17 00:00:00 2001 From: kunfei Date: Thu, 2 Jan 2020 16:45:42 +0800 Subject: [PATCH 61/85] up --- .../app/ui/widget/font/FontSelectDialog.kt | 53 +++++++++++++------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index 5934bd08f..eb1f7eeb6 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -18,10 +18,21 @@ import io.legado.app.constant.PreferKey import io.legado.app.help.FileHelp import io.legado.app.utils.DocumentUtils import io.legado.app.utils.getPrefString +import io.legado.app.utils.toast import kotlinx.android.synthetic.main.dialog_font_select.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.Dispatchers.Main +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import java.io.File +import kotlin.coroutines.CoroutineContext -class FontSelectDialog : DialogFragment(), FontAdapter.CallBack { +class FontSelectDialog : DialogFragment(), + CoroutineScope, + FontAdapter.CallBack { + lateinit var job: Job private val fontFolderRequestCode = 35485 private lateinit var adapter: FontAdapter var curPath: String? = null @@ -29,6 +40,8 @@ class FontSelectDialog : DialogFragment(), FontAdapter.CallBack { App.INSTANCE.filesDir.absolutePath + File.separator + "Fonts" + File.separator var defaultFont: (() -> Unit)? = null var selectFile: ((path: String) -> Unit)? = null + override val coroutineContext: CoroutineContext + get() = job + Main override fun onStart() { super.onStart() @@ -42,6 +55,7 @@ class FontSelectDialog : DialogFragment(), FontAdapter.CallBack { container: ViewGroup?, savedInstanceState: Bundle? ): View? { + job = Job() return inflater.inflate(R.layout.dialog_font_select, container) } @@ -64,26 +78,33 @@ class FontSelectDialog : DialogFragment(), FontAdapter.CallBack { } } + override fun onDestroy() { + super.onDestroy() + job.cancel() + } + @SuppressLint("DefaultLocale") private fun getFontFiles(uri: Uri) { - DocumentFile.fromTreeUri(requireContext(), uri)?.listFiles()?.forEach { file -> - if (file.name?.toLowerCase()?.matches(".*\\.[ot]tf".toRegex()) == true) { - DocumentUtils.readBytes(App.INSTANCE, file.uri)?.let { - FileHelp.getFile(fontFolder + file.name).writeBytes(it) + launch(IO) { + DocumentFile.fromTreeUri(requireContext(), uri)?.listFiles()?.forEach { file -> + if (file.name?.toLowerCase()?.matches(".*\\.[ot]tf".toRegex()) == true) { + DocumentUtils.readBytes(App.INSTANCE, file.uri)?.let { + FileHelp.getFile(fontFolder + file.name).writeBytes(it) + } } } - } - } - - @SuppressLint("DefaultLocale") - private fun getFontFiles(): Array? { - return try { - val file = File(fontFolder) - file.listFiles { pathName -> - pathName.name.toLowerCase().matches(".*\\.[ot]tf".toRegex()) + try { + val file = File(fontFolder) + file.listFiles { pathName -> + pathName.name.toLowerCase().matches(".*\\.[ot]tf".toRegex()) + }?.let { + withContext(Main) { + adapter.setItems(it.toList()) + } + } + } catch (e: Exception) { + toast(e.localizedMessage ?: "") } - } catch (e: Exception) { - null } } From 30ddbec3a64e881ef7494ba4a14d9a911c6f9bc6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 3 Jan 2020 10:30:56 +0800 Subject: [PATCH 62/85] up --- .../main/java/io/legado/app/ui/about/DonateActivity.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt b/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt index 107be8809..18c8730e4 100644 --- a/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt +++ b/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt @@ -34,10 +34,10 @@ class DonateActivity : BaseActivity(R.layout.activity_donate) { toast(R.string.copy_complete) } } - vw_zfb_hb.setOnClickListener { openActionViewIntent("https://gedoor.github.io/MyBookshelf/zfbhbrwm.png") } - vw_zfb_rwm.setOnClickListener { openActionViewIntent("https://gedoor.github.io/MyBookshelf/zfbskrwm.jpg") } - vw_wx_rwm.setOnClickListener { openActionViewIntent("https://gedoor.github.io/MyBookshelf/wxskrwm.jpg") } - vw_qq_rwm.setOnClickListener { openActionViewIntent("https://gedoor.github.io/MyBookshelf/qqskrwm.jpg") } + vw_zfb_hb.setOnClickListener { openActionViewIntent("https://gitee.com/gekunfei/Donate/raw/master/zfbhbrwm.png") } + vw_zfb_rwm.setOnClickListener { openActionViewIntent("https://gitee.com/gekunfei/Donate/raw/master/zfbskrwm.jpg") } + vw_wx_rwm.setOnClickListener { openActionViewIntent("https://gitee.com/gekunfei/Donate/raw/master/wxskrwm.jpg") } + vw_qq_rwm.setOnClickListener { openActionViewIntent("https://gitee.com/gekunfei/Donate/raw/master/qqskrwm.jpg") } vw_zfb_hb_ssm.setOnClickListener { getZfbHb(this) } } From 7629542e1d669bdcbe85cef8232421ac54a6e6ef Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 3 Jan 2020 10:41:14 +0800 Subject: [PATCH 63/85] up --- app/src/main/java/io/legado/app/ui/about/DonateActivity.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt b/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt index 18c8730e4..870f85f53 100644 --- a/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt +++ b/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt @@ -75,9 +75,10 @@ class DonateActivity : BaseActivity(R.layout.activity_donate) { private fun aliDonate(context: Context) { try { - val qrCode = URLEncoder.encode("tsx06677nwdk3javroq4ef0", "utf-8") - val aliPayQr = - "alipayqr://platformapi/startapp?saId=10000007&qrcode=https://qr.alipay.com/$qrCode" + var qrCode = URLEncoder.encode("https://qr.alipay.com/tsx06677nwdk3javroq4ef0", "utf-8") + qrCode = "qrcode=$qrCode%3F_s%3Dweb-other" + qrCode = "saId=10000007&$qrCode&_t=${System.currentTimeMillis()}" + val aliPayQr = "alipayqr://platformapi/startapp?$qrCode" val intent = Intent(Intent.ACTION_VIEW, Uri.parse(aliPayQr)) context.startActivity(intent) } catch (e: Exception) { From 776ce45ef28be5ed65e96fa53418ecc88166b88c Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 3 Jan 2020 10:52:50 +0800 Subject: [PATCH 64/85] up --- .../main/java/io/legado/app/ui/about/DonateActivity.kt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt b/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt index 870f85f53..61cf11177 100644 --- a/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt +++ b/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt @@ -75,10 +75,12 @@ class DonateActivity : BaseActivity(R.layout.activity_donate) { private fun aliDonate(context: Context) { try { - var qrCode = URLEncoder.encode("https://qr.alipay.com/tsx06677nwdk3javroq4ef0", "utf-8") - qrCode = "qrcode=$qrCode%3F_s%3Dweb-other" - qrCode = "saId=10000007&$qrCode&_t=${System.currentTimeMillis()}" - val aliPayQr = "alipayqr://platformapi/startapp?$qrCode" + val qrCode = URLEncoder.encode( + "https://qr.alipay.com/fkx03463i8oppupkpsoo1f?_s=Dweb-other", + "utf-8" + ) + val aliPayQr = + "alipayqr://platformapi/startapp?saId=10000007&qrcode=$qrCode&_t=${System.currentTimeMillis()}" val intent = Intent(Intent.ACTION_VIEW, Uri.parse(aliPayQr)) context.startActivity(intent) } catch (e: Exception) { From 215cc82b8aa6a2153798748cff59354c7f2ddbf9 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 3 Jan 2020 10:56:27 +0800 Subject: [PATCH 65/85] up --- app/src/main/java/io/legado/app/ui/about/DonateActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt b/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt index 61cf11177..19e950ec8 100644 --- a/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt +++ b/app/src/main/java/io/legado/app/ui/about/DonateActivity.kt @@ -76,7 +76,7 @@ class DonateActivity : BaseActivity(R.layout.activity_donate) { private fun aliDonate(context: Context) { try { val qrCode = URLEncoder.encode( - "https://qr.alipay.com/fkx03463i8oppupkpsoo1f?_s=Dweb-other", + "https://qr.alipay.com/tsx06677nwdk3javroq4ef0?_s=Dweb-other", "utf-8" ) val aliPayQr = From 8e0f4c7f81f660f963343ac0cfe4a28da6e601af Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 3 Jan 2020 15:40:53 +0800 Subject: [PATCH 66/85] up --- .../io/legado/app/ui/widget/font/FontSelectDialog.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index eb1f7eeb6..714111062 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -18,6 +18,7 @@ import io.legado.app.constant.PreferKey import io.legado.app.help.FileHelp import io.legado.app.utils.DocumentUtils import io.legado.app.utils.getPrefString +import io.legado.app.utils.putPrefString import io.legado.app.utils.toast import kotlinx.android.synthetic.main.dialog_font_select.* import kotlinx.coroutines.CoroutineScope @@ -38,7 +39,6 @@ class FontSelectDialog : DialogFragment(), var curPath: String? = null private val fontFolder = App.INSTANCE.filesDir.absolutePath + File.separator + "Fonts" + File.separator - var defaultFont: (() -> Unit)? = null var selectFile: ((path: String) -> Unit)? = null override val coroutineContext: CoroutineContext get() = job + Main @@ -75,6 +75,9 @@ class FontSelectDialog : DialogFragment(), } catch (e: java.lang.Exception) { } + } else { + val uri = Uri.parse(fontPath) + getFontFiles(uri) } } @@ -126,6 +129,11 @@ class FontSelectDialog : DialogFragment(), when (requestCode) { fontFolderRequestCode -> if (resultCode == RESULT_OK) { data?.data?.let { uri -> + putPrefString(PreferKey.fontFolder, uri.toString()) + context?.contentResolver?.takePersistableUriPermission( + uri, + Intent.FLAG_GRANT_READ_URI_PERMISSION + ) getFontFiles(uri) } } From fbd2e4573dfc248d68b90f28e30ad4f34ee811a3 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 3 Jan 2020 15:52:56 +0800 Subject: [PATCH 67/85] up --- .../app/ui/widget/font/FontSelectDialog.kt | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index 714111062..194007e6c 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -16,6 +16,8 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.constant.PreferKey import io.legado.app.help.FileHelp +import io.legado.app.help.permission.Permissions +import io.legado.app.help.permission.PermissionsCompat import io.legado.app.utils.DocumentUtils import io.legado.app.utils.getPrefString import io.legado.app.utils.putPrefString @@ -73,7 +75,11 @@ class FontSelectDialog : DialogFragment(), intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) startActivityForResult(intent, fontFolderRequestCode) } catch (e: java.lang.Exception) { - + PermissionsCompat.Builder(this) + .addPermissions(*Permissions.Group.STORAGE) + .rationale(R.string.tip_perm_request_storage) + .onGranted { getFontFilesOld() } + .request() } } else { val uri = Uri.parse(fontPath) @@ -111,6 +117,20 @@ class FontSelectDialog : DialogFragment(), } } + @SuppressLint("DefaultLocale") + private fun getFontFilesOld() { + try { + val file = File(fontFolder) + file.listFiles { pathName -> + pathName.name.toLowerCase().matches(".*\\.[ot]tf".toRegex()) + }?.let { + adapter.setItems(it.toList()) + } + } catch (e: Exception) { + toast(e.localizedMessage ?: "") + } + } + override fun onClick(file: File) { file.absolutePath.let { if (it != curPath) { From d1e25c9772ccd6610630d2968382456050139b6c Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 3 Jan 2020 16:23:13 +0800 Subject: [PATCH 68/85] up --- .../app/ui/widget/font/FontSelectDialog.kt | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index 194007e6c..ca154a4ea 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -70,20 +70,14 @@ class FontSelectDialog : DialogFragment(), val fontPath = getPrefString(PreferKey.fontFolder) if (fontPath.isNullOrEmpty()) { - try { - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - startActivityForResult(intent, fontFolderRequestCode) - } catch (e: java.lang.Exception) { - PermissionsCompat.Builder(this) - .addPermissions(*Permissions.Group.STORAGE) - .rationale(R.string.tip_perm_request_storage) - .onGranted { getFontFilesOld() } - .request() - } + openFolder() } else { val uri = Uri.parse(fontPath) - getFontFiles(uri) + if (DocumentFile.fromTreeUri(requireContext(), uri)?.canRead() == true) { + getFontFiles(uri) + } else { + openFolder() + } } } @@ -92,6 +86,20 @@ class FontSelectDialog : DialogFragment(), job.cancel() } + private fun openFolder() { + try { + val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + startActivityForResult(intent, fontFolderRequestCode) + } catch (e: java.lang.Exception) { + PermissionsCompat.Builder(this) + .addPermissions(*Permissions.Group.STORAGE) + .rationale(R.string.tip_perm_request_storage) + .onGranted { getFontFilesOld() } + .request() + } + } + @SuppressLint("DefaultLocale") private fun getFontFiles(uri: Uri) { launch(IO) { From 572c5957a24f36cbdfe7f8ff6267d9f73c4c3ed1 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 3 Jan 2020 16:47:58 +0800 Subject: [PATCH 69/85] up --- .../app/ui/widget/font/FontSelectDialog.kt | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index ca154a4ea..4d726d973 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -38,10 +38,8 @@ class FontSelectDialog : DialogFragment(), lateinit var job: Job private val fontFolderRequestCode = 35485 private lateinit var adapter: FontAdapter - var curPath: String? = null private val fontFolder = App.INSTANCE.filesDir.absolutePath + File.separator + "Fonts" + File.separator - var selectFile: ((path: String) -> Unit)? = null override val coroutineContext: CoroutineContext get() = job + Main @@ -141,15 +139,32 @@ class FontSelectDialog : DialogFragment(), override fun onClick(file: File) { file.absolutePath.let { - if (it != curPath) { - selectFile?.invoke(it) - dialog?.dismiss() + val pf = parentFragment + if (pf is CallBack) { + if (it != pf.curPath) { + pf.selectFile(it) + } + } + val activity = activity + if (activity is CallBack) { + if (it != activity.curPath) { + activity.selectFile(it) + } } } + dialog?.dismiss() } override fun curFilePath(): String { - return curPath ?: "" + val pf = parentFragment + if (pf is CallBack) { + return pf.curPath + } + val activity = activity + if (activity is CallBack) { + return activity.curPath + } + return "" } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { @@ -169,6 +184,7 @@ class FontSelectDialog : DialogFragment(), } interface CallBack { - fun selectFile(uri: Uri) + fun selectFile(path: String) + val curPath: String } } \ No newline at end of file From c2df639f949a2ebdf0333bc96814b37240b37604 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 3 Jan 2020 17:07:32 +0800 Subject: [PATCH 70/85] up --- .../app/ui/book/read/config/ReadStyleDialog.kt | 15 ++++++++++----- .../legado/app/ui/widget/font/FontSelectDialog.kt | 10 +++++----- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt index e19231b4a..3bc5060b0 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/ReadStyleDialog.kt @@ -20,17 +20,14 @@ import io.legado.app.lib.theme.primaryColor import io.legado.app.ui.book.read.Help import io.legado.app.ui.book.read.ReadBookActivity import io.legado.app.ui.widget.font.FontSelectDialog -import io.legado.app.utils.getPrefInt -import io.legado.app.utils.postEvent -import io.legado.app.utils.progressAdd -import io.legado.app.utils.putPrefInt +import io.legado.app.utils.* import kotlinx.android.synthetic.main.activity_book_read.* import kotlinx.android.synthetic.main.dialog_read_book_style.* import org.jetbrains.anko.sdk27.listeners.onCheckedChange import org.jetbrains.anko.sdk27.listeners.onClick import org.jetbrains.anko.sdk27.listeners.onLongClick -class ReadStyleDialog : DialogFragment() { +class ReadStyleDialog : DialogFragment(), FontSelectDialog.CallBack { override fun onStart() { super.onStart() @@ -263,4 +260,12 @@ class ReadStyleDialog : DialogFragment() { else -> bg0.borderColor = requireContext().accentColor } } + + override val curFontPath: String + get() = requireContext().getPrefString(PreferKey.readBookFont) ?: "" + + override fun selectFile(path: String) { + requireContext().putPrefString(PreferKey.readBookFont, path) + postEvent(Bus.UP_CONFIG, true) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index 4d726d973..7b7a97e9b 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -141,13 +141,13 @@ class FontSelectDialog : DialogFragment(), file.absolutePath.let { val pf = parentFragment if (pf is CallBack) { - if (it != pf.curPath) { + if (it != pf.curFontPath) { pf.selectFile(it) } } val activity = activity if (activity is CallBack) { - if (it != activity.curPath) { + if (it != activity.curFontPath) { activity.selectFile(it) } } @@ -158,11 +158,11 @@ class FontSelectDialog : DialogFragment(), override fun curFilePath(): String { val pf = parentFragment if (pf is CallBack) { - return pf.curPath + return pf.curFontPath } val activity = activity if (activity is CallBack) { - return activity.curPath + return activity.curFontPath } return "" } @@ -185,6 +185,6 @@ class FontSelectDialog : DialogFragment(), interface CallBack { fun selectFile(path: String) - val curPath: String + val curFontPath: String } } \ No newline at end of file From 7533cff6f742721725352c9222b4542de4ab4476 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 3 Jan 2020 20:47:21 +0800 Subject: [PATCH 71/85] up --- .../app/ui/widget/font/FontSelectDialog.kt | 26 +++++++++++++++++++ app/src/main/res/menu/font_select.xml | 15 +++++++++++ app/src/main/res/values/strings.xml | 1 + 3 files changed, 42 insertions(+) create mode 100644 app/src/main/res/menu/font_select.xml diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index 7b7a97e9b..d15d07aeb 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -7,8 +7,10 @@ import android.net.Uri import android.os.Bundle import android.util.DisplayMetrics import android.view.LayoutInflater +import android.view.MenuItem import android.view.View import android.view.ViewGroup +import androidx.appcompat.widget.Toolbar import androidx.documentfile.provider.DocumentFile import androidx.fragment.app.DialogFragment import androidx.recyclerview.widget.LinearLayoutManager @@ -33,6 +35,7 @@ import java.io.File import kotlin.coroutines.CoroutineContext class FontSelectDialog : DialogFragment(), + Toolbar.OnMenuItemClickListener, CoroutineScope, FontAdapter.CallBack { lateinit var job: Job @@ -62,6 +65,8 @@ class FontSelectDialog : DialogFragment(), override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) tool_bar.setTitle(R.string.select_font) + tool_bar.inflateMenu(R.menu.font_select) + tool_bar.setOnMenuItemClickListener(this) adapter = FontAdapter(requireContext(), this) recycler_view.layoutManager = LinearLayoutManager(context) recycler_view.adapter = adapter @@ -79,6 +84,27 @@ class FontSelectDialog : DialogFragment(), } } + override fun onMenuItemClick(item: MenuItem?): Boolean { + when (item?.itemId) { + R.id.menu_default -> { + val pf = parentFragment + if (pf is CallBack) { + if ("" != pf.curFontPath) { + pf.selectFile("") + } + } + val activity = activity + if (activity is CallBack) { + if ("" != activity.curFontPath) { + activity.selectFile("") + } + } + dismiss() + } + } + return true + } + override fun onDestroy() { super.onDestroy() job.cancel() diff --git a/app/src/main/res/menu/font_select.xml b/app/src/main/res/menu/font_select.xml new file mode 100644 index 000000000..44a366ef8 --- /dev/null +++ b/app/src/main/res/menu/font_select.xml @@ -0,0 +1,15 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2d16b399c..5036723df 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -578,5 +578,6 @@ 未分组 上一句 下一句 + 其它目录 From 16bceeffc2045e80ec9297d3c79d5a29d8864fcc Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 3 Jan 2020 20:59:20 +0800 Subject: [PATCH 72/85] up --- app/src/main/assets/updateLog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index 06c0bcaac..aa334f827 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -4,6 +4,10 @@ * 先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】,提示存储权限,选择允许即可导入成功。 * 注意:由于安卓10更改了权限策略,还需要给「允许安装其他应用」的权限才能导入源。MIUI11也需要此权限。 +**2020/01/03** +* 导入旧版本配置不在需要存储权限 +* 选择字体不在需要存储权限 + **2019/12/30** * 修改书源调试 - 调试搜索>>输入关键字,如:`系统` From 8cd1b1af1200606f12d093ae42b9dc62d8b8e046 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 3 Jan 2020 21:00:47 +0800 Subject: [PATCH 73/85] up --- app/src/main/assets/updateLog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/assets/updateLog.md b/app/src/main/assets/updateLog.md index aa334f827..2d01b7c58 100644 --- a/app/src/main/assets/updateLog.md +++ b/app/src/main/assets/updateLog.md @@ -5,6 +5,7 @@ * 注意:由于安卓10更改了权限策略,还需要给「允许安装其他应用」的权限才能导入源。MIUI11也需要此权限。 **2020/01/03** +* 适配Android 10 权限 * 导入旧版本配置不在需要存储权限 * 选择字体不在需要存储权限 From ebad3c04a1563a7c77432bf9928b9ae16bdec9c5 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 3 Jan 2020 21:08:04 +0800 Subject: [PATCH 74/85] up --- .../main/java/io/legado/app/ui/book/read/ReadBookActivity.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index fdc95233d..6a143f542 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -203,6 +203,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo return super.dispatchKeyEvent(event) } + /** + * 按键事件 + */ override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { when (keyCode) { KeyEvent.KEYCODE_VOLUME_UP -> { From fd4b2d6e332cdd3386416cd29bbcdbff1871521a Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 3 Jan 2020 21:14:53 +0800 Subject: [PATCH 75/85] up --- .../io/legado/app/ui/book/read/ReadBookActivity.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index 6a143f542..4066ed269 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -16,6 +16,7 @@ import com.jaredrummler.android.colorpicker.ColorPickerDialogListener import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.constant.Bus +import io.legado.app.constant.PreferKey import io.legado.app.constant.Status import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter @@ -220,6 +221,19 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo } KeyEvent.KEYCODE_SPACE -> { page_view.moveToNextPage() + return true + } + getPrefInt(PreferKey.prevKey) -> { + if (keyCode != 0) { + page_view.moveToPrevPage() + return true + } + } + getPrefInt(PreferKey.nextKey) -> { + if (keyCode != 0) { + page_view.moveToNextPage() + return true + } } } return super.onKeyDown(keyCode, event) From 86049f4208b48bb8fa999bc5b23d94cf3003107b Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 3 Jan 2020 21:16:13 +0800 Subject: [PATCH 76/85] up --- .../main/java/io/legado/app/ui/book/read/ReadBookActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index 4066ed269..a25a6554b 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -224,13 +224,13 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo return true } getPrefInt(PreferKey.prevKey) -> { - if (keyCode != 0) { + if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { page_view.moveToPrevPage() return true } } getPrefInt(PreferKey.nextKey) -> { - if (keyCode != 0) { + if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { page_view.moveToNextPage() return true } From 3c22a6a02f7fdfaf30c2d7d75fdb3a0a06823023 Mon Sep 17 00:00:00 2001 From: kunfei Date: Fri, 3 Jan 2020 21:19:22 +0800 Subject: [PATCH 77/85] up --- .../java/io/legado/app/ui/book/read/ReadBookActivity.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index a25a6554b..3a2523293 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -239,6 +239,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo return super.onKeyDown(keyCode, event) } + /** + * 长按事件 + */ override fun onKeyLongPress(keyCode: Int, event: KeyEvent?): Boolean { when (keyCode) { KeyEvent.KEYCODE_BACK -> { @@ -249,6 +252,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo return super.onKeyLongPress(keyCode, event) } + /** + * 松开按键事件 + */ override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean { when (keyCode) { KeyEvent.KEYCODE_VOLUME_UP, KeyEvent.KEYCODE_VOLUME_DOWN -> { @@ -274,6 +280,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo return super.onKeyUp(keyCode, event) } + /** + * 音量键翻页 + */ private fun volumeKeyPage(direction: PageDelegate.Direction): Boolean { if (!read_menu.isVisible) { if (getPrefBoolean("volumeKeyPage", true)) { From ab4672a5433759625c3a8973dca8d5a0ceaa1637 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 4 Jan 2020 14:53:46 +0800 Subject: [PATCH 78/85] up --- .../io/legado/app/service/TTSReadAloudService.kt | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt index cdfd05581..977e8b0ac 100644 --- a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt @@ -45,16 +45,10 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener override fun onInit(status: Int) { launch { if (status == TextToSpeech.SUCCESS) { - val result = textToSpeech?.setLanguage(Locale.CHINA) - if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) { - toast(R.string.tts_fix) - IntentHelp.toTTSSetting(this@TTSReadAloudService) - stopSelf() - } else { - textToSpeech?.setOnUtteranceProgressListener(TTSUtteranceListener()) - ttsIsSuccess = true - play() - } + textToSpeech?.language = Locale.CHINA + textToSpeech?.setOnUtteranceProgressListener(TTSUtteranceListener()) + ttsIsSuccess = true + play() } else { toast(R.string.tts_init_failed) } From 676bfea8f7aaacd0d967445f2aee14dd54ccf054 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 4 Jan 2020 17:18:27 +0800 Subject: [PATCH 79/85] up --- .../main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index d15d07aeb..4f28f5b06 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -101,6 +101,9 @@ class FontSelectDialog : DialogFragment(), } dismiss() } + R.id.menu_other -> { + openFolder() + } } return true } From 2ce2434e7f272fddc8b2dd02706e1197403f2b73 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 4 Jan 2020 18:30:28 +0800 Subject: [PATCH 80/85] up --- .../io/legado/app/ui/main/MainActivity.kt | 22 ++++++++++++++++-- .../io/legado/app/ui/main/my/MyFragment.kt | 23 ++++++++----------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index a059e380d..1655152b6 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -13,7 +13,10 @@ import io.legado.app.BuildConfig import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.constant.Bus +import io.legado.app.help.permission.Permissions +import io.legado.app.help.permission.PermissionsCompat import io.legado.app.help.storage.Backup +import io.legado.app.help.storage.WebDavHelp import io.legado.app.lib.theme.ATH import io.legado.app.service.BaseReadAloudService import io.legado.app.service.help.ReadAloud @@ -137,6 +140,22 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), } } + fun backup() { + PermissionsCompat.Builder(this) + .addPermissions(*Permissions.Group.STORAGE) + .rationale(R.string.tip_perm_request_storage) + .onGranted { Backup.backup() } + .request() + } + + fun restore() { + PermissionsCompat.Builder(this) + .addPermissions(*Permissions.Group.STORAGE) + .rationale(R.string.tip_perm_request_storage) + .onGranted { WebDavHelp.showRestoreDialog(this) } + .request() + } + private inner class TabFragmentPageAdapter internal constructor(fm: FragmentManager) : FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { @@ -153,5 +172,4 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), } } -} - +} \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt index e19d68ec5..5b2a24114 100644 --- a/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt +++ b/app/src/main/java/io/legado/app/ui/main/my/MyFragment.kt @@ -13,10 +13,6 @@ import io.legado.app.R import io.legado.app.base.BaseFragment import io.legado.app.constant.Bus import io.legado.app.help.BookHelp -import io.legado.app.help.permission.Permissions -import io.legado.app.help.permission.PermissionsCompat -import io.legado.app.help.storage.Backup -import io.legado.app.help.storage.WebDavHelp import io.legado.app.lib.theme.ATH import io.legado.app.service.WebService import io.legado.app.ui.about.AboutActivity @@ -24,6 +20,7 @@ import io.legado.app.ui.about.DonateActivity import io.legado.app.ui.book.source.manage.BookSourceActivity import io.legado.app.ui.config.ConfigActivity import io.legado.app.ui.config.ConfigViewModel +import io.legado.app.ui.main.MainActivity import io.legado.app.ui.replacerule.ReplaceRuleActivity import io.legado.app.utils.* import kotlinx.android.synthetic.main.view_title_bar.* @@ -46,16 +43,14 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config) { override fun onCompatOptionsItemSelected(item: MenuItem) { when (item.itemId) { R.id.menu_help -> startActivity() - R.id.menu_backup -> PermissionsCompat.Builder(this) - .addPermissions(*Permissions.Group.STORAGE) - .rationale(R.string.tip_perm_request_storage) - .onGranted { Backup.backup() } - .request() - R.id.menu_restore -> PermissionsCompat.Builder(this) - .addPermissions(*Permissions.Group.STORAGE) - .rationale(R.string.tip_perm_request_storage) - .onGranted { WebDavHelp.showRestoreDialog(requireContext()) } - .request() + R.id.menu_backup -> { + val activity = activity as? MainActivity + activity?.backup() + } + R.id.menu_restore -> { + val activity = activity as? MainActivity + activity?.restore() + } } } From 62e354572898580cb968ea05cd42fb254b071606 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 4 Jan 2020 19:11:10 +0800 Subject: [PATCH 81/85] up --- .../java/io/legado/app/constant/PreferKey.kt | 1 + .../io/legado/app/ui/main/MainActivity.kt | 33 ++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/legado/app/constant/PreferKey.kt b/app/src/main/java/io/legado/app/constant/PreferKey.kt index bc74ed1ab..0d8cad7cf 100644 --- a/app/src/main/java/io/legado/app/constant/PreferKey.kt +++ b/app/src/main/java/io/legado/app/constant/PreferKey.kt @@ -17,4 +17,5 @@ object PreferKey { const val pageAnim = "pageAnim" const val readBookFont = "readBookFont" const val fontFolder = "fontFolder" + const val backupPath = "backupUri" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index 1655152b6..5ff86cb80 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -1,5 +1,7 @@ package io.legado.app.ui.main +import android.app.Activity +import android.content.Intent import android.os.Bundle import android.view.KeyEvent import android.view.MenuItem @@ -13,6 +15,7 @@ import io.legado.app.BuildConfig import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.constant.Bus +import io.legado.app.constant.PreferKey import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat import io.legado.app.help.storage.Backup @@ -31,7 +34,7 @@ import kotlinx.android.synthetic.main.activity_main.* class MainActivity : VMBaseActivity(R.layout.activity_main), BottomNavigationView.OnNavigationItemSelectedListener, ViewPager.OnPageChangeListener by ViewPager.SimpleOnPageChangeListener() { - + private val backupSelectRequestCode = 4567489 override val viewModel: MainViewModel get() = getViewModel(MainViewModel::class.java) @@ -141,6 +144,10 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), } fun backup() { + val backupPath = getPrefString(PreferKey.backupPath) + if (backupPath?.isEmpty() == null) { + + } PermissionsCompat.Builder(this) .addPermissions(*Permissions.Group.STORAGE) .rationale(R.string.tip_perm_request_storage) @@ -156,6 +163,30 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), .request() } + fun selectBackupFolder() { + try { + val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + startActivityForResult(intent, backupSelectRequestCode) + } catch (e: java.lang.Exception) { + + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + when (requestCode) { + backupSelectRequestCode -> if (resultCode == Activity.RESULT_OK) { + data?.data?.let { uri -> + contentResolver.takePersistableUriPermission( + uri, + Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + ) + } + } + } + } + private inner class TabFragmentPageAdapter internal constructor(fm: FragmentManager) : FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { From e0c8322ae53bd3623a4a83165046d82777f3dbcf Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 4 Jan 2020 21:16:53 +0800 Subject: [PATCH 82/85] up --- .../io/legado/app/ui/main/MainActivity.kt | 42 +++++++++++++++---- .../app/ui/widget/font/FontSelectDialog.kt | 4 +- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index 5ff86cb80..47cd4a252 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -2,9 +2,11 @@ package io.legado.app.ui.main import android.app.Activity import android.content.Intent +import android.net.Uri import android.os.Bundle import android.view.KeyEvent import android.view.MenuItem +import androidx.documentfile.provider.DocumentFile import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentStatePagerAdapter @@ -35,6 +37,7 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), BottomNavigationView.OnNavigationItemSelectedListener, ViewPager.OnPageChangeListener by ViewPager.SimpleOnPageChangeListener() { private val backupSelectRequestCode = 4567489 + private val restoreSelectRequestCode = 654872 override val viewModel: MainViewModel get() = getViewModel(MainViewModel::class.java) @@ -145,14 +148,21 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), fun backup() { val backupPath = getPrefString(PreferKey.backupPath) - if (backupPath?.isEmpty() == null) { - + if (backupPath?.isEmpty() == true) { + selectBackupFolder() + } else { + val uri = Uri.parse(backupPath) + val doc = DocumentFile.fromTreeUri(this, uri) + if (doc?.canWrite() == true) { + backup(uri) + } else { + selectBackupFolder() + } } - PermissionsCompat.Builder(this) - .addPermissions(*Permissions.Group.STORAGE) - .rationale(R.string.tip_perm_request_storage) - .onGranted { Backup.backup() } - .request() + } + + private fun backup(uri: Uri) { + } fun restore() { @@ -163,13 +173,17 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), .request() } - fun selectBackupFolder() { + private fun selectBackupFolder() { try { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) startActivityForResult(intent, backupSelectRequestCode) } catch (e: java.lang.Exception) { - + PermissionsCompat.Builder(this) + .addPermissions(*Permissions.Group.STORAGE) + .rationale(R.string.tip_perm_request_storage) + .onGranted { Backup.backup() } + .request() } } @@ -182,6 +196,16 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), uri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION ) + backup(uri) + } + } + restoreSelectRequestCode -> if (resultCode == Activity.RESULT_OK) { + data?.data?.let { uri -> + contentResolver.takePersistableUriPermission( + uri, + Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + ) + } } } diff --git a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt index 4f28f5b06..1fba2ce2e 100644 --- a/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/font/FontSelectDialog.kt @@ -5,6 +5,7 @@ import android.app.Activity.RESULT_OK import android.content.Intent import android.net.Uri import android.os.Bundle +import android.os.Environment import android.util.DisplayMetrics import android.view.LayoutInflater import android.view.MenuItem @@ -155,7 +156,8 @@ class FontSelectDialog : DialogFragment(), @SuppressLint("DefaultLocale") private fun getFontFilesOld() { try { - val file = File(fontFolder) + val file = + File(Environment.getExternalStorageDirectory().absolutePath + File.separator + "Fonts") file.listFiles { pathName -> pathName.name.toLowerCase().matches(".*\\.[ot]tf".toRegex()) }?.let { From c106782995c3ea63f0b361746de94183120b2ac6 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 4 Jan 2020 21:58:24 +0800 Subject: [PATCH 83/85] up --- .../io/legado/app/ui/main/MainActivity.kt | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index 47cd4a252..e9a139283 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -18,9 +18,11 @@ import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.constant.Bus import io.legado.app.constant.PreferKey +import io.legado.app.help.ReadBookConfig import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat import io.legado.app.help.storage.Backup +import io.legado.app.help.storage.Restore import io.legado.app.help.storage.WebDavHelp import io.legado.app.lib.theme.ATH import io.legado.app.service.BaseReadAloudService @@ -162,7 +164,31 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), } private fun backup(uri: Uri) { + DocumentFile.fromTreeUri(this, uri)?.listFiles()?.forEach { doc -> + when (doc.name) { + "bookshelf.json" -> { + } + "bookGroup.json" -> { + + } + "bookSource.json" -> { + + } + "rssSource.json" -> { + + } + "replaceRule.json" -> { + + } + ReadBookConfig.readConfigFileName -> { + + } + "config.xml" -> { + + } + } + } } fun restore() { @@ -173,6 +199,10 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), .request() } + fun restore(uri: Uri) { + + } + private fun selectBackupFolder() { try { val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) @@ -187,6 +217,20 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), } } + private fun selectRestoreFolder() { + try { + val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + startActivityForResult(intent, restoreSelectRequestCode) + } catch (e: java.lang.Exception) { + PermissionsCompat.Builder(this) + .addPermissions(*Permissions.Group.STORAGE) + .rationale(R.string.tip_perm_request_storage) + .onGranted { Restore.restore() } + .request() + } + } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) when (requestCode) { From 75d69cb249510f24c3ee38b44cf558bbaabeaea4 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 4 Jan 2020 22:02:17 +0800 Subject: [PATCH 84/85] up --- .../java/io/legado/app/help/storage/Backup.kt | 31 +++++++++++++++++ .../io/legado/app/ui/main/MainActivity.kt | 33 ++----------------- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt index 529deb629..f6c7a4953 100644 --- a/app/src/main/java/io/legado/app/help/storage/Backup.kt +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -1,5 +1,8 @@ package io.legado.app.help.storage +import android.content.Context +import android.net.Uri +import androidx.documentfile.provider.DocumentFile import io.legado.app.App import io.legado.app.R import io.legado.app.help.FileHelp @@ -27,6 +30,34 @@ object Backup { legadoPath + File.separator + "Export" } + fun backup(context: Context, uri: Uri) { + DocumentFile.fromTreeUri(context, uri)?.listFiles()?.forEach { doc -> + when (doc.name) { + "bookshelf.json" -> { + + } + "bookGroup.json" -> { + + } + "bookSource.json" -> { + + } + "rssSource.json" -> { + + } + "replaceRule.json" -> { + + } + ReadBookConfig.readConfigFileName -> { + + } + "config.xml" -> { + + } + } + } + } + private fun pBackup(path: String = legadoPath) { backupBookshelf(path) backupBookGroup(path) diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index e9a139283..88cc89b8a 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -18,7 +18,6 @@ import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.constant.Bus import io.legado.app.constant.PreferKey -import io.legado.app.help.ReadBookConfig import io.legado.app.help.permission.Permissions import io.legado.app.help.permission.PermissionsCompat import io.legado.app.help.storage.Backup @@ -156,41 +155,13 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), val uri = Uri.parse(backupPath) val doc = DocumentFile.fromTreeUri(this, uri) if (doc?.canWrite() == true) { - backup(uri) + Backup.backup(this, uri) } else { selectBackupFolder() } } } - private fun backup(uri: Uri) { - DocumentFile.fromTreeUri(this, uri)?.listFiles()?.forEach { doc -> - when (doc.name) { - "bookshelf.json" -> { - - } - "bookGroup.json" -> { - - } - "bookSource.json" -> { - - } - "rssSource.json" -> { - - } - "replaceRule.json" -> { - - } - ReadBookConfig.readConfigFileName -> { - - } - "config.xml" -> { - - } - } - } - } - fun restore() { PermissionsCompat.Builder(this) .addPermissions(*Permissions.Group.STORAGE) @@ -240,7 +211,7 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), uri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION ) - backup(uri) + Backup.backup(this, uri) } } restoreSelectRequestCode -> if (resultCode == Activity.RESULT_OK) { From be233f56156dd2f62d246b96def50f84fb08cd05 Mon Sep 17 00:00:00 2001 From: kunfei Date: Sat, 4 Jan 2020 22:32:04 +0800 Subject: [PATCH 85/85] up --- .../java/io/legado/app/help/storage/Backup.kt | 40 +++++++++++++------ .../io/legado/app/ui/main/MainActivity.kt | 3 +- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/io/legado/app/help/storage/Backup.kt b/app/src/main/java/io/legado/app/help/storage/Backup.kt index f6c7a4953..53d9a4279 100644 --- a/app/src/main/java/io/legado/app/help/storage/Backup.kt +++ b/app/src/main/java/io/legado/app/help/storage/Backup.kt @@ -7,6 +7,7 @@ import io.legado.app.App import io.legado.app.R import io.legado.app.help.FileHelp import io.legado.app.help.ReadBookConfig +import io.legado.app.utils.DocumentUtils import io.legado.app.utils.FileUtils import io.legado.app.utils.GSON import org.jetbrains.anko.defaultSharedPreferences @@ -33,23 +34,38 @@ object Backup { fun backup(context: Context, uri: Uri) { DocumentFile.fromTreeUri(context, uri)?.listFiles()?.forEach { doc -> when (doc.name) { - "bookshelf.json" -> { - + "bookshelf.json" -> App.db.bookDao().allBooks.let { + if (it.isNotEmpty()) { + val json = GSON.toJson(it) + DocumentUtils.writeText(context, json, doc.uri) + } } - "bookGroup.json" -> { - + "bookGroup.json" -> App.db.bookGroupDao().all().let { + if (it.isNotEmpty()) { + val json = GSON.toJson(it) + DocumentUtils.writeText(context, json, doc.uri) + } } - "bookSource.json" -> { - + "bookSource.json" -> App.db.bookSourceDao().all.let { + if (it.isNotEmpty()) { + val json = GSON.toJson(it) + DocumentUtils.writeText(context, json, doc.uri) + } } - "rssSource.json" -> { - + "rssSource.json" -> App.db.rssSourceDao().all.let { + if (it.isNotEmpty()) { + val json = GSON.toJson(it) + DocumentUtils.writeText(context, json, doc.uri) + } } - "replaceRule.json" -> { - + "replaceRule.json" -> App.db.replaceRuleDao().all.let { + if (it.isNotEmpty()) { + val json = GSON.toJson(it) + DocumentUtils.writeText(context, json, doc.uri) + } } - ReadBookConfig.readConfigFileName -> { - + ReadBookConfig.readConfigFileName -> GSON.toJson(ReadBookConfig.configList)?.let { + DocumentUtils.writeText(context, it, doc.uri) } "config.xml" -> { diff --git a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt index 88cc89b8a..76874e612 100644 --- a/app/src/main/java/io/legado/app/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legado/app/ui/main/MainActivity.kt @@ -211,6 +211,7 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), uri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION ) + putPrefString(PreferKey.backupPath, uri.toString()) Backup.backup(this, uri) } } @@ -220,7 +221,7 @@ class MainActivity : VMBaseActivity(R.layout.activity_main), uri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION ) - + putPrefString(PreferKey.backupPath, uri.toString()) } } }