@ -0,0 +1,32 @@ | 
				
			||||
#更新fork | 
				
			||||
name: update fork | 
				
			||||
 | 
				
			||||
on:  | 
				
			||||
  schedule: | 
				
			||||
    - cron: '0 16 * * *' #设置定时任务 | 
				
			||||
 | 
				
			||||
jobs: | 
				
			||||
  build: | 
				
			||||
    runs-on: ubuntu-latest | 
				
			||||
    if: ${{ github.event.repository.owner.id == github.event.sender.id && github.actor != 'gedoor' }} | 
				
			||||
    steps: | 
				
			||||
    - name: Checkout | 
				
			||||
      uses: actions/checkout@v2 | 
				
			||||
      with: | 
				
			||||
        fetch-depth: 0 | 
				
			||||
    - name: Install git | 
				
			||||
      run: | | 
				
			||||
        sudo apt-get update | 
				
			||||
        sudo apt-get -y install git | 
				
			||||
    - name: Set env | 
				
			||||
      run: | | 
				
			||||
        git config --global user.email "github-actions@github.com" | 
				
			||||
        git config --global user.name "github-actions" | 
				
			||||
    - name: Update fork | 
				
			||||
      run: | | 
				
			||||
        git remote add upstream https://github.com/gedoor/legado.git | 
				
			||||
        git remote -v | 
				
			||||
        git fetch upstream | 
				
			||||
        git checkout master | 
				
			||||
        git merge upstream/master | 
				
			||||
        git push origin master | 
				
			||||
@ -0,0 +1,57 @@ | 
				
			||||
name: Android CI | 
				
			||||
 | 
				
			||||
on:  | 
				
			||||
  release: | 
				
			||||
    types: [published] | 
				
			||||
  push: | 
				
			||||
    branches:  | 
				
			||||
      - master | 
				
			||||
#    tags: | 
				
			||||
#      - '3.*' | 
				
			||||
#  pull_request: | 
				
			||||
#    branches: | 
				
			||||
#      - master | 
				
			||||
#  watch: | 
				
			||||
#    types: [started] | 
				
			||||
#  schedule: | 
				
			||||
#    - cron: '0 4 * * *' | 
				
			||||
 | 
				
			||||
jobs: | 
				
			||||
  build: | 
				
			||||
 | 
				
			||||
    runs-on: ubuntu-latest | 
				
			||||
 | 
				
			||||
    steps: | 
				
			||||
    - uses: actions/checkout@v2 | 
				
			||||
    - name: set up JDK 1.8 | 
				
			||||
      uses: actions/setup-java@v1 | 
				
			||||
      with: | 
				
			||||
        java-version: 1.8 | 
				
			||||
    - name: clear 18PlusList.txt | 
				
			||||
      run: | | 
				
			||||
        echo "清空18PlusList.txt" | 
				
			||||
        echo "">$GITHUB_WORKSPACE/app/src/main/assets/18PlusList.txt | 
				
			||||
    - name: release apk sign | 
				
			||||
      run: | | 
				
			||||
        echo "给apk增加签名" | 
				
			||||
        cp $GITHUB_WORKSPACE/.github/workflows/legado.jks $GITHUB_WORKSPACE/app/legado.jks | 
				
			||||
        sed '$a\RELEASE_STORE_FILE=./legado.jks'          $GITHUB_WORKSPACE/gradle.properties -i  | 
				
			||||
        sed '$a\RELEASE_KEY_ALIAS=legado'                 $GITHUB_WORKSPACE/gradle.properties -i | 
				
			||||
        sed '$a\RELEASE_STORE_PASSWORD=gedoor_legado'     $GITHUB_WORKSPACE/gradle.properties -i | 
				
			||||
        sed '$a\RELEASE_KEY_PASSWORD=gedoor_legado'       $GITHUB_WORKSPACE/gradle.properties -i | 
				
			||||
    - name: apk live together | 
				
			||||
      run: | | 
				
			||||
        echo "设置apk共存" | 
				
			||||
        sed "s/'.release'/'.releaseA'/" $GITHUB_WORKSPACE/app/build.gradle  -i | 
				
			||||
        sed 's/.release/.releaseA/'     $GITHUB_WORKSPACE/app/google-services.json -i | 
				
			||||
    - name: build with gradle | 
				
			||||
      run: | | 
				
			||||
        echo "开始进行release构建" | 
				
			||||
        chmod +x gradlew | 
				
			||||
        ./gradlew assembleAppRelease | 
				
			||||
    - name : upload apk | 
				
			||||
      uses: actions/upload-artifact@master | 
				
			||||
      if: always() | 
				
			||||
      with: | 
				
			||||
        name: legado apk | 
				
			||||
        path: ${{ github.workspace }}/app/build/outputs/apk/app/release | 
				
			||||
@ -0,0 +1,169 @@ | 
				
			||||
# 阅读API | 
				
			||||
## 对于Web的配置 | 
				
			||||
您需要先在设置中启用"Web 服务"。   | 
				
			||||
## 使用 | 
				
			||||
### Web | 
				
			||||
以下说明假设您的操作在本机进行,且开放端口为1234。   | 
				
			||||
如果您要从远程计算机访问[阅读](),请将`127.0.0.1`替换成手机IP。 | 
				
			||||
#### 插入单个书源 | 
				
			||||
``` | 
				
			||||
URL = http://127.0.0.1:1234/saveSource | 
				
			||||
Method = POST | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
请求BODY内容为`JSON`字符串,   | 
				
			||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt) | 
				
			||||
 | 
				
			||||
#### 插入多个书源 | 
				
			||||
``` | 
				
			||||
URL = http://127.0.0.1:1234/saveSources | 
				
			||||
Method = POST | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
请求BODY内容为`JSON`字符串,   | 
				
			||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt),**为数组格式**。 | 
				
			||||
 | 
				
			||||
#### 获取书源 | 
				
			||||
``` | 
				
			||||
URL = http://127.0.0.1:1234/getSource?url=xxx | 
				
			||||
Method = GET | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
获取指定URL对应的书源信息。   | 
				
			||||
 | 
				
			||||
#### 获取所有书源 | 
				
			||||
``` | 
				
			||||
URL = http://127.0.0.1:1234/getSources | 
				
			||||
Method = GET | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
获取APP内的所有书源。   | 
				
			||||
 | 
				
			||||
#### 删除多个书源 | 
				
			||||
``` | 
				
			||||
URL = http://127.0.0.1:1234/deleteSources | 
				
			||||
Method = POST | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
请求BODY内容为`JSON`字符串,   | 
				
			||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt),**为数组格式**。 | 
				
			||||
 | 
				
			||||
#### 插入书籍 | 
				
			||||
``` | 
				
			||||
URL = http://127.0.0.1:1234/saveBook | 
				
			||||
Method = POST | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
请求BODY内容为`JSON`字符串,   | 
				
			||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/Book.kt)。 | 
				
			||||
 | 
				
			||||
#### 获取所有书籍 | 
				
			||||
``` | 
				
			||||
URL = http://127.0.0.1:1234/getBookshelf | 
				
			||||
Method = GET | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
获取APP内的所有书籍。   | 
				
			||||
 | 
				
			||||
#### 获取书籍章节列表 | 
				
			||||
``` | 
				
			||||
URL = http://127.0.0.1:1234/getChapterList?url=xxx | 
				
			||||
Method = GET | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
获取指定图书的章节列表。    | 
				
			||||
 | 
				
			||||
#### 获取书籍内容 | 
				
			||||
 | 
				
			||||
``` | 
				
			||||
URL = http://127.0.0.1:1234/getBookContent?url=xxx&index=1 | 
				
			||||
Method = GET | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
获取指定图书的第`index`章节的文本内容。      | 
				
			||||
 | 
				
			||||
### Content Provider | 
				
			||||
* 需声明`io.legado.READ_WRITE`权限 | 
				
			||||
* `providerHost`为`包名.readerProvider`, 如`io.legado.app.release.readerProvider`,不同包的地址不同,防止冲突安装失败 | 
				
			||||
* 以下出现的`providerHost`请自行替换 | 
				
			||||
#### 插入单个书源 | 
				
			||||
``` | 
				
			||||
URL = content://providerHost/source/insert | 
				
			||||
Method = insert | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
创建`Key="json"`的`ContentValues`,内容为`JSON`字符串,   | 
				
			||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt) | 
				
			||||
 | 
				
			||||
#### 插入多个书源 | 
				
			||||
``` | 
				
			||||
URL = content://providerHost/sources/insert | 
				
			||||
Method = insert | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
创建`Key="json"`的`ContentValues`,内容为`JSON`字符串,   | 
				
			||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt),**为数组格式**。 | 
				
			||||
 | 
				
			||||
#### 获取书源 | 
				
			||||
``` | 
				
			||||
URL = content://providerHost/source/query?url=xxx | 
				
			||||
Method = query | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
获取指定URL对应的书源信息。   | 
				
			||||
用`Cursor.getString(0)`取出返回结果。 | 
				
			||||
 | 
				
			||||
#### 获取所有书源 | 
				
			||||
``` | 
				
			||||
URL = content://providerHost/sources/query | 
				
			||||
Method = query | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
获取APP内的所有书源。   | 
				
			||||
用`Cursor.getString(0)`取出返回结果。 | 
				
			||||
 | 
				
			||||
#### 删除多个书源 | 
				
			||||
``` | 
				
			||||
URL = content://providerHost/sources/delete | 
				
			||||
Method = delete | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
创建`Key="json"`的`ContentValues`,内容为`JSON`字符串,   | 
				
			||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt),**为数组格式**。 | 
				
			||||
 | 
				
			||||
#### 插入书籍 | 
				
			||||
``` | 
				
			||||
URL = content://providerHost/book/insert | 
				
			||||
Method = insert | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
创建`Key="json"`的`ContentValues`,内容为`JSON`字符串,   | 
				
			||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/Book.kt)。 | 
				
			||||
 | 
				
			||||
#### 获取所有书籍 | 
				
			||||
``` | 
				
			||||
URL = content://providerHost/books/query | 
				
			||||
Method = query | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
获取APP内的所有书籍。   | 
				
			||||
用`Cursor.getString(0)`取出返回结果。 | 
				
			||||
 | 
				
			||||
#### 获取书籍章节列表 | 
				
			||||
``` | 
				
			||||
URL = content://providerHost/book/chapter/query?url=xxx | 
				
			||||
Method = query | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
获取指定图书的章节列表。    | 
				
			||||
用`Cursor.getString(0)`取出返回结果。 | 
				
			||||
 | 
				
			||||
#### 获取书籍内容 | 
				
			||||
 | 
				
			||||
``` | 
				
			||||
URL = content://providerHost/book/content/query?url=xxx&index=1 | 
				
			||||
Method = query | 
				
			||||
``` | 
				
			||||
 | 
				
			||||
获取指定图书的第`index`章节的文本内容。      | 
				
			||||
用`Cursor.getString(0)`取出返回结果。 | 
				
			||||
@ -0,0 +1,5 @@ | 
				
			||||
<?xml version="1.0" encoding="utf-8"?> | 
				
			||||
<resources> | 
				
			||||
    <string name="app_name">閲讀.D</string> | 
				
			||||
    <string name="receiving_shared_label">閲讀·D·搜索</string> | 
				
			||||
</resources> | 
				
			||||
@ -0,0 +1,5 @@ | 
				
			||||
<?xml version="1.0" encoding="utf-8"?> | 
				
			||||
<resources> | 
				
			||||
    <string name="app_name">閲讀.D</string> | 
				
			||||
    <string name="receiving_shared_label">閲讀·D·搜索</string> | 
				
			||||
</resources> | 
				
			||||
@ -0,0 +1,4 @@ | 
				
			||||
<resources> | 
				
			||||
    <string name="app_name">阅读·D</string> | 
				
			||||
    <string name="receiving_shared_label">阅读·D·搜索</string> | 
				
			||||
</resources> | 
				
			||||
@ -1,4 +1,4 @@ | 
				
			||||
<resources> | 
				
			||||
    <string name="app_name">悦读.debug</string> | 
				
			||||
    <string name="receiving_shared_label">悦读.debug·搜索</string> | 
				
			||||
    <string name="app_name">legado·D</string> | 
				
			||||
    <string name="receiving_shared_label">legado·D·search</string> | 
				
			||||
</resources> | 
				
			||||
@ -0,0 +1,6 @@ | 
				
			||||
<?xml version="1.0" encoding="utf-8"?> | 
				
			||||
<resources> | 
				
			||||
 | 
				
			||||
    <string name="app_name">阅读Pro</string> | 
				
			||||
 | 
				
			||||
</resources> | 
				
			||||
@ -0,0 +1,6 @@ | 
				
			||||
<?xml version="1.0" encoding="utf-8"?> | 
				
			||||
<resources> | 
				
			||||
 | 
				
			||||
    <string name="app_name">閱讀Pro</string> | 
				
			||||
 | 
				
			||||
</resources> | 
				
			||||
@ -0,0 +1,6 @@ | 
				
			||||
<?xml version="1.0" encoding="utf-8"?> | 
				
			||||
<resources> | 
				
			||||
 | 
				
			||||
    <string name="app_name">legadoPro</string> | 
				
			||||
 | 
				
			||||
</resources> | 
				
			||||
@ -0,0 +1,82 @@ | 
				
			||||
OGN5dS5jb20= | 
				
			||||
c2cwMC54eXo= | 
				
			||||
aXRyYWZmaWNuZXQuY29t | 
				
			||||
eGlhb3FpYW5nNTIw | 
				
			||||
MTIzeGlhb3FpYW5n | 
				
			||||
eGlhb3FpYW5neHM= | 
				
			||||
eGlhb3FpYW5nNTIw | 
				
			||||
MzM1eHM= | 
				
			||||
eGN4czk= | 
				
			||||
eGN4czUyMA== | 
				
			||||
c2h1YmFvYW4= | 
				
			||||
c2h1YmFvd2FuZzEyMw== | 
				
			||||
c2h1YmFvYW4= | 
				
			||||
aGFpdGFuZzEyMw== | 
				
			||||
eXV6aGFpd3VsYQ== | 
				
			||||
cG8xOA== | 
				
			||||
Ymwtbm92ZWw= | 
				
			||||
NXRucw== | 
				
			||||
c2hhb3NodWdl | 
				
			||||
amluamlzaHV3dQ== | 
				
			||||
NDJ3Zw== | 
				
			||||
eWlxdXNodQ== | 
				
			||||
c2h1YmFvd2FuZzEyMw== | 
				
			||||
M2hlYmFv | 
				
			||||
MzNoZWJhbw== | 
				
			||||
bHVvcWl1enc= | 
				
			||||
bXlzaHVnZQ== | 
				
			||||
c3NzeHN3 | 
				
			||||
eWl0ZQ== | 
				
			||||
Y3Vpd2VpanV1 | 
				
			||||
Y3Vpd2VpanV4cw== | 
				
			||||
Y3Vpd2VpanV4 | 
				
			||||
eGlhb3FpYW5nd3g= | 
				
			||||
YXN6dw== | 
				
			||||
YXN6dzY= | 
				
			||||
c2FuaGFveHM= | 
				
			||||
ODdzaHV3dQ== | 
				
			||||
NDh3eA== | 
				
			||||
bG9uZ3Rlbmcy | 
				
			||||
NnF3eA== | 
				
			||||
bG9uZ3Rlbmd4cw== | 
				
			||||
aGF4ZHU= | 
				
			||||
M3R3eA== | 
				
			||||
aGF4d3g1 | 
				
			||||
NjZsZXdlbg== | 
				
			||||
eGJhbnpodQ== | 
				
			||||
aGR5cA== | 
				
			||||
ZHliejk= | 
				
			||||
ZGl5aWJhbnpodTk= | 
				
			||||
ZGl5aWJhbnpodQ== | 
				
			||||
ZGl5aWJhbnpodTc= | 
				
			||||
YnoyMjI= | 
				
			||||
d29kZWFwaTAwMQ== | 
				
			||||
dGFuZ3poZWthbg== | 
				
			||||
YmF4aWFueHM= | 
				
			||||
eGlhb3NodW9zaGVuemhhbg== | 
				
			||||
ZGFtb2tl | 
				
			||||
emh3ZW5wZw== | 
				
			||||
eXV6aGFpZ2U= | 
				
			||||
d21wOA== | 
				
			||||
OXhpYW53ZW4= | 
				
			||||
bmFucmVudmlw | 
				
			||||
cmV5b28= | 
				
			||||
eWZ4aWFvc2h1b2U= | 
				
			||||
c2Fuaml1enc= | 
				
			||||
N3Fpbmc3 | 
				
			||||
cWR4aWFvc2h1bw== | 
				
			||||
Y2hpbmVzZXpq | 
				
			||||
MzlzaHViYW8= | 
				
			||||
a3l4czU= | 
				
			||||
NTZtcw== | 
				
			||||
bml1c2hh | 
				
			||||
bWt4czY= | 
				
			||||
MjIyMjJ4cw== | 
				
			||||
OTVkdXNodQ== | 
				
			||||
YmFuemh1MjI= | 
				
			||||
d3JsdHh0 | 
				
			||||
dHVkb3V0eHQ= | 
				
			||||
cm5neHM= | 
				
			||||
OTl3ZW5rdQ== | 
				
			||||
bGFvc2lqaXhz | 
				
			||||
ZnVzaHV6aGFpMQ== | 
				
			||||
@ -0,0 +1,62 @@ | 
				
			||||
[ | 
				
			||||
  { | 
				
			||||
    "id": 1598233029304, | 
				
			||||
    "name": "度小美", | 
				
			||||
    "url": "http://tts.baidu.com/text2audio,{\n    \"method\": \"POST\",\n    \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=0&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "id": 1598233029305, | 
				
			||||
    "name": "度小宇", | 
				
			||||
    "url": "http://tts.baidu.com/text2audio,{\n    \"method\": \"POST\",\n    \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=1&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "id": 1598233029306, | 
				
			||||
    "name": "度逍遥", | 
				
			||||
    "url": "http://tts.baidu.com/text2audio,{\n    \"method\": \"POST\",\n    \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=3&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "id": 1598233029307, | 
				
			||||
    "name": "度丫丫", | 
				
			||||
    "url": "http://tts.baidu.com/text2audio,{\n    \"method\": \"POST\",\n    \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=4&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "id": 1598233029308, | 
				
			||||
    "name": "度小娇", | 
				
			||||
    "url": "http://tts.baidu.com/text2audio,{\n    \"method\": \"POST\",\n    \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=5&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "id": 1598233029309, | 
				
			||||
    "name": "度米朵", | 
				
			||||
    "url": "http://tts.baidu.com/text2audio,{\n    \"method\": \"POST\",\n    \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=103&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "id": 1598233029310, | 
				
			||||
    "name": "度博文", | 
				
			||||
    "url": "http://tts.baidu.com/text2audio,{\n    \"method\": \"POST\",\n    \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=106&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "id": 1598233029311, | 
				
			||||
    "name": "度小童", | 
				
			||||
    "url": "http://tts.baidu.com/text2audio,{\n    \"method\": \"POST\",\n    \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=110&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "id": 1598233029312, | 
				
			||||
    "name": "度小萌", | 
				
			||||
    "url": "http://tts.baidu.com/text2audio,{\n    \"method\": \"POST\",\n    \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=111&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "id": 1598233029313, | 
				
			||||
    "name": "百度骚男", | 
				
			||||
    "url": "http://tts.baidu.com/text2audio,{\n    \"method\": \"POST\",\n    \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=11&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "id": 1598233029314, | 
				
			||||
    "name": "百度评书", | 
				
			||||
    "url": "http://tts.baidu.com/text2audio,{\n    \"method\": \"POST\",\n    \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=6&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "id": 1598233029315, | 
				
			||||
    "name": "百度主持", | 
				
			||||
    "url": "http://tts.baidu.com/text2audio,{\n    \"method\": \"POST\",\n    \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=9&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" | 
				
			||||
  } | 
				
			||||
] | 
				
			||||
@ -0,0 +1,26 @@ | 
				
			||||
[ | 
				
			||||
  { | 
				
			||||
    "themeName": "典雅蓝", | 
				
			||||
    "isNightTheme": false, | 
				
			||||
    "primaryColor": "#03A9F4", | 
				
			||||
    "accentColor": "#AD1457", | 
				
			||||
    "backgroundColor": "#F5F5F5", | 
				
			||||
    "bottomBackground": "#EEEEEE" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "themeName": "黑白", | 
				
			||||
    "isNightTheme": true, | 
				
			||||
    "primaryColor": "#303030", | 
				
			||||
    "accentColor": "#E0E0E0", | 
				
			||||
    "backgroundColor": "#424242", | 
				
			||||
    "bottomBackground": "#424242" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "themeName": "A屏黑", | 
				
			||||
    "isNightTheme": true, | 
				
			||||
    "primaryColor": "#000000", | 
				
			||||
    "accentColor": "#FFFFFF", | 
				
			||||
    "backgroundColor": "#000000", | 
				
			||||
    "bottomBackground": "#000000" | 
				
			||||
  } | 
				
			||||
] | 
				
			||||
| 
		 After Width: | Height: | Size: 4.2 KiB  | 
| 
		 Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 9.2 KiB  | 
| 
		 Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB  | 
| 
		 Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB  | 
| 
		 Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB  | 
| 
		 Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB  | 
| 
		 Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB  | 
| 
		 Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB  | 
| 
		 Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB  | 
| 
		 Before Width: | Height: | Size: 799 B After Width: | Height: | Size: 799 B  | 
| 
		 Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB  | 
| 
		 Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB  | 
| 
		 Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB  | 
| 
		 Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB  | 
| 
		 Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB  | 
@ -0,0 +1,3 @@ | 
				
			||||
<!DOCTYPE html><html lang=en style="padding: 0;height:100%"><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><!--[if IE]><link rel="icon" href="favicon.ico" /><![endif]--><title>Legado Bookshelf</title><link href=css/about.dbe575e1.css rel=prefetch><link href=css/detail.9ba76c69.css rel=prefetch><link href=js/about.59a63964.js rel=prefetch><link href=js/about~detail.1caf6ef5.js rel=prefetch><link href=js/detail.11777eca.js rel=prefetch><link href=css/app.e4c919b7.css rel=preload as=style><link href=css/chunk-vendors.ad4ff18f.css rel=preload as=style><link href=js/app.d7843716.js rel=preload as=script><link href=js/chunk-vendors.8dd9045a.js rel=preload as=script><link href=css/chunk-vendors.ad4ff18f.css rel=stylesheet><link href=css/app.e4c919b7.css rel=stylesheet><link rel=icon type=image/png sizes=32x32 href=img/icons/favicon-32x32.png><link rel=icon type=image/png sizes=16x16 href=img/icons/favicon-16x16.png><link rel=manifest href=manifest.json><meta name=theme-color content=#4DBA87><meta name=apple-mobile-web-app-capable content=no><meta name=apple-mobile-web-app-status-bar-style content=default><meta name=apple-mobile-web-app-title content=yd-web-tool><link rel=apple-touch-icon href=img/icons/apple-touch-icon-152x152.png><link rel=mask-icon href=img/icons/safari-pinned-tab.svg color=#4DBA87><meta name=msapplication-TileImage content=img/icons/msapplication-icon-144x144.png><meta name=msapplication-TileColor content=#000000></head><style>body::-webkit-scrollbar { | 
				
			||||
      display: none; | 
				
			||||
    }</style><body style="margin: 0;height:100%"><noscript><strong>We're sorry but yd-web-tool doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=js/chunk-vendors.8dd9045a.js></script><script src=js/app.d7843716.js></script></body></html> | 
				
			||||
@ -0,0 +1,74 @@ | 
				
			||||
self.__precacheManifest = (self.__precacheManifest || []).concat([ | 
				
			||||
  { | 
				
			||||
    "revision": "a77097c019b699bc81ee", | 
				
			||||
    "url": "css/about.dbe575e1.css" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "revision": "4d729c4b428d537ebd8d", | 
				
			||||
    "url": "css/app.e4c919b7.css" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "revision": "3e91096748e0f4d6bb89", | 
				
			||||
    "url": "css/chunk-vendors.ad4ff18f.css" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "revision": "8f2124417070a994ebbd", | 
				
			||||
    "url": "css/detail.9ba76c69.css" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "revision": "535877f50039c0cb49a6196a5b7517cd", | 
				
			||||
    "url": "fonts/element-icons.535877f5.woff" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "revision": "732389ded34cb9c52dd88271f1345af9", | 
				
			||||
    "url": "fonts/element-icons.732389de.ttf" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "revision": "f9a3fb0e145017e166dd4d91d9280cc4", | 
				
			||||
    "url": "fonts/iconfont.f9a3fb0e.woff" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "revision": "f39ecc1a1d2a1eff3aca8aadd818bb61", | 
				
			||||
    "url": "fonts/popfont.f39ecc1a.ttf" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "revision": "6c094b6d4ae9404dbed273c41b06fae8", | 
				
			||||
    "url": "fonts/shelffont.6c094b6d.ttf" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "revision": "b5c48bc1e1fe73212a31be704875b71f", | 
				
			||||
    "url": "img/noCover.b5c48bc1.jpeg" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "revision": "ad9f43586bb9220e0df71ce8fad92d8b", | 
				
			||||
    "url": "index.html" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "revision": "a77097c019b699bc81ee", | 
				
			||||
    "url": "js/about.59a63964.js" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "revision": "2c81bd893f3a92f018d8", | 
				
			||||
    "url": "js/about~detail.1caf6ef5.js" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "revision": "4d729c4b428d537ebd8d", | 
				
			||||
    "url": "js/app.d7843716.js" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "revision": "3e91096748e0f4d6bb89", | 
				
			||||
    "url": "js/chunk-vendors.8dd9045a.js" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "revision": "8f2124417070a994ebbd", | 
				
			||||
    "url": "js/detail.11777eca.js" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "revision": "b46d04eb43bc31ca0f9f95121646440d", | 
				
			||||
    "url": "manifest.json" | 
				
			||||
  }, | 
				
			||||
  { | 
				
			||||
    "revision": "b6216d61c03e6ce0c9aea6ca7808f7ca", | 
				
			||||
    "url": "robots.txt" | 
				
			||||
  } | 
				
			||||
]); | 
				
			||||
@ -0,0 +1,2 @@ | 
				
			||||
User-agent: * | 
				
			||||
Disallow: | 
				
			||||
@ -0,0 +1,34 @@ | 
				
			||||
/** | 
				
			||||
 * Welcome to your Workbox-powered service worker! | 
				
			||||
 * | 
				
			||||
 * You'll need to register this file in your web app and you should | 
				
			||||
 * disable HTTP caching for this file too. | 
				
			||||
 * See https://goo.gl/nhQhGp
 | 
				
			||||
 * | 
				
			||||
 * The rest of the code is auto-generated. Please don't update this file | 
				
			||||
 * directly; instead, make changes to your Workbox build configuration | 
				
			||||
 * and re-run your build process. | 
				
			||||
 * See https://goo.gl/2aRDsh
 | 
				
			||||
 */ | 
				
			||||
 | 
				
			||||
importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js"); | 
				
			||||
 | 
				
			||||
importScripts( | 
				
			||||
  "precache-manifest.78eb8adcb8f052b2a72d462abe0dc498.js" | 
				
			||||
); | 
				
			||||
 | 
				
			||||
workbox.core.setCacheNameDetails({prefix: "yd-web-tool"}); | 
				
			||||
 | 
				
			||||
self.addEventListener('message', (event) => { | 
				
			||||
  if (event.data && event.data.type === 'SKIP_WAITING') { | 
				
			||||
    self.skipWaiting(); | 
				
			||||
  } | 
				
			||||
}); | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * The workboxSW.precacheAndRoute() method efficiently caches and responds to | 
				
			||||
 * requests for URLs in the manifest. | 
				
			||||
 * See https://goo.gl/S9QRab
 | 
				
			||||
 */ | 
				
			||||
self.__precacheManifest = [].concat(self.__precacheManifest || []); | 
				
			||||
workbox.precaching.precacheAndRoute(self.__precacheManifest, {}); | 
				
			||||
@ -0,0 +1,207 @@ | 
				
			||||
/* | 
				
			||||
 * Copyright (C) 2020 w568w | 
				
			||||
 */ | 
				
			||||
package io.legado.app.api | 
				
			||||
 | 
				
			||||
import android.content.ContentProvider | 
				
			||||
import android.content.ContentResolver | 
				
			||||
import android.content.ContentValues | 
				
			||||
import android.content.UriMatcher | 
				
			||||
import android.database.CharArrayBuffer | 
				
			||||
import android.database.ContentObserver | 
				
			||||
import android.database.Cursor | 
				
			||||
import android.database.DataSetObserver | 
				
			||||
import android.net.Uri | 
				
			||||
import android.os.Bundle | 
				
			||||
import com.google.gson.Gson | 
				
			||||
import io.legado.app.web.controller.BookshelfController | 
				
			||||
import io.legado.app.web.controller.SourceController | 
				
			||||
import io.legado.app.web.utils.ReturnData | 
				
			||||
import java.util.* | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * Export book data to other app. | 
				
			||||
 */ | 
				
			||||
class ReaderProvider : ContentProvider() { | 
				
			||||
    private enum class RequestCode { | 
				
			||||
        SaveSource, SaveSources, SaveBook, DeleteSources, GetSource, GetSources, GetBookshelf, GetChapterList, GetBookContent | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    private val postBodyKey = "json" | 
				
			||||
    private val sMatcher by lazy { | 
				
			||||
        UriMatcher(UriMatcher.NO_MATCH).apply { | 
				
			||||
            "${context?.applicationInfo?.packageName}.readerProvider".also { authority -> | 
				
			||||
                addURI(authority, "source/insert", RequestCode.SaveSource.ordinal) | 
				
			||||
                addURI(authority, "sources/insert", RequestCode.SaveSources.ordinal) | 
				
			||||
                addURI(authority, "book/insert", RequestCode.SaveBook.ordinal) | 
				
			||||
                addURI(authority, "sources/delete", RequestCode.DeleteSources.ordinal) | 
				
			||||
                addURI(authority, "source/query", RequestCode.GetSource.ordinal) | 
				
			||||
                addURI(authority, "sources/query", RequestCode.GetSources.ordinal) | 
				
			||||
                addURI(authority, "books/query", RequestCode.GetBookshelf.ordinal) | 
				
			||||
                addURI(authority, "book/chapter/query", RequestCode.GetChapterList.ordinal) | 
				
			||||
                addURI(authority, "book/content/query", RequestCode.GetBookContent.ordinal) | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    override fun onCreate() = false | 
				
			||||
 | 
				
			||||
    override fun delete( | 
				
			||||
        uri: Uri, | 
				
			||||
        selection: String?, | 
				
			||||
        selectionArgs: Array<String>? | 
				
			||||
    ): Int { | 
				
			||||
        if (sMatcher.match(uri) < 0) return -1 | 
				
			||||
        when (RequestCode.values()[sMatcher.match(uri)]) { | 
				
			||||
            RequestCode.DeleteSources -> SourceController.deleteSources(selection) | 
				
			||||
            else -> throw IllegalStateException( | 
				
			||||
                "Unexpected value: " + RequestCode.values()[sMatcher.match(uri)].name | 
				
			||||
            ) | 
				
			||||
        } | 
				
			||||
        return 0 | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    override fun getType(uri: Uri) = throw UnsupportedOperationException("Not yet implemented") | 
				
			||||
 | 
				
			||||
    override fun insert(uri: Uri, values: ContentValues?): Uri? { | 
				
			||||
        if (sMatcher.match(uri) < 0) return null | 
				
			||||
        when (RequestCode.values()[sMatcher.match(uri)]) { | 
				
			||||
            RequestCode.SaveSource -> values?.let { | 
				
			||||
                SourceController.saveSource(values.getAsString(postBodyKey)) | 
				
			||||
            } | 
				
			||||
            RequestCode.SaveBook -> values?.let { | 
				
			||||
                BookshelfController.saveBook(values.getAsString(postBodyKey)) | 
				
			||||
            } | 
				
			||||
            RequestCode.SaveSources -> values?.let { | 
				
			||||
                SourceController.saveSources(values.getAsString(postBodyKey)) | 
				
			||||
            } | 
				
			||||
            else -> throw IllegalStateException( | 
				
			||||
                "Unexpected value: " + RequestCode.values()[sMatcher.match(uri)].name | 
				
			||||
            ) | 
				
			||||
        } | 
				
			||||
        return null | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    override fun query( | 
				
			||||
        uri: Uri, projection: Array<String>?, selection: String?, | 
				
			||||
        selectionArgs: Array<String>?, sortOrder: String? | 
				
			||||
    ): Cursor? { | 
				
			||||
        val map: MutableMap<String, ArrayList<String>> = HashMap() | 
				
			||||
        uri.getQueryParameter("url")?.let { | 
				
			||||
            map["url"] = arrayListOf(it) | 
				
			||||
        } | 
				
			||||
        uri.getQueryParameter("index")?.let { | 
				
			||||
            map["index"] = arrayListOf(it) | 
				
			||||
        } | 
				
			||||
        return if (sMatcher.match(uri) < 0) null else when (RequestCode.values()[sMatcher.match(uri)]) { | 
				
			||||
            RequestCode.GetSource -> SimpleCursor(SourceController.getSource(map)) | 
				
			||||
            RequestCode.GetSources -> SimpleCursor(SourceController.sources) | 
				
			||||
            RequestCode.GetBookshelf -> SimpleCursor(BookshelfController.bookshelf) | 
				
			||||
            RequestCode.GetBookContent -> SimpleCursor(BookshelfController.getBookContent(map)) | 
				
			||||
            RequestCode.GetChapterList -> SimpleCursor(BookshelfController.getChapterList(map)) | 
				
			||||
            else -> throw IllegalStateException( | 
				
			||||
                "Unexpected value: " + RequestCode.values()[sMatcher.match(uri)].name | 
				
			||||
            ) | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    override fun update( | 
				
			||||
        uri: Uri, values: ContentValues?, selection: String?, | 
				
			||||
        selectionArgs: Array<String>? | 
				
			||||
    ) = throw UnsupportedOperationException("Not yet implemented") | 
				
			||||
     | 
				
			||||
 | 
				
			||||
    /** | 
				
			||||
     * Simple inner class to deliver json callback data. | 
				
			||||
     * | 
				
			||||
     * Only getString() makes sense. | 
				
			||||
     */ | 
				
			||||
    private class SimpleCursor(data: ReturnData?) : Cursor { | 
				
			||||
 | 
				
			||||
        private val mData: String = Gson().toJson(data) | 
				
			||||
 | 
				
			||||
        override fun getCount() = 1 | 
				
			||||
 | 
				
			||||
        override fun getPosition() = 0 | 
				
			||||
 | 
				
			||||
        override fun move(i: Int) = true | 
				
			||||
 | 
				
			||||
        override fun moveToPosition(i: Int) = true | 
				
			||||
 | 
				
			||||
        override fun moveToFirst() = true | 
				
			||||
 | 
				
			||||
        override fun moveToLast() = true | 
				
			||||
 | 
				
			||||
        override fun moveToNext() = true | 
				
			||||
 | 
				
			||||
        override fun moveToPrevious() = true | 
				
			||||
 | 
				
			||||
        override fun isFirst() = true | 
				
			||||
 | 
				
			||||
        override fun isLast() = true | 
				
			||||
 | 
				
			||||
        override fun isBeforeFirst() = true | 
				
			||||
 | 
				
			||||
        override fun isAfterLast() = true | 
				
			||||
 | 
				
			||||
        override fun getColumnIndex(s: String) = 0 | 
				
			||||
 | 
				
			||||
        @Throws(IllegalArgumentException::class) | 
				
			||||
        override fun getColumnIndexOrThrow(s: String): Int { | 
				
			||||
            throw UnsupportedOperationException("Not yet implemented") | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        override fun getColumnName(i: Int) = null as String? | 
				
			||||
 | 
				
			||||
        override fun getColumnNames() = arrayOf<String>() | 
				
			||||
 | 
				
			||||
        override fun getColumnCount() = 0 | 
				
			||||
 | 
				
			||||
        override fun getBlob(i: Int) = ByteArray(0) | 
				
			||||
 | 
				
			||||
        override fun getString(i: Int) = mData | 
				
			||||
 | 
				
			||||
        override fun copyStringToBuffer( | 
				
			||||
            i: Int, | 
				
			||||
            charArrayBuffer: CharArrayBuffer | 
				
			||||
        ) { | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        override fun getShort(i: Int) = 0.toShort() | 
				
			||||
         | 
				
			||||
 | 
				
			||||
        override fun getInt(i: Int) = 0 | 
				
			||||
 | 
				
			||||
        override fun getLong(i: Int) = 0L | 
				
			||||
 | 
				
			||||
        override fun getFloat(i: Int) = 0F | 
				
			||||
 | 
				
			||||
        override fun getDouble(i: Int) = 0.toDouble() | 
				
			||||
 | 
				
			||||
        override fun getType(i: Int) = 0 | 
				
			||||
 | 
				
			||||
        override fun isNull(i: Int) = false | 
				
			||||
 | 
				
			||||
        override fun deactivate() {} | 
				
			||||
        override fun requery() = false | 
				
			||||
 | 
				
			||||
        override fun close() {} | 
				
			||||
        override fun isClosed() = false | 
				
			||||
 | 
				
			||||
        override fun registerContentObserver(contentObserver: ContentObserver) {} | 
				
			||||
        override fun unregisterContentObserver(contentObserver: ContentObserver) {} | 
				
			||||
        override fun registerDataSetObserver(dataSetObserver: DataSetObserver) {} | 
				
			||||
        override fun unregisterDataSetObserver(dataSetObserver: DataSetObserver) {} | 
				
			||||
        override fun setNotificationUri(contentResolver: ContentResolver, uri: Uri) {} | 
				
			||||
 | 
				
			||||
        override fun getNotificationUri() = null as Uri? | 
				
			||||
 | 
				
			||||
        override fun getWantsAllOnMoveCalls() = false | 
				
			||||
 | 
				
			||||
        override fun setExtras(bundle: Bundle) {} | 
				
			||||
        override fun getExtras() = null as Bundle? | 
				
			||||
         | 
				
			||||
        override fun respond(bundle: Bundle) = null as Bundle? | 
				
			||||
 | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,61 @@ | 
				
			||||
package io.legado.app.base | 
				
			||||
 | 
				
			||||
import android.annotation.SuppressLint | 
				
			||||
import androidx.fragment.app.DialogFragment | 
				
			||||
import androidx.preference.* | 
				
			||||
import io.legado.app.ui.widget.prefs.EditTextPreferenceDialog | 
				
			||||
import io.legado.app.ui.widget.prefs.ListPreferenceDialog | 
				
			||||
import io.legado.app.ui.widget.prefs.MultiSelectListPreferenceDialog | 
				
			||||
 | 
				
			||||
abstract class BasePreferenceFragment : PreferenceFragmentCompat() { | 
				
			||||
 | 
				
			||||
    private val dialogFragmentTag = "androidx.preference.PreferenceFragment.DIALOG" | 
				
			||||
 | 
				
			||||
    @SuppressLint("RestrictedApi") | 
				
			||||
    override fun onDisplayPreferenceDialog(preference: Preference) { | 
				
			||||
 | 
				
			||||
        var handled = false | 
				
			||||
        if (callbackFragment is OnPreferenceDisplayDialogCallback) { | 
				
			||||
            handled = | 
				
			||||
                (callbackFragment as OnPreferenceDisplayDialogCallback) | 
				
			||||
                    .onPreferenceDisplayDialog(this, preference) | 
				
			||||
        } | 
				
			||||
        if (!handled && activity is OnPreferenceDisplayDialogCallback) { | 
				
			||||
            handled = (activity as OnPreferenceDisplayDialogCallback) | 
				
			||||
                .onPreferenceDisplayDialog(this, preference) | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        if (handled) { | 
				
			||||
            return | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        // check if dialog is already showing | 
				
			||||
        if (parentFragmentManager.findFragmentByTag(dialogFragmentTag) != null) { | 
				
			||||
            return | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        val f: DialogFragment = when (preference) { | 
				
			||||
            is EditTextPreference -> { | 
				
			||||
                EditTextPreferenceDialog.newInstance(preference.getKey()) | 
				
			||||
            } | 
				
			||||
            is ListPreference -> { | 
				
			||||
                ListPreferenceDialog.newInstance(preference.getKey()) | 
				
			||||
            } | 
				
			||||
            is MultiSelectListPreference -> { | 
				
			||||
                MultiSelectListPreferenceDialog.newInstance(preference.getKey()) | 
				
			||||
            } | 
				
			||||
            else -> { | 
				
			||||
                throw IllegalArgumentException( | 
				
			||||
                    "Cannot display dialog for an unknown Preference type: " | 
				
			||||
                            + preference.javaClass.simpleName | 
				
			||||
                            + ". Make sure to implement onPreferenceDisplayDialog() to handle " | 
				
			||||
                            + "displaying a custom dialog for this Preference." | 
				
			||||
                ) | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
        f.setTargetFragment(this, 0) | 
				
			||||
        f.show(parentFragmentManager, dialogFragmentTag) | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -1,15 +1,19 @@ | 
				
			||||
package io.legado.app.constant | 
				
			||||
 | 
				
			||||
import io.legado.app.help.AppConfig | 
				
			||||
import io.legado.app.utils.ColorUtils | 
				
			||||
 | 
				
			||||
enum class Theme { | 
				
			||||
    Dark, Light, Auto; | 
				
			||||
    Dark, Light, Auto, Transparent; | 
				
			||||
 | 
				
			||||
    companion object { | 
				
			||||
        fun getTheme(): Theme { | 
				
			||||
            return if (AppConfig.isNightTheme) { | 
				
			||||
                Dark | 
				
			||||
            } else Light | 
				
			||||
        } | 
				
			||||
        fun getTheme() = | 
				
			||||
            if (AppConfig.isNightTheme) Dark | 
				
			||||
            else Light | 
				
			||||
 | 
				
			||||
        fun getTheme(backgroundColor: Int) = | 
				
			||||
            if (ColorUtils.isColorLight(backgroundColor)) Light | 
				
			||||
            else Dark | 
				
			||||
         | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,31 @@ | 
				
			||||
package io.legado.app.data.dao | 
				
			||||
 | 
				
			||||
import androidx.lifecycle.LiveData | 
				
			||||
import androidx.room.* | 
				
			||||
import io.legado.app.data.entities.HttpTTS | 
				
			||||
 | 
				
			||||
@Dao | 
				
			||||
interface HttpTTSDao { | 
				
			||||
 | 
				
			||||
    @get:Query("select * from httpTTS order by name") | 
				
			||||
    val all: List<HttpTTS> | 
				
			||||
 | 
				
			||||
    @Query("select * from httpTTS order by name") | 
				
			||||
    fun observeAll(): LiveData<List<HttpTTS>> | 
				
			||||
 | 
				
			||||
    @get:Query("select count(*) from httpTTS") | 
				
			||||
    val count: Int | 
				
			||||
 | 
				
			||||
    @Query("select * from httpTTS where id = :id") | 
				
			||||
    fun get(id: Long): HttpTTS? | 
				
			||||
 | 
				
			||||
    @Insert(onConflict = OnConflictStrategy.REPLACE) | 
				
			||||
    fun insert(vararg httpTTS: HttpTTS) | 
				
			||||
 | 
				
			||||
    @Delete | 
				
			||||
    fun delete(vararg httpTTS: HttpTTS) | 
				
			||||
 | 
				
			||||
    @Update | 
				
			||||
    fun update(vararg httpTTS: HttpTTS) | 
				
			||||
 | 
				
			||||
} | 
				
			||||
@ -0,0 +1,39 @@ | 
				
			||||
package io.legado.app.data.dao | 
				
			||||
 | 
				
			||||
import androidx.room.* | 
				
			||||
import io.legado.app.data.entities.ReadRecord | 
				
			||||
import io.legado.app.data.entities.ReadRecordShow | 
				
			||||
 | 
				
			||||
@Dao | 
				
			||||
interface ReadRecordDao { | 
				
			||||
 | 
				
			||||
    @get:Query("select * from readRecord") | 
				
			||||
    val all: List<ReadRecord> | 
				
			||||
 | 
				
			||||
    @get:Query("select bookName, sum(readTime) as readTime from readRecord group by bookName order by bookName") | 
				
			||||
    val allShow: List<ReadRecordShow> | 
				
			||||
 | 
				
			||||
    @get:Query("select sum(readTime) from readRecord") | 
				
			||||
    val allTime: Long | 
				
			||||
 | 
				
			||||
    @Query("select sum(readTime) from readRecord where bookName = :bookName") | 
				
			||||
    fun getReadTime(bookName: String): Long? | 
				
			||||
 | 
				
			||||
    @Query("select readTime from readRecord where androidId = :androidId and bookName = :bookName") | 
				
			||||
    fun getReadTime(androidId: String, bookName: String): Long? | 
				
			||||
 | 
				
			||||
    @Insert(onConflict = OnConflictStrategy.REPLACE) | 
				
			||||
    fun insert(vararg readRecord: ReadRecord) | 
				
			||||
 | 
				
			||||
    @Update | 
				
			||||
    fun update(vararg record: ReadRecord) | 
				
			||||
 | 
				
			||||
    @Delete | 
				
			||||
    fun delete(vararg record: ReadRecord) | 
				
			||||
 | 
				
			||||
    @Query("delete from readRecord") | 
				
			||||
    fun clear() | 
				
			||||
 | 
				
			||||
    @Query("delete from readRecord where bookName = :bookName") | 
				
			||||
    fun deleteByName(bookName: String) | 
				
			||||
} | 
				
			||||