Merge branch 'master' of https://github.com/gedoor/legado into 跟随主干
commit
c18cebda9a
@ -0,0 +1,129 @@ |
|||||||
|
## 常见问题 |
||||||
|
|
||||||
|
1.为什么第一次安装好之后什么东西都没有? |
||||||
|
* 因为阅读只是一个转码工具,不提供内容,第一次安装app,需要自己手动导入书源,可以从QQ群、公众号“开源阅读软件”、酷安评论里获取由书友制作分享的书源。 |
||||||
|
|
||||||
|
2.如何导入本地书源文件? |
||||||
|
* 下载群文件里的书源文件(书源格式后缀有txt、json,其中json文件某些情况下无法导入,需要修改后缀为txt格式才可导入); |
||||||
|
* 打开阅读软件; |
||||||
|
* 我的 - 点击“书源管理”; |
||||||
|
* 点击右上角选择“本地导入”; |
||||||
|
* 左下角选择书源文件所在的路径; |
||||||
|
* 点击书源文件导入; |
||||||
|
* 导入后返回书源管理界面; |
||||||
|
* 新版qq下载路径:Android/data/com.tencent.mobileqq/Tencent/QQfile_recv/ |
||||||
|
|
||||||
|
3.如何新建大佬发的单独书源? |
||||||
|
* 复制书源代码; |
||||||
|
* 打开阅读软件; |
||||||
|
* 我的 - 点击“书源管理”; |
||||||
|
* 右上角选择“新建书源”; |
||||||
|
* 进入新建书源后点击右上角“粘贴源”; |
||||||
|
* 粘贴书源完成后点击上方保存; |
||||||
|
* 本次新建单独书源操作完成。 |
||||||
|
* 注:如果书源有错误或者复制不全会显示格式错误,请重新复制。 |
||||||
|
|
||||||
|
4.为什么导入2.0书源后看不了书? |
||||||
|
* 2.0部分书源并不适用3.0,建议导入后进行筛选。 |
||||||
|
|
||||||
|
5.阅读2.0数据如何导入阅读3.0? |
||||||
|
* 先对阅读2.0的数据进行备份,然后进入阅读3.0,点击“我的”,选择“备份与恢复”,再点击“导入旧版本数据”。 |
||||||
|
|
||||||
|
6.如何给朋友分享我的书源? |
||||||
|
* 打开阅读软件; |
||||||
|
* 点击备份; |
||||||
|
* 打开手机自带的文件管理; |
||||||
|
* 手机自带内存根目录找到YueDu3.0文件夹; |
||||||
|
* 找到myBookSource.json长按选择分享; |
||||||
|
* 选择微信分享或者QQ分享; |
||||||
|
* 选择你要分享的好友点击发送; |
||||||
|
* 好友接收后在手机自带内存根目录找到myBookSource.json文件(QQ在tencent--QQfile_recv微信在Tencent--MicroMsg--Download); |
||||||
|
* 复制该文件到手机自带内存根目录找到YueDu3.0文件夹(如已有该文件请先删除该文件或者备份到其他地方再复制到文件夹); |
||||||
|
* 打开阅读软件点击恢复。 |
||||||
|
* 注:备份路径如已修改过请在修改后的路径下查找书源文件。 |
||||||
|
|
||||||
|
7.目前阅读支持哪些格式的本地书籍? |
||||||
|
* 目前支持TXT、EPUB格式(只支持显示EPUB里的文本内容,还不支持显示图片)。 |
||||||
|
|
||||||
|
8.如何刷新书架? |
||||||
|
* 在书架界面下拉即可刷新。 |
||||||
|
|
||||||
|
9.书架界面书籍右上角的红色或者灰色背景小数字代表什么? |
||||||
|
* 红色代表书籍有更新,灰色代表无更新,数字代表未读章节。 |
||||||
|
|
||||||
|
10.如何查看书籍详情? |
||||||
|
* 长按书籍。 |
||||||
|
|
||||||
|
11.如何对书架上的书进行删除、切换书架的操作? |
||||||
|
* 书籍详情页操作即可。 |
||||||
|
|
||||||
|
12.如何禁止或允许某本书更新? |
||||||
|
* 书籍详情页,点击右上角 - “允许更新”。 |
||||||
|
|
||||||
|
13.如何更换小说封面、名字、作者或简介? |
||||||
|
* 书籍详情页,点击右上角修改按钮。 |
||||||
|
|
||||||
|
14.怎么使用自定义字体? |
||||||
|
* 阅读界面 - 字体-点击右上角选择字体文件路径。 |
||||||
|
|
||||||
|
15.目前支持哪些格式的字体文件? |
||||||
|
* 目前支持ttf、otf格式。 |
||||||
|
|
||||||
|
16.书籍经常“正在加载中”怎么办? |
||||||
|
* 在线书籍出现这个问题通常是由于源质量不好或不兼容引起的,可以换其它源多试试;本地书籍出现这个问题大概率是目录规则问题,手动切换规则可以解决。 |
||||||
|
|
||||||
|
17.书籍内容只有标题,正文内容是路径怎么办? |
||||||
|
* 通常是缓存路径引起的,更换缓存路径即可。 |
||||||
|
|
||||||
|
18.效验书源显示失效就说明书源不能用了吗? |
||||||
|
* 效验书源只是测试书源,可以做个参考,失效了不代表书源不能用了。 |
||||||
|
|
||||||
|
19.发现和正版书源能不能使用? |
||||||
|
* 发现和正版书源只能用来找书,看排行榜,不能用来看书,如需看书请切换书源。 |
||||||
|
|
||||||
|
20.替换净化是什么? |
||||||
|
* 替换净化可以去除书籍内容里的广告、错别字、屏蔽词等。 |
||||||
|
|
||||||
|
21.如何自己填写净化替换规则? |
||||||
|
* 第一行:替换规则名称 - 根据自己需求对替换净化规则进行命名; |
||||||
|
* 第二行:分组 - 净化规则的分组组别; |
||||||
|
* 第三行:替换规则 - 填写需要被替换的内容; |
||||||
|
* 第四行:替换为 - 填写想替换成的内容(如不填则默认表示删除第二行里填写的内容); |
||||||
|
* 第五行:替换范围,选填书名或者源名 - 填写此替换净化规则需要对哪本书籍或者哪个书源生效(如不填则对所有书籍和书源生效)。 |
||||||
|
* 注:如常规去除方法去除不掉,则需要勾选“使用正则表达式”,同时第二行里的替换规则也需要按照正则表达式来填写(正则表达式填写方法可自行百度学习)。 |
||||||
|
|
||||||
|
22.如何听书? |
||||||
|
* 可以使用手机自带的朗读引擎,也可使用第三方如谷歌、小米等朗读引擎。 |
||||||
|
* 【具体操作:安装-系统设置-其他高级设置-辅助功能-TTS输出-选择安装的朗读引擎(不同品牌手机的操作方法及步骤也不同,视情况而定)。】 |
||||||
|
|
||||||
|
23.如何设置屏幕方向、屏幕显示时长、显示/隐藏状态栏、显示/隐藏导航栏、音量键翻页、长按选择文本、点击总是翻下一页、自定义翻页案件? |
||||||
|
* 阅读界面,设置(可上划,下面还有其他设置)。 |
||||||
|
|
||||||
|
24.搜索的时候感觉手机卡顿,如何解决? |
||||||
|
* 我的 - 其他设置 - “更新和搜索线程数”调低。 |
||||||
|
|
||||||
|
25.更新前有什么注意事项? |
||||||
|
* 要做好备份。 |
||||||
|
|
||||||
|
26.看书时如遇到“目录为空”、“加载失败”和长串英文等情况怎么办? |
||||||
|
* 一般是书源问题,切换书源即可。 |
||||||
|
|
||||||
|
27.为什么书源这么多,发现里却只有一点点? |
||||||
|
* 书源想要在发现界面里显示需要在书源里添加发现规则,并不是所有书源都有发现规则。 |
||||||
|
|
||||||
|
28.云备份在哪? |
||||||
|
* 我的 - 备份与恢复 - WebDav设置。 |
||||||
|
|
||||||
|
29.如何操作进行云备份? |
||||||
|
* 侧栏设置,WebDav设置; |
||||||
|
* 正确填写WebDAV 服务器地址、WebDAV 账号、WebDAV 密码;(要获得这三项的信息,需要注册一个坚果云账号,如果直接在手机上注册,坚果云会让你下载app,过程比较麻烦,为了一步到位,最好是在电脑上打开这个注册链接:https://www.jianguoyun.com/d/signup;注册后,进入坚果云;点击右上角账户名处选择 “账户信息”,然后选择“安全选项”;在“安全选项” 中找到“第三方应用管理”,并选择“添加应用”,输入名称如“阅读”后,会生成密码,选择完成;其中https://dav.jianguoyun.com/dav/就是填入“WebDAV 服务器地址”的内容,“使用情况”后面的邮箱地址就是你的“WebDAV 账号”,点击显示密码后得到的密码就是你的“WebDAV 密码”。) |
||||||
|
* 无需操作,APP默认每天自动云备份一次。 |
||||||
|
|
||||||
|
30.关于云备份的相关说明 |
||||||
|
* 在正确设置好云备份的情况下,APP默认每天自动云备份一次,当日多次手动云备份会对当日的旧云备份文件进行覆盖,并不会覆盖之前及之后不同日期的备份文件,每天所自动云备份的文件会按照日期进行命名。 |
||||||
|
|
||||||
|
31.本地备份和云备份都能备份哪些东西? |
||||||
|
* 书架、看书进度、搜索记录、书源、替换、APP设置等都会备份,基本涵盖所有内容。 |
||||||
|
|
||||||
|
32.出现某些未知bug怎么办? |
||||||
|
* 清除软件数据试试看,不行再进行反馈。 |
@ -0,0 +1,93 @@ |
|||||||
|
package io.legado.app.model |
||||||
|
|
||||||
|
import io.legado.app.App |
||||||
|
import io.legado.app.data.entities.SearchBook |
||||||
|
import io.legado.app.help.AppConfig |
||||||
|
import io.legado.app.help.coroutine.Coroutine |
||||||
|
import io.legado.app.utils.getPrefString |
||||||
|
import kotlinx.coroutines.CoroutineScope |
||||||
|
import kotlinx.coroutines.Dispatchers.IO |
||||||
|
import kotlinx.coroutines.asCoroutineDispatcher |
||||||
|
import java.util.concurrent.Executors |
||||||
|
|
||||||
|
class SearchBookModel(private val scope: CoroutineScope, private val callBack: CallBack) { |
||||||
|
private var searchPool = |
||||||
|
Executors.newFixedThreadPool(AppConfig.threadCount).asCoroutineDispatcher() |
||||||
|
private var mSearchId = System.currentTimeMillis() |
||||||
|
private var searchPage = 1 |
||||||
|
private var searchKey: String = "" |
||||||
|
private var task: Coroutine<*>? = null |
||||||
|
|
||||||
|
private fun initSearchPool() { |
||||||
|
searchPool = |
||||||
|
Executors.newFixedThreadPool(AppConfig.threadCount).asCoroutineDispatcher() |
||||||
|
} |
||||||
|
|
||||||
|
fun search(searchId: Long, key: String) { |
||||||
|
if (searchId != mSearchId) { |
||||||
|
task?.cancel() |
||||||
|
searchPool.close() |
||||||
|
initSearchPool() |
||||||
|
mSearchId = searchId |
||||||
|
searchPage = 1 |
||||||
|
if (key.isEmpty()) { |
||||||
|
return |
||||||
|
} else { |
||||||
|
this.searchKey = key |
||||||
|
} |
||||||
|
} else { |
||||||
|
searchPage++ |
||||||
|
} |
||||||
|
task = Coroutine.async(scope, searchPool) { |
||||||
|
val searchGroup = App.INSTANCE.getPrefString("searchGroup") ?: "" |
||||||
|
val bookSourceList = if (searchGroup.isBlank()) { |
||||||
|
App.db.bookSourceDao().allEnabled |
||||||
|
} else { |
||||||
|
App.db.bookSourceDao().getEnabledByGroup(searchGroup) |
||||||
|
} |
||||||
|
for (item in bookSourceList) { |
||||||
|
//task取消时自动取消 by (scope = this@execute) |
||||||
|
WebBook(item).searchBook( |
||||||
|
searchKey, |
||||||
|
searchPage, |
||||||
|
scope = this, |
||||||
|
context = searchPool |
||||||
|
) |
||||||
|
.timeout(30000L) |
||||||
|
.onSuccess(IO) { |
||||||
|
if (searchId == mSearchId) { |
||||||
|
callBack.onSearchSuccess(it) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}.onStart { |
||||||
|
callBack.onSearchStart() |
||||||
|
} |
||||||
|
|
||||||
|
task?.invokeOnCompletion { |
||||||
|
if (searchId == mSearchId) { |
||||||
|
callBack.onSearchFinish() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun cancelSearch() { |
||||||
|
task?.cancel() |
||||||
|
mSearchId = 0 |
||||||
|
callBack.onSearchCancel() |
||||||
|
} |
||||||
|
|
||||||
|
fun close() { |
||||||
|
task?.cancel() |
||||||
|
mSearchId = 0 |
||||||
|
searchPool.close() |
||||||
|
} |
||||||
|
|
||||||
|
interface CallBack { |
||||||
|
fun onSearchStart() |
||||||
|
fun onSearchSuccess(searchBooks: ArrayList<SearchBook>) |
||||||
|
fun onSearchFinish() |
||||||
|
fun onSearchCancel() |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,36 +0,0 @@ |
|||||||
package io.legado.app.ui.main.bookshelf |
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment |
|
||||||
import androidx.viewpager2.adapter.FragmentStateAdapter |
|
||||||
import io.legado.app.data.entities.BookGroup |
|
||||||
import io.legado.app.ui.main.bookshelf.books.BooksFragment |
|
||||||
|
|
||||||
|
|
||||||
class BookshelfAdapter(fragment: Fragment, val callBack: CallBack) : |
|
||||||
FragmentStateAdapter(fragment) { |
|
||||||
|
|
||||||
private val ids = hashSetOf<Long>() |
|
||||||
|
|
||||||
override fun getItemCount(): Int { |
|
||||||
return callBack.groupSize |
|
||||||
} |
|
||||||
|
|
||||||
override fun getItemId(position: Int): Long { |
|
||||||
return callBack.getGroup(position).groupId.toLong() |
|
||||||
} |
|
||||||
|
|
||||||
override fun containsItem(itemId: Long): Boolean { |
|
||||||
return ids.contains(itemId) |
|
||||||
} |
|
||||||
|
|
||||||
override fun createFragment(position: Int): Fragment { |
|
||||||
val groupId = callBack.getGroup(position).groupId |
|
||||||
ids.add(groupId.toLong()) |
|
||||||
return BooksFragment.newInstance(position, groupId) |
|
||||||
} |
|
||||||
|
|
||||||
interface CallBack { |
|
||||||
val groupSize: Int |
|
||||||
fun getGroup(position: Int): BookGroup |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,17 @@ |
|||||||
|
package io.legado.app.ui.rss.read |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.util.AttributeSet |
||||||
|
import android.view.View |
||||||
|
import android.webkit.WebView |
||||||
|
|
||||||
|
class VisibleWebView( |
||||||
|
context: Context, |
||||||
|
attrs: AttributeSet? = null |
||||||
|
) : WebView(context, attrs) { |
||||||
|
|
||||||
|
override fun onWindowVisibilityChanged(visibility: Int) { |
||||||
|
super.onWindowVisibilityChanged(View.VISIBLE) |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,110 @@ |
|||||||
|
package io.legado.app.ui.widget |
||||||
|
|
||||||
|
import android.app.SearchableInfo |
||||||
|
import android.content.Context |
||||||
|
import android.graphics.Canvas |
||||||
|
import android.graphics.Paint |
||||||
|
import android.graphics.drawable.Drawable |
||||||
|
import android.text.Spannable |
||||||
|
import android.text.SpannableStringBuilder |
||||||
|
import android.text.style.ImageSpan |
||||||
|
import android.util.AttributeSet |
||||||
|
import android.util.TypedValue |
||||||
|
import android.view.Gravity |
||||||
|
import android.widget.TextView |
||||||
|
import androidx.appcompat.widget.SearchView |
||||||
|
import io.legado.app.R |
||||||
|
|
||||||
|
class SearchView : SearchView { |
||||||
|
private var mSearchHintIcon: Drawable? = null |
||||||
|
private var textView: TextView? = null |
||||||
|
|
||||||
|
constructor( |
||||||
|
context: Context?, |
||||||
|
attrs: AttributeSet? = null |
||||||
|
) : super(context, attrs) |
||||||
|
|
||||||
|
constructor( |
||||||
|
context: Context?, |
||||||
|
attrs: AttributeSet?, |
||||||
|
defStyleAttr: Int |
||||||
|
) : super(context, attrs, defStyleAttr) |
||||||
|
|
||||||
|
override fun onLayout( |
||||||
|
changed: Boolean, |
||||||
|
left: Int, |
||||||
|
top: Int, |
||||||
|
right: Int, |
||||||
|
bottom: Int |
||||||
|
) { |
||||||
|
super.onLayout(changed, left, top, right, bottom) |
||||||
|
try { |
||||||
|
if (textView == null) { |
||||||
|
textView = findViewById(androidx.appcompat.R.id.search_src_text) |
||||||
|
mSearchHintIcon = this.context.getDrawable(R.drawable.ic_search_hint) |
||||||
|
updateQueryHint() |
||||||
|
} |
||||||
|
// 改变字体 |
||||||
|
textView!!.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14f) |
||||||
|
textView!!.gravity = Gravity.CENTER_VERTICAL |
||||||
|
} catch (e: Exception) { |
||||||
|
e.printStackTrace() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun getDecoratedHint(hintText: CharSequence): CharSequence { |
||||||
|
// If the field is always expanded or we don't have a search hint icon, |
||||||
|
// then don't add the search icon to the hint. |
||||||
|
if (mSearchHintIcon == null) { |
||||||
|
return hintText |
||||||
|
} |
||||||
|
val textSize = (textView!!.textSize * 0.8).toInt() |
||||||
|
mSearchHintIcon!!.setBounds(0, 0, textSize, textSize) |
||||||
|
val ssb = SpannableStringBuilder(" ") |
||||||
|
ssb.setSpan(CenteredImageSpan(mSearchHintIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) |
||||||
|
ssb.append(hintText) |
||||||
|
return ssb |
||||||
|
} |
||||||
|
|
||||||
|
private fun updateQueryHint() { |
||||||
|
textView?.let { |
||||||
|
it.hint = getDecoratedHint(queryHint ?: "") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun setIconifiedByDefault(iconified: Boolean) { |
||||||
|
super.setIconifiedByDefault(iconified) |
||||||
|
updateQueryHint() |
||||||
|
} |
||||||
|
|
||||||
|
override fun setSearchableInfo(searchable: SearchableInfo?) { |
||||||
|
super.setSearchableInfo(searchable) |
||||||
|
searchable?.let { |
||||||
|
updateQueryHint() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun setQueryHint(hint: CharSequence?) { |
||||||
|
super.setQueryHint(hint) |
||||||
|
updateQueryHint() |
||||||
|
} |
||||||
|
|
||||||
|
internal class CenteredImageSpan(drawable: Drawable?) : ImageSpan(drawable!!) { |
||||||
|
override fun draw( |
||||||
|
canvas: Canvas, text: CharSequence, |
||||||
|
start: Int, end: Int, x: Float, |
||||||
|
top: Int, y: Int, bottom: Int, paint: Paint |
||||||
|
) { |
||||||
|
// image to draw |
||||||
|
val b = drawable |
||||||
|
// font metrics of text to be replaced |
||||||
|
val fm = paint.fontMetricsInt |
||||||
|
val transY = ((y + fm.descent + y + fm.ascent) / 2 |
||||||
|
- b.bounds.bottom / 2) |
||||||
|
canvas.save() |
||||||
|
canvas.translate(x, transY.toFloat()) |
||||||
|
b.draw(canvas) |
||||||
|
canvas.restore() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,185 @@ |
|||||||
|
package io.legado.app.ui.widget |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.graphics.Canvas |
||||||
|
import android.graphics.Color |
||||||
|
import android.graphics.Paint |
||||||
|
import android.graphics.RectF |
||||||
|
import android.util.AttributeSet |
||||||
|
import android.view.View |
||||||
|
import android.widget.RelativeLayout |
||||||
|
import io.legado.app.R |
||||||
|
import io.legado.app.utils.getCompatColor |
||||||
|
|
||||||
|
/** |
||||||
|
* ShadowLayout.java |
||||||
|
* |
||||||
|
* |
||||||
|
* Created by lijiankun on 17/8/11. |
||||||
|
*/ |
||||||
|
class ShadowLayout( |
||||||
|
context: Context, |
||||||
|
attrs: AttributeSet? = null |
||||||
|
) : RelativeLayout(context, attrs) { |
||||||
|
private val mPaint = |
||||||
|
Paint(Paint.ANTI_ALIAS_FLAG) |
||||||
|
private val mRectF = RectF() |
||||||
|
|
||||||
|
/** |
||||||
|
* 阴影的颜色 |
||||||
|
*/ |
||||||
|
private var mShadowColor = Color.TRANSPARENT |
||||||
|
|
||||||
|
/** |
||||||
|
* 阴影的大小范围 |
||||||
|
*/ |
||||||
|
private var mShadowRadius = 0f |
||||||
|
|
||||||
|
/** |
||||||
|
* 阴影 x 轴的偏移量 |
||||||
|
*/ |
||||||
|
private var mShadowDx = 0f |
||||||
|
|
||||||
|
/** |
||||||
|
* 阴影 y 轴的偏移量 |
||||||
|
*/ |
||||||
|
private var mShadowDy = 0f |
||||||
|
|
||||||
|
/** |
||||||
|
* 阴影显示的边界 |
||||||
|
*/ |
||||||
|
private var mShadowSide = ALL |
||||||
|
|
||||||
|
/** |
||||||
|
* 阴影的形状,圆形/矩形 |
||||||
|
*/ |
||||||
|
private var mShadowShape = SHAPE_RECTANGLE |
||||||
|
|
||||||
|
|
||||||
|
init { |
||||||
|
setLayerType(View.LAYER_TYPE_SOFTWARE, null) // 关闭硬件加速 |
||||||
|
setWillNotDraw(false) // 调用此方法后,才会执行 onDraw(Canvas) 方法 |
||||||
|
val typedArray = |
||||||
|
context.obtainStyledAttributes(attrs, R.styleable.ShadowLayout) |
||||||
|
mShadowColor = typedArray.getColor( |
||||||
|
R.styleable.ShadowLayout_shadowColor, |
||||||
|
context.getCompatColor(android.R.color.black) |
||||||
|
) |
||||||
|
mShadowRadius = |
||||||
|
typedArray.getDimension(R.styleable.ShadowLayout_shadowRadius, dip2px(0f)) |
||||||
|
mShadowDx = typedArray.getDimension(R.styleable.ShadowLayout_shadowDx, dip2px(0f)) |
||||||
|
mShadowDy = typedArray.getDimension(R.styleable.ShadowLayout_shadowDy, dip2px(0f)) |
||||||
|
mShadowSide = |
||||||
|
typedArray.getInt(R.styleable.ShadowLayout_shadowSide, ALL) |
||||||
|
mShadowShape = typedArray.getInt( |
||||||
|
R.styleable.ShadowLayout_shadowShape, |
||||||
|
SHAPE_RECTANGLE |
||||||
|
) |
||||||
|
typedArray.recycle() |
||||||
|
|
||||||
|
setUpShadowPaint() |
||||||
|
} |
||||||
|
|
||||||
|
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { |
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec) |
||||||
|
val effect = mShadowRadius + dip2px(5f) |
||||||
|
var rectLeft = 0f |
||||||
|
var rectTop = 0f |
||||||
|
var rectRight = this.measuredWidth.toFloat() |
||||||
|
var rectBottom = this.measuredHeight.toFloat() |
||||||
|
var paddingLeft = 0 |
||||||
|
var paddingTop = 0 |
||||||
|
var paddingRight = 0 |
||||||
|
var paddingBottom = 0 |
||||||
|
this.width |
||||||
|
if (mShadowSide and LEFT == LEFT) { |
||||||
|
rectLeft = effect |
||||||
|
paddingLeft = effect.toInt() |
||||||
|
} |
||||||
|
if (mShadowSide and TOP == TOP) { |
||||||
|
rectTop = effect |
||||||
|
paddingTop = effect.toInt() |
||||||
|
} |
||||||
|
if (mShadowSide and RIGHT == RIGHT) { |
||||||
|
rectRight = this.measuredWidth - effect |
||||||
|
paddingRight = effect.toInt() |
||||||
|
} |
||||||
|
if (mShadowSide and BOTTOM == BOTTOM) { |
||||||
|
rectBottom = this.measuredHeight - effect |
||||||
|
paddingBottom = effect.toInt() |
||||||
|
} |
||||||
|
if (mShadowDy != 0.0f) { |
||||||
|
rectBottom -= mShadowDy |
||||||
|
paddingBottom += mShadowDy.toInt() |
||||||
|
} |
||||||
|
if (mShadowDx != 0.0f) { |
||||||
|
rectRight -= mShadowDx |
||||||
|
paddingRight += mShadowDx.toInt() |
||||||
|
} |
||||||
|
mRectF.left = rectLeft |
||||||
|
mRectF.top = rectTop |
||||||
|
mRectF.right = rectRight |
||||||
|
mRectF.bottom = rectBottom |
||||||
|
setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 真正绘制阴影的方法 |
||||||
|
*/ |
||||||
|
override fun onDraw(canvas: Canvas) { |
||||||
|
super.onDraw(canvas) |
||||||
|
setUpShadowPaint() |
||||||
|
if (mShadowShape == SHAPE_RECTANGLE) { |
||||||
|
canvas.drawRect(mRectF, mPaint) |
||||||
|
} else if (mShadowShape == SHAPE_OVAL) { |
||||||
|
canvas.drawCircle( |
||||||
|
mRectF.centerX(), |
||||||
|
mRectF.centerY(), |
||||||
|
mRectF.width().coerceAtMost(mRectF.height()) / 2, |
||||||
|
mPaint |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun setShadowColor(shadowColor: Int) { |
||||||
|
mShadowColor = shadowColor |
||||||
|
requestLayout() |
||||||
|
postInvalidate() |
||||||
|
} |
||||||
|
|
||||||
|
fun setShadowRadius(shadowRadius: Float) { |
||||||
|
mShadowRadius = shadowRadius |
||||||
|
requestLayout() |
||||||
|
postInvalidate() |
||||||
|
} |
||||||
|
|
||||||
|
private fun setUpShadowPaint() { |
||||||
|
mPaint.reset() |
||||||
|
mPaint.isAntiAlias = true |
||||||
|
mPaint.color = Color.TRANSPARENT |
||||||
|
mPaint.setShadowLayer(mShadowRadius, mShadowDx, mShadowDy, mShadowColor) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* dip2px dp 值转 px 值 |
||||||
|
* |
||||||
|
* @param dpValue dp 值 |
||||||
|
* @return px 值 |
||||||
|
*/ |
||||||
|
private fun dip2px(dpValue: Float): Float { |
||||||
|
val dm = context.resources.displayMetrics |
||||||
|
val scale = dm.density |
||||||
|
return dpValue * scale + 0.5f |
||||||
|
} |
||||||
|
|
||||||
|
companion object { |
||||||
|
const val ALL = 0x1111 |
||||||
|
const val LEFT = 0x0001 |
||||||
|
const val TOP = 0x0010 |
||||||
|
const val RIGHT = 0x0100 |
||||||
|
const val BOTTOM = 0x1000 |
||||||
|
const val SHAPE_RECTANGLE = 0x0001 |
||||||
|
const val SHAPE_OVAL = 0x0010 |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
package io.legado.app.ui.widget.prefs |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.util.AttributeSet |
||||||
|
import android.widget.TextView |
||||||
|
import androidx.preference.PreferenceViewHolder |
||||||
|
import io.legado.app.R |
||||||
|
|
||||||
|
class EditTextPreference(context: Context, attrs: AttributeSet) : androidx.preference.EditTextPreference(context, attrs) { |
||||||
|
|
||||||
|
init { |
||||||
|
// isPersistent = true |
||||||
|
layoutResource = R.layout.view_preference |
||||||
|
} |
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: PreferenceViewHolder?) { |
||||||
|
Preference.bindView<TextView>(context, holder, icon, title, summary, null, null) |
||||||
|
super.onBindViewHolder(holder) |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,85 @@ |
|||||||
|
package io.legado.app.ui.widget.prefs |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.graphics.drawable.Drawable |
||||||
|
import android.util.AttributeSet |
||||||
|
import android.view.LayoutInflater |
||||||
|
import android.view.View |
||||||
|
import android.widget.FrameLayout |
||||||
|
import android.widget.ImageView |
||||||
|
import android.widget.TextView |
||||||
|
import androidx.core.view.isVisible |
||||||
|
import androidx.preference.PreferenceViewHolder |
||||||
|
import io.legado.app.R |
||||||
|
import io.legado.app.lib.theme.accentColor |
||||||
|
import org.jetbrains.anko.layoutInflater |
||||||
|
import kotlin.math.roundToInt |
||||||
|
|
||||||
|
class Preference(context: Context, attrs: AttributeSet) : androidx.preference.Preference(context, attrs) { |
||||||
|
|
||||||
|
init { |
||||||
|
// isPersistent = true |
||||||
|
layoutResource = R.layout.view_preference |
||||||
|
} |
||||||
|
|
||||||
|
companion object { |
||||||
|
|
||||||
|
fun <T: View> bindView(context: Context, it: PreferenceViewHolder?, icon: Drawable?, title: CharSequence?, summary: CharSequence?, weightLayoutRes: Int?, viewId: Int?, |
||||||
|
weightWidth: Int = 0, weightHeight: Int = 0): T? { |
||||||
|
if (it == null) return null |
||||||
|
val view = it.findViewById(R.id.preference_title) |
||||||
|
if (view is TextView) { |
||||||
|
view.text = title |
||||||
|
view.isVisible = title != null && title.isNotEmpty() |
||||||
|
|
||||||
|
val tvSummary = it.findViewById(R.id.preference_desc) |
||||||
|
if (tvSummary is TextView) { |
||||||
|
tvSummary.text = summary |
||||||
|
tvSummary.isVisible = summary != null && summary.isNotEmpty() |
||||||
|
} |
||||||
|
|
||||||
|
val iconView = it.findViewById(R.id.preference_icon) |
||||||
|
if (iconView is ImageView) { |
||||||
|
iconView.isVisible = icon != null && icon.isVisible |
||||||
|
iconView.setImageDrawable(icon) |
||||||
|
iconView.setColorFilter(context.accentColor) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (weightLayoutRes != null && weightLayoutRes != 0 && viewId != null && viewId != 0) { |
||||||
|
val lay = it.findViewById(R.id.preference_widget) |
||||||
|
if (lay is FrameLayout) { |
||||||
|
var v = it.itemView.findViewById<T>(viewId) |
||||||
|
if (v == null) { |
||||||
|
val inflater: LayoutInflater = context.layoutInflater |
||||||
|
val childView = inflater.inflate(weightLayoutRes, null) |
||||||
|
lay.removeAllViews() |
||||||
|
lay.addView(childView) |
||||||
|
lay.isVisible = true |
||||||
|
v = lay.findViewById(viewId) |
||||||
|
} |
||||||
|
|
||||||
|
if (weightWidth > 0 || weightHeight > 0) { |
||||||
|
val lp = lay.layoutParams |
||||||
|
if (weightHeight > 0) |
||||||
|
lp.height = (context.resources.displayMetrics.density * weightHeight).roundToInt() |
||||||
|
if (weightWidth > 0) |
||||||
|
lp.width = (context.resources.displayMetrics.density * weightWidth).roundToInt() |
||||||
|
lay.layoutParams = lp |
||||||
|
} |
||||||
|
|
||||||
|
return v |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return null |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: PreferenceViewHolder?) { |
||||||
|
bindView<View>(context, holder, icon, title, summary, null, null) |
||||||
|
super.onBindViewHolder(holder) |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,66 @@ |
|||||||
|
package io.legado.app.utils |
||||||
|
|
||||||
|
import org.jsoup.internal.StringUtil |
||||||
|
import org.jsoup.nodes.CDataNode |
||||||
|
import org.jsoup.nodes.Element |
||||||
|
import org.jsoup.nodes.Node |
||||||
|
import org.jsoup.nodes.TextNode |
||||||
|
import org.jsoup.select.NodeTraversor |
||||||
|
import org.jsoup.select.NodeVisitor |
||||||
|
|
||||||
|
|
||||||
|
fun Element.textArray(): Array<String> { |
||||||
|
val accum = StringUtil.borrowBuilder() |
||||||
|
NodeTraversor.traverse(object : NodeVisitor { |
||||||
|
override fun head(node: Node, depth: Int) { |
||||||
|
if (node is TextNode) { |
||||||
|
appendNormalisedText(accum, node) |
||||||
|
} else if (node is Element) { |
||||||
|
if (accum.isNotEmpty() && |
||||||
|
(node.isBlock || node.tag().name == "br") && |
||||||
|
!lastCharIsWhitespace(accum) |
||||||
|
) accum.append("\n") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun tail(node: Node, depth: Int) { |
||||||
|
if (node is Element) { |
||||||
|
if (node.isBlock && node.nextSibling() is TextNode && !lastCharIsWhitespace( |
||||||
|
accum |
||||||
|
) |
||||||
|
) accum.append("\n") |
||||||
|
} |
||||||
|
} |
||||||
|
}, this) |
||||||
|
val text = StringUtil.releaseBuilder(accum).trim { it <= ' ' } |
||||||
|
return text.splitNotBlank("\n") |
||||||
|
} |
||||||
|
|
||||||
|
private fun appendNormalisedText(accum: StringBuilder, textNode: TextNode) { |
||||||
|
val text = textNode.wholeText |
||||||
|
if (preserveWhitespace(textNode.parentNode()) || textNode is CDataNode) |
||||||
|
accum.append(text) |
||||||
|
else StringUtil.appendNormalisedWhitespace( |
||||||
|
accum, |
||||||
|
text, |
||||||
|
lastCharIsWhitespace(accum) |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
private fun preserveWhitespace(node: Node?): Boolean { |
||||||
|
if (node is Element) { |
||||||
|
var el = node as Element? |
||||||
|
var i = 0 |
||||||
|
do { |
||||||
|
if (el!!.tag().preserveWhitespace()) return true |
||||||
|
el = el.parent() |
||||||
|
i++ |
||||||
|
} while (i < 6 && el != null) |
||||||
|
} |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
private fun lastCharIsWhitespace(sb: java.lang.StringBuilder): Boolean { |
||||||
|
return sb.isNotEmpty() && sb[sb.length - 1] == ' ' |
||||||
|
} |
||||||
|
|
@ -1,24 +0,0 @@ |
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
|
||||||
android:width="108dp" |
|
||||||
android:height="108dp" |
|
||||||
android:viewportWidth="108" |
|
||||||
android:viewportHeight="108"> |
|
||||||
<path |
|
||||||
android:pathData="M34.73,33.55l-0.09,13.54A5.17,5.17 0,0 1,33.23 50c-0.23,0.06 -0.38,0 -0.44,-0.18l0.09,-6.41L33,34.25l-0.09,-2.55 2,0.71c0.18,0.06 0.21,0.17 0.09,0.35ZM43.08,40.41c0.11,0.06 0.11,0.14 0,0.26l-0.27,0.53 -0.52,2.55c-0.12,0.47 0,0.73 0.35,0.79a4.7,4.7 0,0 0,1.84 -0.18c0.41,0 0.74,-0.38 1,-1.14a0.26,0.26 0,0 1,0.18 -0.09s0.08,0.06 0.08,0.18c-0.11,0.7 0,1.11 0.27,1.23 0.64,0.76 0.44,1.32 -0.62,1.67a6,6 0,0 1,-2.72 0.17c-1.06,-0.29 -1.56,-1.23 -1.5,-2.81l0.09,-2.2L41.26,39.79L39.47,39.79l1.23,0.53c0.12,0.06 0.12,0.15 0,0.26l-0.26,0.35a19.72,19.72 0,0 1,-5.62 7c-0.18,0.05 -0.21,0 -0.09,-0.18a19.79,19.79 0,0 0,4.22 -8h-0.71a3.35,3.35 0,0 1,-1.05 1.41c-0.3,0.17 -0.47,0.14 -0.53,-0.09l0.09,-2.46L36.75,37.42q0,-0.44 -0.09,-1.41v-0.79q0,-0.09 0.18,-0.09l1.49,0.79 2.9,-0.08a16,16 0,0 0,1.14 -4l1.94,0.62c0.11,0 0.11,0.17 0,0.35s-0.5,0.52 -1,1l-1.76,1.94L43,35.75l0.79,-1 1.76,1c0.11,0 0.11,0 0,0.17l-0.44,0.7L45,39.35l0.18,0.27c0,0.11 0,0.17 -0.09,0.17L41.76,39.79ZM35.17,28.72a0.87,0.87 0,0 1,0.26 0.08c1.93,0.65 2.87,1.18 2.81,1.59s-0.26,1 -1,1.67c-0.41,0.17 -0.68,0.08 -0.79,-0.27a8,8 0,0 0,-1.5 -2.9C34.93,28.72 35,28.66 35.17,28.72ZM37.89,32.41c1.47,0.64 2.23,1.23 2.29,1.76a1.51,1.51 0,0 1,-0.88 1.23c-0.35,0.06 -0.56,-0.06 -0.62,-0.36a3.14,3.14 0,0 0,-0.88 -2.46C37.74,32.41 37.77,32.35 37.89,32.41ZM38.24,36.41v3L43,39.26v-3ZM42.46,31.41a20,20 0,0 0,-2.72 0.18L39,31l7.65,-0.26 1,-1.06 1.67,1.15h0.09c0.05,0.05 0,0.14 -0.09,0.26l-0.62,1 0.09,8.79L49,45.68a4.38,4.38 0,0 1,-2.73 4.13,0.66 0.66,0 0,1 -0.26,0.09c-0.06,-0.06 -0.06,-0.15 0,-0.26a2.43,2.43 0,0 0,-0.88 -1.85,0.26 0.26,0 0,1 -0.09,-0.18c0,-0.06 0,-0.08 0.09,-0.08 1.23,0 1.79,-0.24 1.67,-0.88l-0.09,-15.47Z" |
|
||||||
android:fillColor="#fff" /> |
|
||||||
<path |
|
||||||
android:pathData="M63.27,43.66c0.18,-0.06 0.21,0 0.09,0.17L60.28,47a21.87,21.87 0,0 0,-1.67 1.67c-0.06,0.12 -0.14,0.12 -0.26,0L57,47.35c-0.17,-0.12 -0.2,-0.2 -0.09,-0.26 0.82,-0.41 1.44,-0.71 1.85,-0.88l-0.09,-10 -1.49,0.09a6.65,6.65 0,0 0,-1.76 0.17l-0.79,-0.7 3.78,-0.09 1,-1.14 1.75,1q0.18,0.09 0,0.27l-0.44,0.61 -0.61,9ZM57.27,29.24c1.69,0.65 2.69,1.26 3,1.85a1.93,1.93 0,0 1,-1 1.85,0.6 0.6,0 0,1 -0.88,-0.27 6.33,6.33 0,0 0,-1.32 -3.25C57.06,29.24 57.12,29.19 57.3,29.24ZM67.84,36.1l2.38,0.79c0.17,0.06 0.2,0.21 0.08,0.44l-0.43,0.62 -0.27,2.9a9.75,9.75 0,0 1,-0.26 1.4l3.6,-0.09 1.23,-1.4 1.76,1.58q0.18,0.18 -0.09,0.18l-6.59,0.26q-0.61,5.1 -11.51,7.56 -0.27,0 -0.27,-0.09a0.28,0.28 0,0 1,0.18 -0.26q9,-2.46 9.75,-7.21L64.77,43a13,13 0,0 0,-2 0.17,1.48 1.48,0 0,1 -0.44,0.09l-0.53,-0.7 5.71,-0.18A5.35,5.35 0,0 0,67.67 41l0.17,-1.76a18,18 0,0 0,0 -2.55ZM65.91,32.58c-0.82,0.06 -1.58,0.15 -2.29,0.27l-0.7,-0.71 4.31,-0.08v-0.62c0,-1.17 0,-2.08 -0.09,-2.72l2.37,0.61q0.18,0 0.18,0.09a0.28,0.28 0,0 1,-0.09 0.35,1.9 1.9,0 0,0 -0.35,1.32l-0.09,0.88 2.29,-0.09 1,-1.05 1.41,1.23 0.09,0.17a0.26,0.26 0,0 1,-0.18 0.09l-4.66,0.18v2.63L72.68,35l0.88,-1 2.11,1.84a0.29,0.29 0,0 1,0.17 0.27,0.9 0.9,0 0,1 -0.26,0.17 5.83,5.83 0,0 0,-3.34 1.41q-0.27,0.09 -0.18,-0.18l0.62,-2 -7.3,0.18a7.26,7.26 0,0 0,-0.79 0.09c-0.94,0.11 -1.55,0.2 -1.84,0.26L62,35.4l5.19,-0.18L67.19,32.58ZM62.83,38.74c1.82,0.47 2.79,0.93 2.9,1.4a1.47,1.47 0,0 1,-0.52 1.41c-0.36,0.29 -0.62,0.23 -0.79,-0.18A8.87,8.87 0,0 0,62.75 39C62.63,38.82 62.66,38.74 62.83,38.74ZM64.15,36.36c1.58,0.35 2.4,0.71 2.46,1.06a1.54,1.54 0,0 1,-0.44 1.32c-0.35,0.23 -0.58,0.17 -0.7,-0.18a3.66,3.66 0,0 0,-1.32 -2Q63.9,36.45 64.15,36.36ZM69.15,44.36q3.87,1.23 4.92,2.46c0.24,0.47 0.09,1.15 -0.44,2 -0.23,0.24 -0.41,0.36 -0.52,0.36s-0.27,-0.15 -0.44,-0.44a11.71,11.71 0,0 0,-3.61 -4.22Q69,44.45 69.16,44.36Z" |
|
||||||
android:fillColor="#fff" /> |
|
||||||
<path |
|
||||||
android:pathData="M44.5,53.5l0,0 0,0a2,2 0,0 1,0.57 -0.33,2.29 2.29,0 0,1 0.69,-0.14v0.49a1.39,1.39 0,0 0,-0.5 0.09,1.27 1.27,0 0,0 -0.42,0.25 1.23,1.23 0,0 0,-0.29 0.35,1.33 1.33,0 0,0 -0.14,0.44v2.16H44V53h0.52Z" |
|
||||||
android:fillColor="#fff" /> |
|
||||||
<path |
|
||||||
android:pathData="M51.49,56.35a2.72,2.72 0,0 1,-0.71 0.29,2.57 2.57,0 0,1 -0.72,0.11 2.42,2.42 0,0 1,-1 -0.2,2.22 2.22,0 0,1 -0.42,-0.25 1.88,1.88 0,0 1,-0.34 -0.35,1.54 1.54,0 0,1 -0.24,-0.48 2,2 0,0 1,-0.09 -0.61,2 2,0 0,1 0.09,-0.62 1.69,1.69 0,0 1,0.23 -0.51,1.86 1.86,0 0,1 0.36,-0.38 2.43,2.43 0,0 1,0.44 -0.26,2.06 2.06,0 0,1 0.76,-0.17 1.92,1.92 0,0 1,0.74 0.15,2.22 2.22,0 0,1 0.42,0.25 1.48,1.48 0,0 1,0.33 0.37,1.76 1.76,0 0,1 0.22,0.48 2.23,2.23 0,0 1,0.08 0.6L51.64,55L48.51,55a1.41,1.41 0,0 0,0.09 0.38,1.29 1.29,0 0,0 0.16,0.31 1.47,1.47 0,0 0,0.55 0.44,2 2,0 0,0 0.75,0.14 2.36,2.36 0,0 0,0.58 -0.07,2.31 2.31,0 0,0 0.57,-0.24ZM49.33,53.51a1.51,1.51 0,0 0,-0.5 0.38,1.4 1.4,0 0,0 -0.29,0.64h2.58a1.3,1.3 0,0 0,-0.24 -0.66,1.35 1.35,0 0,0 -0.49,-0.37 1.27,1.27 0,0 0,-0.52 -0.1A1.37,1.37 0,0 0,49.33 53.51Z" |
|
||||||
android:fillColor="#fff" /> |
|
||||||
<path |
|
||||||
android:pathData="M53.9,53.46a1.72,1.72 0,0 1,0.53 -0.34,2.83 2.83,0 0,1 0.5,-0.13 2.45,2.45 0,0 1,0.54 0,1.86 1.86,0 0,1 0.52,0.11 1.13,1.13 0,0 1,0.43 0.26,0.89 0.89,0 0,1 0.25,0.34 1.4,1.4 0,0 1,0.14 0.56c0,0.2 0,0.43 0,0.68h0v1.76h-0.51v-0.34a1.82,1.82 0,0 1,-0.36 0.2,2.35 2.35,0 0,1 -0.37,0.14 1.71,1.71 0,0 1,-0.84 0,1.09 1.09,0 0,1 -0.83,-0.73 1.17,1.17 0,0 1,-0.05 -0.38,1 1,0 0,1 0.08,-0.42 1.13,1.13 0,0 1,0.24 -0.36,1.31 1.31,0 0,1 0.28,-0.2l0.32,-0.11 0.34,-0.05 0.38,0 0.39,0a2.7,2.7 0,0 0,0.41 -0.06,1.44 1.44,0 0,0 -0.1,-0.48 0.72,0.72 0,0 0,-0.14 -0.19,0.85 0.85,0 0,0 -0.28,-0.16 1.53,1.53 0,0 0,-0.36 -0.07,1.8 1.8,0 0,0 -0.8,0.13 0.75,0.75 0,0 0,-0.2 0.1,0.76 0.76,0 0,0 -0.17,0.13ZM56.32,54.92h0v-0.1l-0.41,0 -0.38,0 -0.56,0a0.82,0.82 0,0 0,-0.42 0.19,0.53 0.53,0 0,0 -0.12,0.2 0.49,0.49 0,0 0,0 0.25,0.69 0.69,0 0,0 0.13,0.43 0.61,0.61 0,0 0,0.36 0.23,1.18 1.18,0 0,0 0.59,0 2,2 0,0 0,0.43 -0.19,2.15 2.15,0 0,0 0.43,-0.33Z" |
|
||||||
android:fillColor="#fff" /> |
|
||||||
<path |
|
||||||
android:pathData="M62,56.74h-0.9a1.67,1.67 0,0 1,-0.71 -0.15,1.79 1.79,0 0,1 -0.56,-0.42 2,2 0,0 1,-0.36 -0.6,1.92 1.92,0 0,1 -0.13,-0.72 2,2 0,0 1,0.49 -1.34,1.76 1.76,0 0,1 0.56,-0.41 1.67,1.67 0,0 1,0.71 -0.15L62,52.95v-1.4h0.51v5.19L62,56.74ZM62,53.43h-0.9a1.12,1.12 0,0 0,-0.48 0.1,1.24 1.24,0 0,0 -0.39,0.29 1.29,1.29 0,0 0,-0.27 0.45,1.57 1.57,0 0,0 -0.1,0.58 1.47,1.47 0,0 0,0.1 0.56,1.29 1.29,0 0,0 0.27,0.45 1.11,1.11 0,0 0,0.39 0.29,1.13 1.13,0 0,0 0.48,0.11L62,56.26Z" |
|
||||||
android:fillColor="#fff" /> |
|
||||||
</vector> |
|
@ -1,56 +0,0 @@ |
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
|
||||||
xmlns:aapt="http://schemas.android.com/aapt" |
|
||||||
android:width="108dp" |
|
||||||
android:height="108dp" |
|
||||||
android:viewportWidth="108" |
|
||||||
android:viewportHeight="108"> |
|
||||||
<path |
|
||||||
android:pathData="M0,0h108v108h-108z" |
|
||||||
android:fillColor="#4d4d4d" /> |
|
||||||
<path android:pathData="M0,108H54V64c0,-12 -54,-5 -54,-5Z"> |
|
||||||
<aapt:attr name="android:fillColor"> |
|
||||||
<gradient |
|
||||||
android:startY="79.39" |
|
||||||
android:startX="0.55" |
|
||||||
android:endY="88.08" |
|
||||||
android:endX="53.13" |
|
||||||
android:type="linear"> |
|
||||||
<item |
|
||||||
android:offset="0" |
|
||||||
android:color="#FFFFFFFF" /> |
|
||||||
<item |
|
||||||
android:offset="1" |
|
||||||
android:color="#FFCCCCCC" /> |
|
||||||
</gradient> |
|
||||||
</aapt:attr> |
|
||||||
</path> |
|
||||||
<path |
|
||||||
android:pathData="M108,108H54V64c0,-12 54,-5 54,-5Z" |
|
||||||
android:fillColor="#fff" /> |
|
||||||
<path android:pathData="M71.5,70 L78,76V57a94.89,94.89 0,0 0,-13 0.75V76Z"> |
|
||||||
<aapt:attr name="android:fillColor"> |
|
||||||
<gradient |
|
||||||
android:startY="57.11" |
|
||||||
android:startX="71.5" |
|
||||||
android:endY="76" |
|
||||||
android:endX="71.5" |
|
||||||
android:type="linear"> |
|
||||||
<item |
|
||||||
android:offset="0" |
|
||||||
android:color="#FFFFFFFF" /> |
|
||||||
<item |
|
||||||
android:offset="0.24" |
|
||||||
android:color="#FFFFE1DD" /> |
|
||||||
<item |
|
||||||
android:offset="0.58" |
|
||||||
android:color="#FFFFBEB6" /> |
|
||||||
<item |
|
||||||
android:offset="0.84" |
|
||||||
android:color="#FFFFA89D" /> |
|
||||||
<item |
|
||||||
android:offset="1" |
|
||||||
android:color="#FFFFA094" /> |
|
||||||
</gradient> |
|
||||||
</aapt:attr> |
|
||||||
</path> |
|
||||||
</vector> |
|
@ -0,0 +1,7 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" > |
||||||
|
<!-- 角度 --> |
||||||
|
<corners android:radius="6dp"/> |
||||||
|
<!-- 填充色 --> |
||||||
|
<solid android:color="@color/transparent10" /> |
||||||
|
</shape> |
@ -0,0 +1,10 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<ripple xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:color="@color/btn_bg_press"> |
||||||
|
<item> |
||||||
|
<shape android:shape="rectangle"> |
||||||
|
<solid android:color="@color/background_prefs" /> |
||||||
|
<corners android:radius="0dp" /> |
||||||
|
</shape> |
||||||
|
</item> |
||||||
|
</ripple> |
@ -0,0 +1,11 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" > |
||||||
|
<!-- 角度 --> |
||||||
|
<corners android:radius="35dp"/> |
||||||
|
<!-- 填充色 --> |
||||||
|
<solid android:color="@color/transparent10" /> |
||||||
|
<!-- 描边 设置线宽及颜色 --> |
||||||
|
<stroke |
||||||
|
android:color="@color/transparent10" |
||||||
|
android:width="0.5dp" /> |
||||||
|
</shape> |
@ -0,0 +1,9 @@ |
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:width="64dp" |
||||||
|
android:height="64dp" |
||||||
|
android:viewportWidth="1024" |
||||||
|
android:viewportHeight="1024"> |
||||||
|
<path |
||||||
|
android:pathData="M512,685.25l-278.62,-278.62 45.25,-45.25L512,594.75l233.38,-233.38 45.25,45.25z" |
||||||
|
android:fillColor="#181818"/> |
||||||
|
</vector> |
@ -0,0 +1,9 @@ |
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:width="64dp" |
||||||
|
android:height="64dp" |
||||||
|
android:viewportWidth="1024" |
||||||
|
android:viewportHeight="1024"> |
||||||
|
<path |
||||||
|
android:pathData="M434.94,790.62l-45.25,-45.25L623.04,512l-233.38,-233.38 45.25,-45.25L713.57,512z" |
||||||
|
android:fillColor="#181818"/> |
||||||
|
</vector> |
@ -0,0 +1,5 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android"> |
||||||
|
<item android:drawable="@drawable/ic_bottom_books_e" android:state_checked="false" /> |
||||||
|
<item android:drawable="@drawable/ic_bottom_books_s" android:state_checked="true" /> |
||||||
|
</selector> |
@ -0,0 +1,12 @@ |
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:width="24dp" |
||||||
|
android:height="24dp" |
||||||
|
android:viewportWidth="24" |
||||||
|
android:viewportHeight="24"> |
||||||
|
<path |
||||||
|
android:pathData="M23,3V2.5a0.5,0.5 0,0 0,-0.5 -0.5H5.69A4.63,4.63 0,0 0,1 6.06,4.51 4.51,0 0,0 5.5,11h17a0.5,0.5 0,0 0,0.5 -0.5V10a0.5,0.5 0,0 0,-0.41 -0.5,3 3,0 0,1 0,-5.94A0.5,0.5 0,0 0,23 3ZM2.56,5.9A3.09,3.09 0,0 1,5.62 3.5H19.67a4.43,4.43 0,0 0,0 6H5.5A3,3 0,0 1,2.56 5.9Z" |
||||||
|
android:fillColor="#2f45a6" /> |
||||||
|
<path |
||||||
|
android:pathData="M1,21v0.53a0.5,0.5 0,0 0,0.5 0.5H18.31A4.63,4.63 0,0 0,23 17.94,4.51 4.51,0 0,0 18.5,13H1.5a0.5,0.5 0,0 0,-0.5 0.5V14a0.5,0.5 0,0 0,0.41 0.5,3 3,0 0,1 0,5.94A0.5,0.5 0,0 0,1 21ZM21.44,18.1a3.09,3.09 0,0 1,-3.06 2.4h-14a4.43,4.43 0,0 0,0 -6H18.5A3,3 0,0 1,21.44 18.1Z" |
||||||
|
android:fillColor="#2f45a6" /> |
||||||
|
</vector> |
@ -0,0 +1,12 @@ |
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:width="24dp" |
||||||
|
android:height="24dp" |
||||||
|
android:viewportWidth="24" |
||||||
|
android:viewportHeight="24"> |
||||||
|
<path |
||||||
|
android:pathData="M20,6.5a3,3 0,0 1,2.59 -3A0.5,0.5 0,0 0,23 3V2.5a0.5,0.5 0,0 0,-0.5 -0.5H5.69A4.63,4.63 0,0 0,1 6.06,4.51 4.51,0 0,0 5.5,11h17a0.5,0.5 0,0 0,0.5 -0.5V10a0.5,0.5 0,0 0,-0.41 -0.5A3,3 0,0 1,20 6.5Z" |
||||||
|
android:fillColor="#2f45a6" /> |
||||||
|
<path |
||||||
|
android:pathData="M4,17.5a3,3 0,0 1,-2.59 3A0.5,0.5 0,0 0,1 21v0.53a0.5,0.5 0,0 0,0.5 0.5H18.31A4.63,4.63 0,0 0,23 17.94,4.51 4.51,0 0,0 18.5,13H1.5a0.5,0.5 0,0 0,-0.5 0.5V14a0.5,0.5 0,0 0,0.41 0.5A3,3 0,0 1,4 17.5Z" |
||||||
|
android:fillColor="#2f45a6" /> |
||||||
|
</vector> |
@ -0,0 +1,5 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android"> |
||||||
|
<item android:drawable="@drawable/ic_bottom_explore_e" android:state_checked="false" /> |
||||||
|
<item android:drawable="@drawable/ic_bottom_explore_s" android:state_checked="true" /> |
||||||
|
</selector> |
@ -0,0 +1,12 @@ |
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:width="24dp" |
||||||
|
android:height="24dp" |
||||||
|
android:viewportWidth="24" |
||||||
|
android:viewportHeight="24"> |
||||||
|
<path |
||||||
|
android:pathData="M12,2.5A9.5,9.5 0,1 1,2.5 12,9.51 9.51,0 0,1 12,2.5M12,1A11,11 0,1 0,23 12,11 11,0 0,0 12,1Z" |
||||||
|
android:fillColor="#2f45a6" /> |
||||||
|
<path |
||||||
|
android:pathData="M13.93,10.07l-1.29,2.57 -2.57,1.29 1.29,-2.57 2.57,-1.29M16.85,7a0.18,0.18 0,0 0,-0.1 0l-6.51,3.26L7,16.75a0.2,0.2 0,0 0,0.17 0.29,0.18 0.18,0 0,0 0.1,0l6.51,-3.26L17,7.25A0.2,0.2 0,0 0,16.85 7Z" |
||||||
|
android:fillColor="#2f45a6" /> |
||||||
|
</vector> |
@ -0,0 +1,9 @@ |
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:width="24dp" |
||||||
|
android:height="24dp" |
||||||
|
android:viewportWidth="24" |
||||||
|
android:viewportHeight="24"> |
||||||
|
<path |
||||||
|
android:pathData="M12,1A11,11 0,1 0,23 12,11 11,0 0,0 12,1ZM17,7.25 L13.74,13.76L7.25,17A0.2,0.2 0,0 1,7 16.75l3.26,-6.51L16.75,7A0.2,0.2 0,0 1,17 7.25Z" |
||||||
|
android:fillColor="#2f45a6" /> |
||||||
|
</vector> |
@ -0,0 +1,5 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android"> |
||||||
|
<item android:drawable="@drawable/ic_bottom_person_e" android:state_checked="false" /> |
||||||
|
<item android:drawable="@drawable/ic_bottom_person_s" android:state_checked="true" /> |
||||||
|
</selector> |
@ -0,0 +1,12 @@ |
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:width="24dp" |
||||||
|
android:height="24dp" |
||||||
|
android:viewportWidth="24" |
||||||
|
android:viewportHeight="24"> |
||||||
|
<path |
||||||
|
android:pathData="M12,2.5A4.5,4.5 0,1 1,7.5 7,4.51 4.51,0 0,1 12,2.5M12,1a6,6 0,1 0,6 6,6 6,0 0,0 -6,-6Z" |
||||||
|
android:fillColor="#2f45a6" /> |
||||||
|
<path |
||||||
|
android:pathData="M3.5,21A4.49,4.49 0,0 1,8 16.5h8A4.49,4.49 0,0 1,20.5 21v2H21a1,1 0,0 0,1 -1V21a6,6 0,0 0,-6 -6H8a6,6 0,0 0,-6 6v1a1,1 0,0 0,1 1h0.5Z" |
||||||
|
android:fillColor="#2f45a6" /> |
||||||
|
</vector> |
@ -0,0 +1,12 @@ |
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:width="24dp" |
||||||
|
android:height="24dp" |
||||||
|
android:viewportWidth="24" |
||||||
|
android:viewportHeight="24"> |
||||||
|
<path |
||||||
|
android:pathData="M12,7m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0" |
||||||
|
android:fillColor="#2f45a6" /> |
||||||
|
<path |
||||||
|
android:pathData="M8,15h8a6,6 0,0 1,6 6v1a1,1 0,0 1,-1 1H3a1,1 0,0 1,-1 -1V21A6,6 0,0 1,8 15Z" |
||||||
|
android:fillColor="#2f45a6" /> |
||||||
|
</vector> |
@ -0,0 +1,5 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android"> |
||||||
|
<item android:drawable="@drawable/ic_bottom_rss_feed_e" android:state_checked="false" /> |
||||||
|
<item android:drawable="@drawable/ic_bottom_rss_feed_s" android:state_checked="true" /> |
||||||
|
</selector> |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue