commit
0c8182ea3a
@ -0,0 +1,25 @@ |
||||
# 书源管理界面帮助 |
||||
|
||||
* 书源右上角标志 |
||||
* 绿点表示书源有发现,且启用了发现 |
||||
* 红点表示书源有发现,但是未启用 |
||||
* 没有标志表示此书源没有发现 |
||||
* 右上角有分组菜单,可以按分组筛选书源 |
||||
* 右上角更多菜单里包含 |
||||
* 新建书源 |
||||
* 本地导入 |
||||
* 网络导入 |
||||
* 二维码导入 |
||||
* 分享选中书源 |
||||
* 选择书源的更多操作在右下角的菜单里面,操作都是针对选择的书源 |
||||
* 启用所选 |
||||
* 禁用所选 |
||||
* 添加分组 |
||||
* 移除分组 |
||||
* 启用发现 |
||||
* 禁用发现 |
||||
* 置顶所选 |
||||
* 置底所选 |
||||
* 导出所选 |
||||
* 校验所选 |
||||
* 校验失败的书源分组会加上"失效",选择"失效"分组即可批量操作 |
@ -0,0 +1,42 @@ |
||||
# 阅读界面帮助文档 |
||||
|
||||
1.阅读界面主菜单 |
||||
* 顶部操作 |
||||
* 章节名称:点击可编辑书源 |
||||
* 章节url:点击可打开浏览器浏览 |
||||
* 菜单:不同类型的书籍显示的菜单不同,详情查看菜单文字,长按菜单图标可显示文字 |
||||
* 中间左侧-亮度调节 |
||||
* 亮度调节的顶端有跟随系统亮度的开关,打开后亮度跟随系统,关闭后才可以调节亮度条 |
||||
* 底部操作 |
||||
* 4个圆形按钮依次为 全文搜索✧自动翻页✧替换净化✧切换夜间模式 |
||||
* 上一章✧下一章中间的进度条为页数进度,要快速跳转章节点击目录按钮进入目录快速跳转 |
||||
* 目录->目录和书签界面 |
||||
* 朗读->单击开始朗读,长按进入朗读设置界面 |
||||
* 界面->所有排版设置都在里面 |
||||
* 设置->其它一些设置,找不到的设置去这里看看,可滚动 |
||||
|
||||
2.朗读设置界面 |
||||
* 后台->进入后台朗读,可以做一些其它事 |
||||
* 设置->朗读引擎设置,可以切换本地TTS和在线朗读,在线朗读可自定义 |
||||
|
||||
3.排版设置界面 |
||||
* 白天模式和夜间模式背景不同布局相同 |
||||
* 共用布局->启用共用布局时所有背景使用同一布局,关闭共用布局则每个背景单独布局 |
||||
* 长按背景可进入文字颜色和背景设置界面 |
||||
|
||||
4.其它设置界面 |
||||
* 屏幕方向 |
||||
* 屏幕超时 |
||||
* 隐藏状态栏 |
||||
* 扩展到刘海 |
||||
* 隐藏导航栏 |
||||
* 文字两端对齐 |
||||
* 文字底部对齐 |
||||
* 音量键翻页 |
||||
* 点击翻页 |
||||
* 朗读时音量键翻页 |
||||
* 自动换源->书源被删除时自动切换到其它书源 |
||||
* 长按选择文本 |
||||
* 显示亮度调节控件 |
||||
* 点击区域设置 |
||||
* 自定义翻页按键 |
@ -1,4 +1,4 @@ |
||||
## 正则表达式学习 |
||||
# 正则表达式学习 |
||||
|
||||
- [基本匹配](#1-基本匹配) |
||||
- [元字符](#2-元字符) |
@ -0,0 +1,19 @@ |
||||
# WebDav备份教程 |
||||
|
||||
### 阅读支持云备份,采用WebDav协议,所有支持WebDav的云盘都可以,建议采用坚果云,每月免费1G流量,用来备份阅读足够了,下面就采用坚果云来讲解配置步骤. |
||||
|
||||
1. 打开坚果云网站 https://www.jianguoyun.com/d/home#/ |
||||
2. 如果没有注册过坚果云先注册一下 |
||||
3. 登录坚果云 |
||||
4. 右上角用户名点开点账户信息 |
||||
5. 点击安全选项 |
||||
6. 在第三方管理里添加应用 |
||||
7. 将应用示例里的服务器地址,用户名,和密码填到阅读的WebDav设置里 |
||||
8. 阅读的WebDav配置在我的-备份与恢复,创建子文件夹选项保持默认即可 |
||||
9. 设置完成后手动执行一下备份,看看是否成功 |
||||
10. 恢复时选择想要恢复的备份文件 |
||||
|
||||
### 自动备份说明 |
||||
|
||||
* 设置好备份之后每次退出App会自动进行备份 |
||||
* WebDav同一天的备份会覆盖,不同日期的备份不会覆盖 |
@ -0,0 +1,56 @@ |
||||
package io.legado.app.help |
||||
|
||||
import android.content.Context |
||||
import androidx.core.content.edit |
||||
import io.legado.app.App |
||||
|
||||
object LocalConfig { |
||||
|
||||
private val localConfig = |
||||
App.INSTANCE.getSharedPreferences("local", Context.MODE_PRIVATE) |
||||
|
||||
val isFirstOpenApp: Boolean |
||||
get() { |
||||
val value = localConfig.getBoolean("firstOpen", true) |
||||
if (value) { |
||||
localConfig.edit { putBoolean("firstOpen", false) } |
||||
} |
||||
return value |
||||
} |
||||
|
||||
val isFirstRead: Boolean |
||||
get() { |
||||
val value = localConfig.getBoolean("firstRead", true) |
||||
if (value) { |
||||
localConfig.edit { putBoolean("firstRead", false) } |
||||
} |
||||
return value |
||||
} |
||||
|
||||
val isFirstOpenBackup: Boolean |
||||
get() { |
||||
val value = localConfig.getBoolean("firstBackup", true) |
||||
if (value) { |
||||
localConfig.edit { putBoolean("firstBackup", false) } |
||||
} |
||||
return value |
||||
} |
||||
|
||||
val isFirstReadMenuShow: Boolean |
||||
get() { |
||||
val value = localConfig.getBoolean("firstReadMenu", true) |
||||
if (value) { |
||||
localConfig.edit { putBoolean("firstReadMenu", false) } |
||||
} |
||||
return value |
||||
} |
||||
|
||||
val isFirstOpenBookSources: Boolean |
||||
get() { |
||||
val value = localConfig.getBoolean("firstOpenBookSources", true) |
||||
if (value) { |
||||
localConfig.edit { putBoolean("firstOpenBookSources", false) } |
||||
} |
||||
return value |
||||
} |
||||
} |
@ -0,0 +1,156 @@ |
||||
package io.legado.app.ui.association |
||||
|
||||
import android.annotation.SuppressLint |
||||
import android.content.Context |
||||
import android.content.DialogInterface |
||||
import android.os.Bundle |
||||
import android.view.LayoutInflater |
||||
import android.view.MenuItem |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import androidx.appcompat.widget.Toolbar |
||||
import androidx.recyclerview.widget.LinearLayoutManager |
||||
import io.legado.app.R |
||||
import io.legado.app.base.BaseDialogFragment |
||||
import io.legado.app.base.adapter.ItemViewHolder |
||||
import io.legado.app.base.adapter.SimpleRecyclerAdapter |
||||
import io.legado.app.constant.PreferKey |
||||
import io.legado.app.data.entities.BookSource |
||||
import io.legado.app.help.AppConfig |
||||
import io.legado.app.lib.dialogs.alert |
||||
import io.legado.app.ui.widget.text.AutoCompleteTextView |
||||
import io.legado.app.utils.getViewModelOfActivity |
||||
import io.legado.app.utils.putPrefBoolean |
||||
import io.legado.app.utils.visible |
||||
import kotlinx.android.synthetic.main.dialog_edit_text.view.* |
||||
import kotlinx.android.synthetic.main.dialog_recycler_view.* |
||||
import kotlinx.android.synthetic.main.item_source_import.view.* |
||||
import org.jetbrains.anko.sdk27.listeners.onClick |
||||
|
||||
/** |
||||
* 导入书源弹出窗口 |
||||
*/ |
||||
class ImportBookSourceDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener { |
||||
|
||||
val viewModel: ImportBookSourceViewModel |
||||
get() = getViewModelOfActivity(ImportBookSourceViewModel::class.java) |
||||
lateinit var adapter: SourcesAdapter |
||||
|
||||
override fun onStart() { |
||||
super.onStart() |
||||
dialog?.window?.setLayout( |
||||
ViewGroup.LayoutParams.MATCH_PARENT, |
||||
ViewGroup.LayoutParams.WRAP_CONTENT |
||||
) |
||||
} |
||||
|
||||
override fun onCreateView( |
||||
inflater: LayoutInflater, |
||||
container: ViewGroup?, |
||||
savedInstanceState: Bundle? |
||||
): View? { |
||||
return inflater.inflate(R.layout.dialog_recycler_view, container) |
||||
} |
||||
|
||||
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { |
||||
tool_bar.setTitle(R.string.import_book_source) |
||||
initMenu() |
||||
adapter = SourcesAdapter(requireContext()) |
||||
recycler_view.layoutManager = LinearLayoutManager(requireContext()) |
||||
recycler_view.adapter = adapter |
||||
adapter.setItems(viewModel.allSources) |
||||
tv_cancel.visible() |
||||
tv_cancel.onClick { |
||||
dismiss() |
||||
} |
||||
tv_ok.visible() |
||||
tv_ok.onClick { |
||||
viewModel.importSelect { |
||||
dismiss() |
||||
} |
||||
} |
||||
} |
||||
|
||||
private fun initMenu() { |
||||
tool_bar.setOnMenuItemClickListener(this) |
||||
tool_bar.inflateMenu(R.menu.import_source) |
||||
tool_bar.menu.findItem(R.id.menu_Keep_original_name)?.isChecked = AppConfig.importKeepName |
||||
} |
||||
|
||||
@SuppressLint("InflateParams") |
||||
override fun onMenuItemClick(item: MenuItem): Boolean { |
||||
when (item.itemId) { |
||||
R.id.menu_new_group -> { |
||||
alert(R.string.diy_edit_source_group) { |
||||
var editText: AutoCompleteTextView? = null |
||||
customView { |
||||
layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { |
||||
editText = edit_view |
||||
} |
||||
} |
||||
okButton { |
||||
editText?.text?.toString()?.let { group -> |
||||
viewModel.groupName = group |
||||
item.title = getString(R.string.diy_edit_source_group_title, group) |
||||
} |
||||
} |
||||
noButton() |
||||
}.show() |
||||
} |
||||
R.id.menu_select_all -> { |
||||
viewModel.selectStatus.forEachIndexed { index, b -> |
||||
if (!b) { |
||||
viewModel.selectStatus[index] = true |
||||
} |
||||
} |
||||
adapter.notifyDataSetChanged() |
||||
} |
||||
R.id.menu_un_select_all -> { |
||||
viewModel.selectStatus.forEachIndexed { index, b -> |
||||
if (b) { |
||||
viewModel.selectStatus[index] = false |
||||
} |
||||
} |
||||
adapter.notifyDataSetChanged() |
||||
} |
||||
R.id.menu_Keep_original_name -> { |
||||
item.isChecked = !item.isChecked |
||||
putPrefBoolean(PreferKey.importKeepName, item.isChecked) |
||||
} |
||||
} |
||||
return false |
||||
} |
||||
|
||||
override fun onDismiss(dialog: DialogInterface) { |
||||
super.onDismiss(dialog) |
||||
activity?.finish() |
||||
} |
||||
|
||||
inner class SourcesAdapter(context: Context) : |
||||
SimpleRecyclerAdapter<BookSource>(context, R.layout.item_source_import) { |
||||
|
||||
override fun convert(holder: ItemViewHolder, item: BookSource, payloads: MutableList<Any>) { |
||||
holder.itemView.apply { |
||||
cb_source_name.isChecked = viewModel.selectStatus[holder.layoutPosition] |
||||
cb_source_name.text = item.bookSourceName |
||||
tv_source_state.text = if (viewModel.checkSources[holder.layoutPosition] != null) { |
||||
"已存在" |
||||
} else { |
||||
"新书源" |
||||
} |
||||
} |
||||
} |
||||
|
||||
override fun registerListener(holder: ItemViewHolder) { |
||||
holder.itemView.apply { |
||||
cb_source_name.setOnCheckedChangeListener { buttonView, isChecked -> |
||||
if (buttonView.isPressed) { |
||||
viewModel.selectStatus[holder.layoutPosition] = isChecked |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,155 @@ |
||||
package io.legado.app.ui.association |
||||
|
||||
import android.annotation.SuppressLint |
||||
import android.content.Context |
||||
import android.content.DialogInterface |
||||
import android.os.Bundle |
||||
import android.view.LayoutInflater |
||||
import android.view.MenuItem |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import androidx.appcompat.widget.Toolbar |
||||
import androidx.recyclerview.widget.LinearLayoutManager |
||||
import io.legado.app.R |
||||
import io.legado.app.base.BaseDialogFragment |
||||
import io.legado.app.base.adapter.ItemViewHolder |
||||
import io.legado.app.base.adapter.SimpleRecyclerAdapter |
||||
import io.legado.app.constant.PreferKey |
||||
import io.legado.app.data.entities.RssSource |
||||
import io.legado.app.help.AppConfig |
||||
import io.legado.app.lib.dialogs.alert |
||||
import io.legado.app.ui.widget.text.AutoCompleteTextView |
||||
import io.legado.app.utils.getViewModelOfActivity |
||||
import io.legado.app.utils.putPrefBoolean |
||||
import io.legado.app.utils.visible |
||||
import kotlinx.android.synthetic.main.dialog_edit_text.view.* |
||||
import kotlinx.android.synthetic.main.dialog_recycler_view.* |
||||
import kotlinx.android.synthetic.main.item_source_import.view.* |
||||
import org.jetbrains.anko.sdk27.listeners.onClick |
||||
|
||||
/** |
||||
* 导入rss源弹出窗口 |
||||
*/ |
||||
class ImportRssSourceDialog : BaseDialogFragment(), Toolbar.OnMenuItemClickListener { |
||||
|
||||
val viewModel: ImportRssSourceViewModel |
||||
get() = getViewModelOfActivity(ImportRssSourceViewModel::class.java) |
||||
lateinit var adapter: SourcesAdapter |
||||
|
||||
override fun onStart() { |
||||
super.onStart() |
||||
dialog?.window?.setLayout( |
||||
ViewGroup.LayoutParams.MATCH_PARENT, |
||||
ViewGroup.LayoutParams.WRAP_CONTENT |
||||
) |
||||
} |
||||
|
||||
override fun onCreateView( |
||||
inflater: LayoutInflater, |
||||
container: ViewGroup?, |
||||
savedInstanceState: Bundle? |
||||
): View? { |
||||
return inflater.inflate(R.layout.dialog_recycler_view, container) |
||||
} |
||||
|
||||
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { |
||||
tool_bar.setTitle(R.string.import_rss_source) |
||||
initMenu() |
||||
adapter = SourcesAdapter(requireContext()) |
||||
recycler_view.layoutManager = LinearLayoutManager(requireContext()) |
||||
recycler_view.adapter = adapter |
||||
adapter.setItems(viewModel.allSources) |
||||
tv_cancel.visible() |
||||
tv_cancel.onClick { |
||||
dismiss() |
||||
} |
||||
tv_ok.visible() |
||||
tv_ok.onClick { |
||||
viewModel.importSelect { |
||||
dismiss() |
||||
} |
||||
} |
||||
} |
||||
|
||||
private fun initMenu() { |
||||
tool_bar.setOnMenuItemClickListener(this) |
||||
tool_bar.inflateMenu(R.menu.import_source) |
||||
tool_bar.menu.findItem(R.id.menu_Keep_original_name)?.isChecked = AppConfig.importKeepName |
||||
} |
||||
|
||||
@SuppressLint("InflateParams") |
||||
override fun onMenuItemClick(item: MenuItem): Boolean { |
||||
when (item.itemId) { |
||||
R.id.menu_new_group -> { |
||||
alert(R.string.diy_edit_source_group) { |
||||
var editText: AutoCompleteTextView? = null |
||||
customView { |
||||
layoutInflater.inflate(R.layout.dialog_edit_text, null).apply { |
||||
editText = edit_view |
||||
} |
||||
} |
||||
okButton { |
||||
editText?.text?.toString()?.let { group -> |
||||
viewModel.groupName = group |
||||
item.title = getString(R.string.diy_edit_source_group_title, group) |
||||
} |
||||
} |
||||
noButton() |
||||
}.show() |
||||
} |
||||
R.id.menu_select_all -> { |
||||
viewModel.selectStatus.forEachIndexed { index, b -> |
||||
if (!b) { |
||||
viewModel.selectStatus[index] = true |
||||
} |
||||
} |
||||
adapter.notifyDataSetChanged() |
||||
} |
||||
R.id.menu_un_select_all -> { |
||||
viewModel.selectStatus.forEachIndexed { index, b -> |
||||
if (b) { |
||||
viewModel.selectStatus[index] = false |
||||
} |
||||
} |
||||
adapter.notifyDataSetChanged() |
||||
} |
||||
R.id.menu_Keep_original_name -> { |
||||
item.isChecked = !item.isChecked |
||||
putPrefBoolean(PreferKey.importKeepName, item.isChecked) |
||||
} |
||||
} |
||||
return false |
||||
} |
||||
|
||||
override fun onDismiss(dialog: DialogInterface) { |
||||
super.onDismiss(dialog) |
||||
activity?.finish() |
||||
} |
||||
|
||||
inner class SourcesAdapter(context: Context) : |
||||
SimpleRecyclerAdapter<RssSource>(context, R.layout.item_source_import) { |
||||
|
||||
override fun convert(holder: ItemViewHolder, item: RssSource, payloads: MutableList<Any>) { |
||||
holder.itemView.apply { |
||||
cb_source_name.isChecked = viewModel.selectStatus[holder.layoutPosition] |
||||
cb_source_name.text = item.sourceName |
||||
tv_source_state.text = if (viewModel.checkSources[holder.layoutPosition] != null) { |
||||
"已存在" |
||||
} else { |
||||
"新订阅源" |
||||
} |
||||
} |
||||
} |
||||
|
||||
override fun registerListener(holder: ItemViewHolder) { |
||||
holder.itemView.apply { |
||||
cb_source_name.setOnCheckedChangeListener { buttonView, isChecked -> |
||||
if (buttonView.isPressed) { |
||||
viewModel.selectStatus[holder.layoutPosition] = isChecked |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,132 @@ |
||||
package io.legado.app.ui.book.read.config |
||||
|
||||
import android.content.DialogInterface |
||||
import android.os.Bundle |
||||
import android.view.LayoutInflater |
||||
import android.view.View |
||||
import android.view.ViewGroup |
||||
import android.widget.TextView |
||||
import io.legado.app.R |
||||
import io.legado.app.base.BaseDialogFragment |
||||
import io.legado.app.constant.PreferKey |
||||
import io.legado.app.help.AppConfig |
||||
import io.legado.app.lib.dialogs.selector |
||||
import io.legado.app.ui.book.read.ReadBookActivity |
||||
import io.legado.app.utils.getCompatColor |
||||
import io.legado.app.utils.putPrefInt |
||||
import kotlinx.android.synthetic.main.dialog_click_action_config.* |
||||
import org.jetbrains.anko.sdk27.listeners.onClick |
||||
|
||||
class ClickActionConfigDialog : BaseDialogFragment() { |
||||
|
||||
private val actions = linkedMapOf<Int, String>() |
||||
|
||||
override fun onStart() { |
||||
super.onStart() |
||||
(activity as ReadBookActivity).bottomDialog++ |
||||
dialog?.window?.let { |
||||
it.setBackgroundDrawableResource(R.color.transparent) |
||||
it.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) |
||||
} |
||||
} |
||||
|
||||
override fun onCreateView( |
||||
inflater: LayoutInflater, |
||||
container: ViewGroup?, |
||||
savedInstanceState: Bundle? |
||||
): View? { |
||||
return inflater.inflate(R.layout.dialog_click_action_config, container) |
||||
} |
||||
|
||||
override fun onDismiss(dialog: DialogInterface) { |
||||
super.onDismiss(dialog) |
||||
(activity as ReadBookActivity).bottomDialog-- |
||||
} |
||||
|
||||
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { |
||||
view.setBackgroundColor(getCompatColor(R.color.translucent)) |
||||
actions[-1] = getString(R.string.non_action) |
||||
actions[0] = getString(R.string.menu) |
||||
actions[1] = getString(R.string.next_page) |
||||
actions[2] = getString(R.string.prev_page) |
||||
actions[3] = getString(R.string.next_chapter) |
||||
actions[4] = getString(R.string.previous_chapter) |
||||
initData() |
||||
initViewEvent() |
||||
} |
||||
|
||||
private fun initData() = with(AppConfig) { |
||||
tv_top_left.text = actions[clickActionTopLeft] |
||||
tv_top_center.text = actions[clickActionTopCenter] |
||||
tv_top_right.text = actions[clickActionTopRight] |
||||
tv_middle_left.text = actions[clickActionMiddleLeft] |
||||
tv_middle_right.text = actions[clickActionMiddleRight] |
||||
tv_bottom_left.text = actions[clickActionBottomLeft] |
||||
tv_bottom_center.text = actions[clickActionBottomCenter] |
||||
tv_bottom_right.text = actions[clickActionBottomRight] |
||||
} |
||||
|
||||
private fun initViewEvent() { |
||||
iv_close.onClick { |
||||
dismiss() |
||||
} |
||||
tv_top_left.onClick { |
||||
selectAction { action -> |
||||
putPrefInt(PreferKey.clickActionTopLeft, action) |
||||
(it as? TextView)?.text = actions[action] |
||||
} |
||||
} |
||||
tv_top_center.onClick { |
||||
selectAction { action -> |
||||
putPrefInt(PreferKey.clickActionTopCenter, action) |
||||
(it as? TextView)?.text = actions[action] |
||||
} |
||||
} |
||||
tv_top_right.onClick { |
||||
selectAction { action -> |
||||
putPrefInt(PreferKey.clickActionTopRight, action) |
||||
(it as? TextView)?.text = actions[action] |
||||
} |
||||
} |
||||
tv_middle_left.onClick { |
||||
selectAction { action -> |
||||
putPrefInt(PreferKey.clickActionMiddleLeft, action) |
||||
(it as? TextView)?.text = actions[action] |
||||
} |
||||
} |
||||
tv_middle_right.onClick { |
||||
selectAction { action -> |
||||
putPrefInt(PreferKey.clickActionMiddleRight, action) |
||||
(it as? TextView)?.text = actions[action] |
||||
} |
||||
} |
||||
tv_bottom_left.onClick { |
||||
selectAction { action -> |
||||
putPrefInt(PreferKey.clickActionBottomLeft, action) |
||||
(it as? TextView)?.text = actions[action] |
||||
} |
||||
} |
||||
tv_bottom_center.onClick { |
||||
selectAction { action -> |
||||
putPrefInt(PreferKey.clickActionBottomCenter, action) |
||||
(it as? TextView)?.text = actions[action] |
||||
} |
||||
} |
||||
tv_bottom_right.onClick { |
||||
selectAction { action -> |
||||
putPrefInt(PreferKey.clickActionBottomRight, action) |
||||
(it as? TextView)?.text = actions[action] |
||||
} |
||||
} |
||||
} |
||||
|
||||
private fun selectAction(success: (action: Int) -> Unit) { |
||||
selector( |
||||
getString(R.string.select_action), |
||||
actions.values.toList() |
||||
) { _, index -> |
||||
success.invoke(actions.keys.toList()[index]) |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,6 @@ |
||||
package io.legado.app.ui.book.read.page.entities |
||||
|
||||
data class PageData( |
||||
val textPage: TextPage, |
||||
val textChapter: TextChapter? = null |
||||
) |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue