diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 67af4688e..543c13f6c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -185,6 +185,7 @@ android:launchMode="singleTop" /> 【备份与恢复】,选择【导入旧版本数据】。 * 请关注[开源阅读软件]()支持我,同时关注合作公众号[小说拾遗](),阅读公众号小编。 +**2020/03/10** +* 优化文字选择菜单弹出位置 +* 添加屏幕方向控制 + +**2020/03/09** +* 底部文字对齐 +* 主题添加阴影调节 by yangyxd + **2020/03/08** * 订阅长按保存图片 * 订阅全屏播放 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 1ba9ba6cf..e14ec42f6 100644 --- a/app/src/main/java/io/legado/app/constant/PreferKey.kt +++ b/app/src/main/java/io/legado/app/constant/PreferKey.kt @@ -3,7 +3,6 @@ package io.legado.app.constant object PreferKey { const val versionCode = "versionCode" const val themeMode = "themeMode" - const val downloadPath = "downloadPath" const val hideStatusBar = "hideStatusBar" const val clickTurnPage = "clickTurnPage" const val clickAllNext = "clickAllNext" diff --git a/app/src/main/java/io/legado/app/help/AppConfig.kt b/app/src/main/java/io/legado/app/help/AppConfig.kt index 6eef2bfa0..4b768b9e7 100644 --- a/app/src/main/java/io/legado/app/help/AppConfig.kt +++ b/app/src/main/java/io/legado/app/help/AppConfig.kt @@ -32,6 +32,9 @@ object AppConfig { App.INSTANCE.putPrefBoolean("transparentStatusBar", value) } + val requestedDirection: String? + get() = App.INSTANCE.getPrefString(R.string.pk_requested_direction) + var backupPath: String? get() = App.INSTANCE.getPrefString(PreferKey.backupPath) set(value) { @@ -49,7 +52,7 @@ object AppConfig { } val autoRefreshBook: Boolean - get() = App.INSTANCE.getPrefBoolean(App.INSTANCE.getString(R.string.pk_auto_refresh)) + get() = App.INSTANCE.getPrefBoolean(R.string.pk_auto_refresh) var threadCount: Int get() = App.INSTANCE.getPrefInt(PreferKey.threadCount, 16) @@ -111,4 +114,9 @@ object AppConfig { App.INSTANCE.putPrefBoolean("bookGroupAudio", value) } + var elevation: Int + get() = App.INSTANCE.getPrefInt("elevation", -1) + set(value) { + App.INSTANCE.putPrefInt("elevation", value) + } } 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 304df9997..b6e3ec000 100644 --- a/app/src/main/java/io/legado/app/help/BookHelp.kt +++ b/app/src/main/java/io/legado/app/help/BookHelp.kt @@ -4,8 +4,8 @@ import android.net.Uri import androidx.documentfile.provider.DocumentFile import com.github.houbb.opencc4j.core.impl.ZhConvertBootstrap import io.legado.app.App +import io.legado.app.R import io.legado.app.constant.EventBus -import io.legado.app.constant.PreferKey import io.legado.app.data.entities.Book import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.ReplaceRule @@ -21,7 +21,7 @@ import kotlin.math.min object BookHelp { private const val cacheFolderName = "book_cache" val downloadPath: String - get() = App.INSTANCE.getPrefString(PreferKey.downloadPath) + get() = App.INSTANCE.getPrefString(R.string.pk_download_path) ?: App.INSTANCE.getExternalFilesDir(null)?.absolutePath ?: App.INSTANCE.cacheDir.absolutePath @@ -300,6 +300,8 @@ object BookHelp { 1 -> c = ZhConvertBootstrap.newInstance().toSimple(c) 2 -> c = ZhConvertBootstrap.newInstance().toTraditional(c) } - return c.replace("\\s*\\n+\\s*".toRegex(), "\n${ReadBookConfig.bodyIndent}") + return c + .replace("\\s*\\n+\\s*".toRegex(), "\n${ReadBookConfig.bodyIndent}") + .replace("[\\n\\s]+$".toRegex(), "") //移除尾部空行 } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/lib/theme/ATHUtils.kt b/app/src/main/java/io/legado/app/lib/theme/ATHUtils.kt index 73e342713..ddd6fc816 100644 --- a/app/src/main/java/io/legado/app/lib/theme/ATHUtils.kt +++ b/app/src/main/java/io/legado/app/lib/theme/ATHUtils.kt @@ -19,4 +19,16 @@ object ATHUtils { a.recycle() } } + + @JvmOverloads + fun resolveFloat(context: Context, @AttrRes attr: Int, fallback: Float = 0.0f): Float { + val a = context.theme.obtainStyledAttributes(intArrayOf(attr)) + return try { + a.getFloat(0, fallback) + } catch (e: Exception) { + fallback + } finally { + a.recycle() + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/lib/theme/MaterialValueHelper.kt b/app/src/main/java/io/legado/app/lib/theme/MaterialValueHelper.kt index fab853c6b..bc898d065 100644 --- a/app/src/main/java/io/legado/app/lib/theme/MaterialValueHelper.kt +++ b/app/src/main/java/io/legado/app/lib/theme/MaterialValueHelper.kt @@ -107,4 +107,7 @@ val Context.isDarkTheme: Boolean get() = ColorUtils.isColorLight(ThemeStore.primaryColor(this)) val Fragment.isDarkTheme: Boolean - get() = requireContext().isDarkTheme \ No newline at end of file + get() = requireContext().isDarkTheme + +val Context.elevation: Float + get() = ThemeStore.elevation(this) \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/lib/theme/ThemeStore.kt b/app/src/main/java/io/legado/app/lib/theme/ThemeStore.kt index 927fc2fb0..5b3997081 100644 --- a/app/src/main/java/io/legado/app/lib/theme/ThemeStore.kt +++ b/app/src/main/java/io/legado/app/lib/theme/ThemeStore.kt @@ -284,6 +284,14 @@ private constructor(private val mContext: Context) : ThemeStoreInterface { ) } + @CheckResult + fun elevation(context: Context): Float { + return prefs(context).getFloat( + ThemeStorePrefKeys.KEY_ELEVATION, + ATHUtils.resolveFloat(context, android.R.attr.elevation, context.resources.getDimension(R.dimen.design_appbar_elevation)) + ) + } + @CheckResult @ColorInt fun bottomBackground(context: Context): Int { diff --git a/app/src/main/java/io/legado/app/lib/theme/ThemeStorePrefKeys.kt b/app/src/main/java/io/legado/app/lib/theme/ThemeStorePrefKeys.kt index a2ab19d60..ca8e85fc1 100644 --- a/app/src/main/java/io/legado/app/lib/theme/ThemeStorePrefKeys.kt +++ b/app/src/main/java/io/legado/app/lib/theme/ThemeStorePrefKeys.kt @@ -27,4 +27,6 @@ object ThemeStorePrefKeys { const val KEY_APPLY_PRIMARYDARK_STATUSBAR = "apply_primarydark_statusbar" const val KEY_APPLY_PRIMARY_NAVBAR = "apply_primary_navbar" const val KEY_AUTO_GENERATE_PRIMARYDARK = "auto_generate_primarydark" + + const val KEY_ELEVATION = "elevation" } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt index 9a893b8a3..fc94613d8 100644 --- a/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt +++ b/app/src/main/java/io/legado/app/model/localBook/LocalBook.kt @@ -4,6 +4,7 @@ import android.net.Uri import androidx.documentfile.provider.DocumentFile import io.legado.app.App import io.legado.app.data.entities.Book +import io.legado.app.help.BookHelp import io.legado.app.utils.FileUtils @@ -12,8 +13,17 @@ object LocalBook { fun importFile(doc: DocumentFile) { doc.name?.let { fileName -> val str = fileName.substringBeforeLast(".") - var name = str.substringBefore("作者") - val author = str.substringAfter("作者", "") + val authorIndex = str.indexOf("作者") + var name: String + var author: String + if (authorIndex == -1) { + name = str + author = "" + } else { + name = str.substring(0, authorIndex) + author = str.substring(authorIndex) + author = BookHelp.formatAuthor(author) + } val smhStart = name.indexOf("《") val smhEnd = name.indexOf("》") if (smhStart != -1 && smhEnd != -1) { 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 6fd32219d..e54900db7 100644 --- a/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/TTSReadAloudService.kt @@ -175,9 +175,7 @@ class TTSReadAloudService : BaseReadAloudService(), TextToSpeech.OnInitListener } override fun onError(s: String) { - launch { - toast(s) - } + pauseReadAloud(true) } } diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt index 769b47b21..42e56f206 100644 --- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt @@ -207,7 +207,7 @@ class BookInfoActivity : ChangeSourceDialog.show(supportFragmentManager, it.name, it.author) } } - tv_toc.onClick { + tv_toc_view.onClick { if (!viewModel.inBookshelf) { viewModel.saveBook { viewModel.saveChapterList { @@ -218,7 +218,7 @@ class BookInfoActivity : openChapterList() } } - tv_group.onClick { + tv_change_group.onClick { viewModel.bookData.value?.let { GroupSelectDialog.show(supportFragmentManager, it.group) } diff --git a/app/src/main/java/io/legado/app/ui/book/read/Help.kt b/app/src/main/java/io/legado/app/ui/book/read/Help.kt index 549b7b987..f5144977e 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/Help.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/Help.kt @@ -3,6 +3,7 @@ package io.legado.app.ui.book.read import android.annotation.SuppressLint import android.app.Activity import android.content.Context +import android.content.pm.ActivityInfo import android.os.AsyncTask import android.os.Build import android.view.* @@ -62,6 +63,18 @@ object Help { } } + + @SuppressLint("SourceLockedOrientationActivity") + fun setOrientation(activity: Activity) = activity.apply { + when (AppConfig.requestedDirection) { + "0" -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED + "1" -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT + "2" -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + "3" -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR + } + } + + /** * 返回NavigationBar是否存在 * 该方法需要在View完全被绘制出来之后调用,否则判断不了 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 2ca4555a3..3de366ec3 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 @@ -3,6 +3,7 @@ package io.legado.app.ui.book.read import android.annotation.SuppressLint import android.app.Activity import android.content.Intent +import android.content.res.Configuration import android.net.Uri import android.os.Bundle import android.os.Handler @@ -13,6 +14,7 @@ import androidx.core.view.isVisible import androidx.core.view.size import androidx.lifecycle.Observer import com.jaredrummler.android.colorpicker.ColorPickerDialogListener +import io.legado.app.BuildConfig import io.legado.app.R import io.legado.app.base.VMBaseActivity import io.legado.app.constant.EventBus @@ -88,6 +90,11 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo override val pageFactory: TextPageFactory get() = page_view.pageFactory override val headerHeight: Int get() = page_view.curPage.headerHeight + override fun onCreate(savedInstanceState: Bundle?) { + Help.setOrientation(this) + super.onCreate(savedInstanceState) + } + override fun onActivityCreated(savedInstanceState: Bundle?) { Help.upLayoutInDisplayCutoutMode(window) initView() @@ -106,6 +113,11 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo upSystemUiVisibility() } + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + ReadBook.loadContent() + } + override fun onResume() { super.onResume() upSystemUiVisibility() @@ -338,7 +350,8 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo @SuppressLint("ClickableViewAccessibility") override fun onTouch(v: View, event: MotionEvent): Boolean { when (event.action) { - MotionEvent.ACTION_MOVE, MotionEvent.ACTION_UP -> { + MotionEvent.ACTION_DOWN -> textActionMenu?.dismiss() + MotionEvent.ACTION_MOVE -> { when (v.id) { R.id.cursor_left -> page_view.curPage.selectStartMove( event.rawX + cursor_left.width, @@ -350,6 +363,7 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo ) } } + MotionEvent.ACTION_UP -> showTextActionMenu() } return true } @@ -357,11 +371,12 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo /** * 更新文字选择开始位置 */ - override fun upSelectedStart(x: Float, y: Float) { + override fun upSelectedStart(x: Float, y: Float, top: Float) { cursor_left.x = x - cursor_left.width cursor_left.y = y cursor_left.visible(true) - showTextActionMenu() + text_menu_position.x = x + text_menu_position.y = top } /** @@ -371,7 +386,6 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo cursor_right.x = x cursor_right.y = y cursor_right.visible(true) - showTextActionMenu() } /** @@ -386,19 +400,24 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo /** * 显示文本操作菜单 */ - private fun showTextActionMenu() { + override fun showTextActionMenu() { textActionMenu ?: let { - textActionMenu = TextActionMenu(this, this) - } - val x = cursor_left.x.toInt() + cursor_left.width - val y = if (cursor_left.y - statusBarHeight > ReadBookConfig.textSize.dp * 1.5 + 20.dp) { - (page_view.height - cursor_left.y + ReadBookConfig.textSize.dp * 1.5).toInt() - } else { - (page_view.height - cursor_left.y - cursor_left.height - 40.dp).toInt() + textActionMenu = TextActionMenu(this, this).apply { + contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED) + } } textActionMenu?.let { popup -> + val popupHeight = popup.contentView.measuredHeight + val x = text_menu_position.x.toInt() + var y = text_menu_position.y.toInt() - popupHeight + if (y < statusBarHeight) { + y = (cursor_left.y + cursor_left.height).toInt() + } + if (cursor_right.y > y && cursor_right.y < y + popupHeight) { + y = (cursor_right.y + cursor_right.height).toInt() + } if (!popup.isShowing) { - popup.showAtLocation(cursor_left, Gravity.BOTTOM or Gravity.START, x, y) + popup.showAtLocation(text_menu_position, Gravity.TOP or Gravity.START, x, y) } else { popup.update(x, y, WRAP_CONTENT, WRAP_CONTENT) } @@ -663,7 +682,9 @@ class ReadBookActivity : VMBaseActivity(R.layout.activity_boo mHandler.removeCallbacks(keepScreenRunnable) textActionMenu?.dismiss() page_view.onDestroy() - SyncBookProgress.uploadBookProgress() + if (!BuildConfig.DEBUG) { + SyncBookProgress.uploadBookProgress() + } } override fun observeLiveBus() { diff --git a/app/src/main/java/io/legado/app/ui/book/read/TextActionMenu.kt b/app/src/main/java/io/legado/app/ui/book/read/TextActionMenu.kt index 7e90c7ad1..9d7046f6e 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/TextActionMenu.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/TextActionMenu.kt @@ -151,15 +151,16 @@ class TextActionMenu(private val context: Context, private val callBack: CallBac */ @RequiresApi(Build.VERSION_CODES.M) private fun onInitializeMenu(menu: Menu) { - // Start with a menu Item order value that is high enough - // so that your "PROCESS_TEXT" menu items appear after the - // standard selection menu items like Cut, Copy, Paste. - var menuItemOrder = 100 - for (resolveInfo in getSupportedActivities()) { - menu.add( - Menu.NONE, Menu.NONE, - menuItemOrder++, resolveInfo.loadLabel(context.packageManager) - ).intent = createProcessTextIntentForResolveInfo(resolveInfo) + try { + var menuItemOrder = 100 + for (resolveInfo in getSupportedActivities()) { + menu.add( + Menu.NONE, Menu.NONE, + menuItemOrder++, resolveInfo.loadLabel(context.packageManager) + ).intent = createProcessTextIntentForResolveInfo(resolveInfo) + } + } catch (e: Exception) { + context.toast("获取文字操作菜单出错:${e.localizedMessage}") } } diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/MoreConfigDialog.kt b/app/src/main/java/io/legado/app/ui/book/read/config/MoreConfigDialog.kt index 6f472f270..a23725143 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/config/MoreConfigDialog.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/config/MoreConfigDialog.kt @@ -104,6 +104,11 @@ class MoreConfigDialog : DialogFragment() { } PreferKey.keepLight -> postEvent(key, true) PreferKey.textSelectAble -> postEvent(key, getPrefBoolean(key)) + getString(R.string.pk_requested_direction) -> { + activity?.let { + Help.setOrientation(it) + } + } } } diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/ChapterProvider.kt b/app/src/main/java/io/legado/app/ui/book/read/page/ChapterProvider.kt index 65121906c..b7cf7182e 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/ChapterProvider.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/ChapterProvider.kt @@ -75,6 +75,7 @@ object ChapterProvider { item.chapterIndex = bookChapter.index item.chapterSize = chapterSize item.title = bookChapter.title + item.upLinesPosition(visibleHeight) } return TextChapter( bookChapter.index, diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt b/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt index 44baa68f6..53f03462f 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/ContentTextView.kt @@ -31,6 +31,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at private val selectStart = arrayOf(0, 0, 0) private val selectEnd = arrayOf(0, 0, 0) private var textPage: TextPage = TextPage() + //滚动参数 private val pageFactory: TextPageFactory get() = callBack.pageFactory private val maxScrollOffset = 100f @@ -210,7 +211,11 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at selectEnd[0] = 0 selectEnd[1] = lineIndex selectEnd[2] = charIndex - upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset) + upSelectedStart( + textChar.start, + textLine.lineBottom + relativeOffset, + textLine.lineTop + relativeOffset + ) upSelectedEnd(textChar.end, textLine.lineBottom + relativeOffset) select(0, lineIndex, charIndex) return @@ -236,7 +241,11 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at selectEnd[0] = 1 selectEnd[1] = lineIndex selectEnd[2] = charIndex - upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset) + upSelectedStart( + textChar.start, + textLine.lineBottom + relativeOffset, + textLine.lineTop + relativeOffset + ) upSelectedEnd(textChar.end, textLine.lineBottom + relativeOffset) select(1, lineIndex, charIndex) return @@ -259,7 +268,11 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at selectEnd[0] = 2 selectEnd[1] = lineIndex selectEnd[2] = charIndex - upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset) + upSelectedStart( + textChar.start, + textLine.lineBottom + relativeOffset, + textLine.lineTop + relativeOffset + ) upSelectedEnd(textChar.end, textLine.lineBottom + relativeOffset) select(2, lineIndex, charIndex) return @@ -287,7 +300,11 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at selectStart[0] = 0 selectStart[1] = lineIndex selectStart[2] = charIndex - upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset) + upSelectedStart( + textChar.start, + textLine.lineBottom + relativeOffset, + textLine.lineTop + relativeOffset + ) upSelectChars() } return @@ -311,7 +328,11 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at selectStart[0] = 1 selectStart[1] = lineIndex selectStart[2] = charIndex - upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset) + upSelectedStart( + textChar.start, + textLine.lineBottom + relativeOffset, + textLine.lineTop + relativeOffset + ) upSelectChars() } return @@ -333,7 +354,11 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at selectStart[0] = 2 selectStart[1] = lineIndex selectStart[2] = charIndex - upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset) + upSelectedStart( + textChar.start, + textLine.lineBottom + relativeOffset, + textLine.lineTop + relativeOffset + ) upSelectChars() } return @@ -427,7 +452,11 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at selectStart[2] = charIndex val textLine = relativePage(relativePage).textLines[lineIndex] val textChar = textLine.textChars[charIndex] - upSelectedStart(textChar.start, textLine.lineBottom + relativeOffset(relativePage)) + upSelectedStart( + textChar.start, + textLine.lineBottom + relativeOffset(relativePage), + textLine.lineTop + ) upSelectChars() } @@ -475,12 +504,12 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at invalidate() } - private fun upSelectedStart(x: Float, y: Float) { - callBack.upSelectedStart(x, y + callBack.headerHeight) + private fun upSelectedStart(x: Float, y: Float, top: Float) = callBack.apply { + upSelectedStart(x, y + headerHeight, top + headerHeight) } - private fun upSelectedEnd(x: Float, y: Float) { - callBack.upSelectedEnd(x, y + callBack.headerHeight) + private fun upSelectedEnd(x: Float, y: Float) = callBack.apply { + upSelectedEnd(x, y + headerHeight) } fun cancelSelect() { @@ -580,7 +609,7 @@ class ContentTextView(context: Context, attrs: AttributeSet?) : View(context, at } interface CallBack { - fun upSelectedStart(x: Float, y: Float) + fun upSelectedStart(x: Float, y: Float, top: Float) fun upSelectedEnd(x: Float, y: Float) fun onCancelSelect() val headerHeight: Int 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 a9a752303..4e820008e 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 @@ -109,7 +109,6 @@ class ContentView(context: Context) : FrameLayout(context) { fun setContent(textPage: TextPage) { setProgress(textPage) - content_text_view.resetPageOffset() content_text_view.setContent(textPage) } 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 dbde99c7e..1b7b71b07 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 @@ -16,25 +16,20 @@ class PageView(context: Context, attrs: AttributeSet) : FrameLayout(context, attrs), DataSource { - var callBack: CallBack - var pageFactory: TextPageFactory + val callBack: CallBack get() = activity as CallBack + var pageFactory: TextPageFactory = TextPageFactory(this) var pageDelegate: PageDelegate? = null - var prevPage: ContentView - var curPage: ContentView - var nextPage: ContentView + var prevPage: ContentView = ContentView(context) + var curPage: ContentView = ContentView(context) + var nextPage: ContentView = ContentView(context) init { - callBack = activity as CallBack - nextPage = ContentView(context) addView(nextPage) - curPage = ContentView(context) addView(curPage) - prevPage = ContentView(context) addView(prevPage) upBg() setWillNotDraw(false) - pageFactory = TextPageFactory(this) upPageAnim() } @@ -170,5 +165,6 @@ class PageView(context: Context, attrs: AttributeSet) : val isInitFinish: Boolean fun clickCenter() fun screenOffTimerStart() + fun showTextActionMenu() } } 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 4173ffb09..d83f60edb 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 @@ -200,11 +200,16 @@ abstract class PageDelegate(protected val pageView: PageView) : //GestureDetector.onFling小幅移动不会触发,所以要自己判断 when (event.action) { MotionEvent.ACTION_UP, - MotionEvent.ACTION_CANCEL -> if (isMoved) { - if (selectedOnDown) { - selectedOnDown = false + MotionEvent.ACTION_CANCEL -> { + if (isTextSelected) { + pageView.callBack.showTextActionMenu() + } + if (isMoved) { + if (selectedOnDown) { + selectedOnDown = false + } + if (!noNext) onAnimStart() } - if (!noNext) onAnimStart() } } } diff --git a/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt index bfb8e822c..6c4e27073 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/page/entities/TextPage.kt @@ -18,6 +18,21 @@ data class TextPage( var height: Float = 0f ) { + fun upLinesPosition(visibleHeight: Int) { + if (textLines.size <= 1) return + if (visibleHeight - height > with(textLines.last()) { lineBottom - lineTop }) return + val surplus = (visibleHeight - textLines.last().lineBottom) + if (surplus == 0f) return + height += surplus + val tj = surplus / (textLines.size - 1) + for (i in 1 until textLines.size) { + val line = textLines[i] + line.lineTop = line.lineTop + tj * i + line.lineBase = line.lineBase + tj * i + line.lineBottom = line.lineBottom + tj * i + } + } + @Suppress("DEPRECATION") fun format(): TextPage { if (textLines.isEmpty() && ChapterProvider.visibleWidth > 0) { @@ -101,4 +116,5 @@ data class TextPage( } return percent } + } diff --git a/app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt index 58caa351d..a010428fd 100644 --- a/app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/OtherConfigFragment.kt @@ -40,7 +40,7 @@ class OtherConfigFragment : PreferenceFragmentCompat(), override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { putPrefBoolean(PreferKey.processText, isProcessTextEnabled()) addPreferencesFromResource(R.xml.pref_config_other) - upPreferenceSummary(PreferKey.downloadPath, BookHelp.downloadPath) + upPreferenceSummary(getString(R.string.pk_download_path), BookHelp.downloadPath) upPreferenceSummary(PreferKey.threadCount, AppConfig.threadCount.toString()) upPreferenceSummary(PreferKey.webPort, webPort.toString()) } @@ -74,7 +74,7 @@ class OtherConfigFragment : PreferenceFragmentCompat(), .show { putPrefInt(PreferKey.webPort, it) } - PreferKey.downloadPath -> selectDownloadPath() + getString(R.string.pk_download_path) -> selectDownloadPath() PreferKey.cleanCache -> { BookHelp.clearCache() toast(R.string.clear_cache_success) @@ -85,7 +85,7 @@ class OtherConfigFragment : PreferenceFragmentCompat(), override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { when (key) { - PreferKey.downloadPath -> { + getString(R.string.pk_download_path) -> { upPreferenceSummary(key, BookHelp.downloadPath) } PreferKey.threadCount -> upPreferenceSummary( @@ -141,13 +141,17 @@ class OtherConfigFragment : PreferenceFragmentCompat(), private fun selectDownloadPath() { FilePicker.selectFolder(this, requestCodeDownloadPath) { - removePref(PreferKey.downloadPath) + removePref(getString(R.string.pk_download_path)) } } + private fun putDownloadPath(path: String) { + putPrefString(getString(R.string.pk_download_path), path) + } + override fun onFilePicked(requestCode: Int, currentPath: String) { if (requestCode == requestCodeDownloadPath) { - putPrefString(PreferKey.downloadPath, currentPath) + putDownloadPath(currentPath) } } @@ -160,7 +164,7 @@ class OtherConfigFragment : PreferenceFragmentCompat(), uri, Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION ) - putPrefString(PreferKey.downloadPath, uri.toString()) + putDownloadPath(uri.toString()) } } } diff --git a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt index 99d7d1e54..da2672841 100644 --- a/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt +++ b/app/src/main/java/io/legado/app/ui/config/ThemeConfigFragment.kt @@ -1,6 +1,7 @@ package io.legado.app.ui.config import android.content.SharedPreferences +import android.os.Build import android.os.Bundle import android.view.View import androidx.preference.Preference @@ -16,6 +17,8 @@ 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.ColorUtils +import io.legado.app.ui.widget.number.NumberPickerDialog +import io.legado.app.ui.widget.prefs.IconListPreference import io.legado.app.utils.* @@ -25,6 +28,12 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.pref_config_theme) + if (Build.VERSION.SDK_INT < 26) { + findPreference(PreferKey.launcherIcon)?.let { + preferenceScreen.removePreference(it) + } + } + upPreferenceSummary("barElevation", AppConfig.elevation.toString()) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -145,6 +154,19 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar recreateActivities() } }.show().applyTint() + "barElevation" -> NumberPickerDialog(requireContext()) + .setTitle(getString(R.string.bar_elevation)) + .setMaxValue(32) + .setMinValue(0) + .setValue(AppConfig.elevation) + .setCustomButton((R.string.btn_default_s)) { + AppConfig.elevation = App.INSTANCE.resources.getDimension(R.dimen.design_appbar_elevation).toInt() + recreateActivities() + } + .show { + AppConfig.elevation = it + recreateActivities() + } } return super.onPreferenceTreeClick(preference) } @@ -180,4 +202,10 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), SharedPreferences.OnShar postEvent(EventBus.RECREATE, "") } + private fun upPreferenceSummary(preferenceKey: String, value: String?) { + val preference = findPreference(preferenceKey) ?: return + when (preferenceKey) { + "barElevation" -> preference.summary = getString(R.string.bar_elevation_s, value) + } + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt b/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt index 5c84aa679..46e1e446e 100644 --- a/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt +++ b/app/src/main/java/io/legado/app/ui/welcome/WelcomeActivity.kt @@ -48,7 +48,7 @@ open class WelcomeActivity : BaseActivity(R.layout.activity_welcome) { private fun startMainActivity() { startActivity() - if (getPrefBoolean(getString(R.string.pk_default_read))) { + if (getPrefBoolean(R.string.pk_default_read)) { startActivity() } finish() diff --git a/app/src/main/java/io/legado/app/ui/widget/BatteryView.kt b/app/src/main/java/io/legado/app/ui/widget/BatteryView.kt index 60e781c93..f11db64e8 100644 --- a/app/src/main/java/io/legado/app/ui/widget/BatteryView.kt +++ b/app/src/main/java/io/legado/app/ui/widget/BatteryView.kt @@ -1,67 +1,57 @@ package io.legado.app.ui.widget +import android.annotation.SuppressLint import android.content.Context import android.graphics.Canvas import android.graphics.Paint import android.graphics.Rect -import android.graphics.Typeface -import android.text.StaticLayout -import android.text.TextPaint import android.util.AttributeSet -import android.view.View import androidx.annotation.ColorInt -import io.legado.app.R +import androidx.appcompat.widget.AppCompatTextView import io.legado.app.utils.dp -import io.legado.app.utils.getCompatColor -import io.legado.app.utils.sp -class BatteryView(context: Context, attrs: AttributeSet?) : View(context, attrs) { - private var battery = 100 - private val textPaint = TextPaint() - private var batteryHeight: Int = 0 - private var batteryWidth: Int = 0 +class BatteryView(context: Context, attrs: AttributeSet?) : AppCompatTextView(context, attrs) { + private val batteryPaint = Paint() private val outFrame = Rect() private val polar = Rect() init { - textPaint.textSize = 10.sp.toFloat() - textPaint.strokeWidth = 1.dp.toFloat() - textPaint.isAntiAlias = true - textPaint.textAlign = Paint.Align.CENTER - textPaint.color = context.getCompatColor(R.color.tv_text_default) - textPaint.typeface = Typeface.createFromAsset(context.assets, "number.ttf") - batteryHeight = with(textPaint.fontMetrics) { descent - ascent + leading }.toInt() - batteryWidth = StaticLayout.getDesiredWidth("100", textPaint).toInt() + 10.dp - outFrame.set(1.dp, 1.dp, batteryWidth - 3.dp, batteryHeight - 1.dp) - polar.set(outFrame.right, batteryHeight / 3, batteryWidth, batteryHeight * 2 / 3) - } - - override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { - super.onMeasure( - MeasureSpec.makeMeasureSpec(batteryWidth, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(batteryHeight, MeasureSpec.EXACTLY) - ) + setPadding(4.dp, 0, 6.dp, 0) + batteryPaint.strokeWidth = 1.dp.toFloat() + batteryPaint.isAntiAlias = true + batteryPaint.color = paint.color } fun setColor(@ColorInt color: Int) { - textPaint.color = color + setTextColor(color) + batteryPaint.color = color invalidate() } + @SuppressLint("SetTextI18n") fun setBattery(battery: Int) { - this.battery = battery - invalidate() + text = "$battery" } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) - textPaint.style = Paint.Style.STROKE - canvas.drawRect(outFrame, textPaint) - textPaint.style = Paint.Style.FILL - canvas.drawRect(polar, textPaint) - val text = battery.toString() - val baseHeight = batteryHeight - textPaint.fontMetrics.descent - canvas.drawText(text, outFrame.right / 2.toFloat(), baseHeight, textPaint) + outFrame.set( + 1.dp, + layout.getLineTop(0) + 2.dp, + width - 3.dp, + layout.getLineBottom(0) - 2.dp + ) + val dj = (outFrame.bottom - outFrame.top) / 3 + polar.set( + outFrame.right, + outFrame.top + dj, + width - 1.dp, + outFrame.bottom - dj + ) + batteryPaint.style = Paint.Style.STROKE + canvas.drawRect(outFrame, batteryPaint) + batteryPaint.style = Paint.Style.FILL + canvas.drawRect(polar, batteryPaint) } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt index d19c8929f..663bb55a8 100644 --- a/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt +++ b/app/src/main/java/io/legado/app/ui/widget/TitleBar.kt @@ -10,6 +10,8 @@ import androidx.annotation.StyleRes import androidx.appcompat.widget.Toolbar import com.google.android.material.appbar.AppBarLayout import io.legado.app.R +import io.legado.app.help.AppConfig +import io.legado.app.lib.theme.elevation import io.legado.app.lib.theme.primaryColor import io.legado.app.utils.activity import io.legado.app.utils.navigationBarHeight @@ -141,6 +143,13 @@ class TitleBar(context: Context, attrs: AttributeSet?) : AppBarLayout(context, a backgroundColor = context.primaryColor + stateListAnimator = null + elevation = if (AppConfig.elevation < 0) { + context.elevation + } else { + AppConfig.elevation.toFloat() + } + a.recycle() } diff --git a/app/src/main/java/io/legado/app/ui/widget/number/NumberPickerDialog.kt b/app/src/main/java/io/legado/app/ui/widget/number/NumberPickerDialog.kt index 17fe9ab53..3b4c8f5db 100644 --- a/app/src/main/java/io/legado/app/ui/widget/number/NumberPickerDialog.kt +++ b/app/src/main/java/io/legado/app/ui/widget/number/NumberPickerDialog.kt @@ -40,6 +40,17 @@ class NumberPickerDialog(context: Context) { return this } + fun setCustomButton(textId: Int, listener: (() -> Unit)?): NumberPickerDialog { + builder.setNeutralButton(textId) { _, _ -> + numberPicker?.let { + it.clearFocus() + it.hideSoftInput() + listener?.invoke() + } + } + return this; + } + fun show(callBack: ((value: Int) -> Unit)?) { builder.setPositiveButton(R.string.ok) { _, _ -> numberPicker?.let { diff --git a/app/src/main/java/io/legado/app/utils/ContextExtensions.kt b/app/src/main/java/io/legado/app/utils/ContextExtensions.kt index 3436c9d94..bc3f6f9fa 100644 --- a/app/src/main/java/io/legado/app/utils/ContextExtensions.kt +++ b/app/src/main/java/io/legado/app/utils/ContextExtensions.kt @@ -12,6 +12,7 @@ import android.os.BatteryManager import android.provider.Settings import androidx.annotation.ColorRes import androidx.annotation.DrawableRes +import androidx.annotation.StringRes import androidx.core.content.ContextCompat import androidx.core.content.FileProvider import androidx.core.content.edit @@ -28,6 +29,9 @@ import java.io.FileOutputStream fun Context.getPrefBoolean(key: String, defValue: Boolean = false) = defaultSharedPreferences.getBoolean(key, defValue) +fun Context.getPrefBoolean(@StringRes keyId: Int, defValue: Boolean = false) = + defaultSharedPreferences.getBoolean(getString(keyId), defValue) + fun Context.putPrefBoolean(key: String, value: Boolean = false) = defaultSharedPreferences.edit { putBoolean(key, value) } @@ -46,6 +50,9 @@ fun Context.putPrefLong(key: String, value: Long) = fun Context.getPrefString(key: String, defValue: String? = null) = defaultSharedPreferences.getString(key, defValue) +fun Context.getPrefString(@StringRes keyId: Int, defValue: String? = null) = + defaultSharedPreferences.getString(getString(keyId), defValue) + fun Context.putPrefString(key: String, value: String) = defaultSharedPreferences.edit { putString(key, value) } diff --git a/app/src/main/res/layout-land/activity_book_info.xml b/app/src/main/res/layout-land/activity_book_info.xml new file mode 100644 index 000000000..27e0bec0d --- /dev/null +++ b/app/src/main/res/layout-land/activity_book_info.xml @@ -0,0 +1,419 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_book_info.xml b/app/src/main/res/layout/activity_book_info.xml index 8e58e34cb..568a4e60a 100644 --- a/app/src/main/res/layout/activity_book_info.xml +++ b/app/src/main/res/layout/activity_book_info.xml @@ -64,40 +64,6 @@ - - - - - - - - + + + + + + + + @@ -241,6 +241,94 @@ + + + + + + + + + + + + + + + + + + + + - - - - - - - + android:layout_height="8dp" + android:background="@color/background"> + + + android:textSize="10sp" + tools:ignore="RtlHardcoded,RtlSymmetry,SmallSp" /> diff --git a/app/src/main/res/values/array_values.xml b/app/src/main/res/values/array_values.xml index 2aa918837..c517c46ce 100644 --- a/app/src/main/res/values/array_values.xml +++ b/app/src/main/res/values/array_values.xml @@ -38,5 +38,11 @@ 9 + + 0 + 1 + 2 + 3 + \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 104febad6..a53546e7f 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -67,7 +67,7 @@ @string/app_folder_picker - + @string/screen_unspecified @string/screen_portrait @string/screen_landscape diff --git a/app/src/main/res/values/pref_key_value.xml b/app/src/main/res/values/pref_key_value.xml index 7bcded4da..0c535ad67 100644 --- a/app/src/main/res/values/pref_key_value.xml +++ b/app/src/main/res/values/pref_key_value.xml @@ -1,7 +1,7 @@ auto_refresh - list_screen_direction + list_screen_direction full_screen threads_num user_agent diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2af658b79..84e6e6bb2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -160,7 +160,7 @@ 添加书籍网址 背景 作者 - 作者:%s + 作者: %s 朗读停止 清除缓存 成功清理缓存 @@ -641,4 +641,10 @@ 加入分组 保存图片 没有默认路径 + 设置分组 + 查看目录 + 导航栏阴影 + 当前阴影大小(elevation): %s + 默认 + diff --git a/app/src/main/res/xml/pref_config_read.xml b/app/src/main/res/xml/pref_config_read.xml index a19a8ba4c..ef360b43c 100644 --- a/app/src/main/res/xml/pref_config_read.xml +++ b/app/src/main/res/xml/pref_config_read.xml @@ -2,6 +2,14 @@ + + + +