pull/21/head
fengyuecanzhu 3 years ago
parent 64abf589b1
commit 39160c8ff0
  1. 15
      .idea/misc.xml
  2. 2
      app/build.gradle
  3. 1
      app/src/main/AndroidManifest.xml
  4. 11
      app/src/main/java/xyz/fycz/myreader/application/App.java
  5. 1
      app/src/main/java/xyz/fycz/myreader/common/APPCONST.java
  6. 6
      app/src/main/java/xyz/fycz/myreader/common/URLCONST.java
  7. 74
      app/src/main/java/xyz/fycz/myreader/entity/AdBean.java
  8. 10
      app/src/main/java/xyz/fycz/myreader/entity/ad/AdBean.kt
  9. 137
      app/src/main/java/xyz/fycz/myreader/entity/ad/AdConfig.java
  10. 12
      app/src/main/java/xyz/fycz/myreader/entity/lanzou/LanZouFile.kt
  11. 4
      app/src/main/java/xyz/fycz/myreader/entity/lanzou/LanZouParseBean.kt
  12. 44
      app/src/main/java/xyz/fycz/myreader/enums/Font.java
  13. 2
      app/src/main/java/xyz/fycz/myreader/experiment/BookWCEstimate.kt
  14. 77
      app/src/main/java/xyz/fycz/myreader/greendao/entity/SubscribeFile.java
  15. 2
      app/src/main/java/xyz/fycz/myreader/greendao/util/MySQLiteOpenHelper.java
  16. 22
      app/src/main/java/xyz/fycz/myreader/model/sourceAnalyzer/BookSourceManager.java
  17. 6
      app/src/main/java/xyz/fycz/myreader/model/third3/http/OkHttpUtils.kt
  18. 6
      app/src/main/java/xyz/fycz/myreader/ui/activity/AboutActivity.java
  19. 32
      app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java
  20. 9
      app/src/main/java/xyz/fycz/myreader/ui/activity/BookSourceActivity.java
  21. 66
      app/src/main/java/xyz/fycz/myreader/ui/activity/DonateActivity.java
  22. 32
      app/src/main/java/xyz/fycz/myreader/ui/activity/MoreSettingActivity.java
  23. 42
      app/src/main/java/xyz/fycz/myreader/ui/activity/SearchBookActivity.java
  24. 116
      app/src/main/java/xyz/fycz/myreader/ui/activity/SourceSubscribeActivity.kt
  25. 1
      app/src/main/java/xyz/fycz/myreader/ui/activity/SplashActivity.java
  26. 58
      app/src/main/java/xyz/fycz/myreader/ui/adapter/SubscribeSourceAdapter.kt
  27. 36
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SourceFileHolder.kt
  28. 96
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SubscribeSourceHolder.kt
  29. 13
      app/src/main/java/xyz/fycz/myreader/ui/fragment/DIYSourceFragment.java
  30. 40
      app/src/main/java/xyz/fycz/myreader/ui/fragment/MineFragment.java
  31. 202
      app/src/main/java/xyz/fycz/myreader/ui/fragment/SubscribeSourceFragment.kt
  32. 193
      app/src/main/java/xyz/fycz/myreader/util/utils/AdUtils.java
  33. 19
      app/src/main/java/xyz/fycz/myreader/util/utils/OkHttpUtils.java
  34. 2
      app/src/main/java/xyz/fycz/myreader/util/utils/ShareBookUtil.java
  35. 83
      app/src/main/java/xyz/fycz/myreader/webapi/LanZouApi.kt
  36. 4
      app/src/main/java/xyz/fycz/myreader/webapi/LanZousApi.java
  37. 3
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/ReadCrawlerUtil.java
  38. 26
      app/src/main/res/layout/activity_more_setting.xml
  39. 41
      app/src/main/res/layout/activity_source_subscribe.xml
  40. 230
      app/src/main/res/layout/fragment_mine.xml
  41. 86
      app/src/main/res/layout/fragment_subscribe_source.xml
  42. 36
      app/src/main/res/layout/item_lan_zou_file.xml
  43. 60
      app/src/main/res/layout/item_subscribe_source.xml
  44. 18
      app/src/main/res/menu/menu_subscribe_source.xml
  45. 19
      app/src/main/res/values/strings.xml

@ -17,6 +17,7 @@
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_about.xml" value="0.12132725430597771" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_auth_email.xml" value="0.1897644927536232" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_book_detail.xml" value="0.12132725430597771" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_catalog.xml" value="0.21557971014492755" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_crash.xml" value="0.264" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_donate.xml" value="0.32698961937716264" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_feedback.xml" value="0.12132725430597771" />
@ -30,38 +31,50 @@
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_search_book.xml" value="0.26904376012965964" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_search_word.xml" value="0.144" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_source_debug.xml" value="0.2391304347826087" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_source_subscribe.xml" value="0.21557971014492755" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/dialog_book_source.xml" value="0.20969202898550723" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/dialog_loading.xml" value="0.1" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/dialog_textview.xml" value="0.1947463768115942" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/fingerprint_dialog.xml" value="0.20425724637681159" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/fragment_file_category.xml" value="0.2318840579710145" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/fragment_find_book_2.xml" value="0.12132725430597771" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/fragment_import_source.xml" value="0.12132725430597771" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/fragment_local_book.xml" value="0.21557971014492755" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/fragment_local_source.xml" value="0.1947463768115942" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/fragment_mine.xml" value="0.37037037037037035" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/fragment_private_bookcase.xml" value="0.21195652173913043" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/fragment_subscribe_source.xml" value="0.21557971014492755" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/fragment_webdav_setting.xml" value="0.4" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/gridview_book_detailed_item.xml" value="0.1947463768115942" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/item_book_source.xml" value="0.21195652173913043" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/item_file.xml" value="0.21557971014492755" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/item_find_source.xml" value="0.12132725430597771" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/item_group.xml" value="0.4" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/item_local_source.xml" value="0.21195652173913043" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/item_lan_zou_file.xml" value="0.21557971014492755" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/item_local_source.xml" value="0.536" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/item_read_record.xml" value="0.12132725430597771" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/item_replace_rule.xml" value="0.1947463768115942" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/item_search_book.xml" value="0.1947463768115942" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/item_search_word1.xml" value="0.2889273356401384" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/item_search_word2.xml" value="0.1947463768115942" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/item_search_word_1.xml" value="0.1947463768115942" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/item_subscribe_source.xml" value="0.21557971014492755" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/layout_about_content.xml" value="0.176" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/layout_book_detail_content.xml" value="0.17889492753623187" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/layout_book_detail_header.xml" value="0.536" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/listview_search_book_item.xml" value="0.22010869565217392" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/menu_book.xml" value="0.21557971014492755" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/search_book_item.xml" value="0.1947463768115942" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/view_file_picker.xml" value="0.12132725430597771" />
<entry key="..\:/android/FYReader/app/src/main/res/menu/menu_book.xml" value="0.13703703703703704" />
<entry key="..\:/android/FYReader/app/src/main/res/menu/menu_book_detail.xml" value="0.24947916666666667" />
<entry key="..\:/android/FYReader/app/src/main/res/menu/menu_book_detail_local.xml" value="0.24947916666666667" />
<entry key="..\:/android/FYReader/app/src/main/res/menu/menu_import_source.xml" value="0.1675925925925926" />
<entry key="..\:/android/FYReader/app/src/main/res/menu/menu_read.xml" value="0.24947916666666667" />
<entry key="..\:/android/FYReader/app/src/main/res/menu/menu_rule.xml" value="0.24947916666666667" />
<entry key="..\:/android/FYReader/app/src/main/res/menu/menu_search_word.xml" value="0.1425925925925926" />
<entry key="..\:/android/FYReader/app/src/main/res/menu/menu_source_edit.xml" value="0.2815533980582524" />
<entry key="..\:/android/FYReader/app/src/main/res/menu/menu_subscribe_source.xml" value="0.24947916666666667" />
</map>
</option>
</component>

@ -277,7 +277,7 @@ dependencies {
}
greendao {
schemaVersion 33
schemaVersion 34
daoPackage 'xyz.fycz.myreader.greendao.gen'
// targetGenDir 'src/main/java'
}

@ -129,6 +129,7 @@
<activity android:name=".ui.activity.AuthEmailActivity" />
<activity android:name=".ui.activity.RestartActivity" />
<activity android:name=".ui.activity.CrashActivity" />
<activity android:name=".ui.activity.SourceSubscribeActivity" />
<receiver android:name=".util.notification.NotificationClickReceiver" />
<receiver android:name=".ui.presenter.BookcasePresenter$cancelDownloadReceiver" />

@ -1,15 +1,12 @@
package xyz.fycz.myreader.application;
import static android.provider.ContactsContract.Directory.PACKAGE_NAME;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Application;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@ -36,7 +33,6 @@ import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.io.File;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -92,7 +88,8 @@ public class App extends Application {
initNightTheme();
// LLog.init(APPCONST.LOG_DIR);
initDialogX();
AdUtils.initAd();
if (!debug)
AdUtils.initAd();
}
@ -312,7 +309,7 @@ public class App extends Application {
if (!StringHelper.isEmpty(downloadLink)) {
spu.putString(getmContext().getString(R.string.downloadLink), downloadLink);
} else {
spu.putString(getmContext().getString(R.string.downloadLink), URLCONST.APP_DIR_UR);
spu.putString(getmContext().getString(R.string.downloadLink), URLCONST.APP_DIR_URL);
}
String[] updateContents = updateContent.split("/");
for (String string : updateContents) {
@ -364,7 +361,7 @@ public class App extends Application {
private void goDownload(Activity activity, String url) {
String downloadLink = url;
if (url == null || "".equals(url)) {
downloadLink = URLCONST.APP_DIR_UR;
downloadLink = URLCONST.APP_DIR_URL;
}
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);

@ -102,6 +102,7 @@ public class APPCONST {
public static final int REQUEST_GROUP_MANAGER = 1014;
public static final int REQUEST_SEARCH_WORD = 1015;
public static final int REQUEST_AUTH_EMAIL = 1016;
public static final int REQUEST_SETTING = 1017;
public static final int REQUEST_READ = 1;

@ -6,9 +6,11 @@ public class URLCONST {
public static final String OFFICIAL_WEB = "https://reader." + getDefaultDomain() + "/";
public static String APP_DIR_UR = "https://www.lanzous.com/b00ngso7e";
public static String LAN_ZOU_URL = "https://fycz.lanzoum.com";
public static String LAN_ZOUS_URL = "https://fycz.lanzoui.com";
public static String APP_DIR_URL = LAN_ZOU_URL + "/b00ngso7e";
public static final String SUB_SOURCE_URL = LAN_ZOU_URL + "/b00pfkkgh";
//字体下载
public static final String FONT_DOWNLOAD_URL = "https://novel." + getDefaultDomain() + "/app/fonts/";

@ -1,74 +0,0 @@
package xyz.fycz.myreader.entity;
/**
* @author fengyue
* @date 2022/2/17 18:56
*/
public class AdBean {
//是否云控
private boolean isCloud;
//是否有广告
private boolean hasAd;
//应用处于后台一段时间展示开屏广告(单位:分钟)
private int backAdTime;
//应用回到前台展示广告间隔(单位:分钟)
private int intervalAdTime;
//是否在详情页展示信息流广告
private boolean showFlowAd;
public AdBean() {
}
public AdBean(boolean hasAd, int backAdTime, int intervalAdTime) {
this.hasAd = hasAd;
this.backAdTime = backAdTime;
this.intervalAdTime = intervalAdTime;
}
public AdBean(boolean hasAd, int backAdTime, int intervalAdTime, boolean showFlowAd) {
this.hasAd = hasAd;
this.backAdTime = backAdTime;
this.intervalAdTime = intervalAdTime;
this.showFlowAd = showFlowAd;
}
public boolean isCloud() {
return isCloud;
}
public void setCloud(boolean cloud) {
isCloud = cloud;
}
public boolean isHasAd() {
return hasAd;
}
public void setHasAd(boolean hasAd) {
this.hasAd = hasAd;
}
public int getBackAdTime() {
return backAdTime;
}
public void setBackAdTime(int backAdTime) {
this.backAdTime = backAdTime;
}
public int getIntervalAdTime() {
return intervalAdTime;
}
public void setIntervalAdTime(int intervalAdTime) {
this.intervalAdTime = intervalAdTime;
}
public boolean isShowFlowAd() {
return showFlowAd;
}
public void setShowFlowAd(boolean showFlowAd) {
this.showFlowAd = showFlowAd;
}
}

@ -0,0 +1,10 @@
package xyz.fycz.myreader.entity.ad
/**
* @author fengyue
* @date 2022/3/3 15:00
*/
data class AdBean(
val status: Int,// 广告展示状态:0:不展示,1:展示信息流广告,2:展示插屏广告
val interval: Int,// 广告展示间隔(单位:分钟)
)

@ -0,0 +1,137 @@
package xyz.fycz.myreader.entity.ad;
import androidx.annotation.NonNull;
import xyz.fycz.myreader.util.utils.GsonExtensionsKt;
/**
* @author fengyue
* @date 2022/2/17 18:56
*/
public class AdConfig {
//是否云控
private boolean isCloud;
//是否有广告
private boolean hasAd;
//配置过期时间
private int expireTime;
//应用处于后台一段时间展示开屏广告(单位:分钟)
private int backAdTime;
//应用回到前台展示广告间隔(单位:分钟)
private int intervalAdTime;
//单次激励视频可去广告时间(单位:小时),为0时表示关闭去广告
private int removeAdTime;
//每日最大去除广告次数
private int maxRemove;
//累计最高去除时间(单位:小时)
private int totalRemove;
//详情页广告配置
private AdBean detail;
//搜索页广告配置
private AdBean search;
public AdConfig() {
}
public AdConfig(boolean hasAd, int expireTime, int backAdTime, int intervalAdTime, int removeAdTime, int maxRemove, int totalRemove) {
this.hasAd = hasAd;
this.expireTime = expireTime;
this.backAdTime = backAdTime;
this.intervalAdTime = intervalAdTime;
this.removeAdTime = removeAdTime;
this.maxRemove = maxRemove;
this.totalRemove = totalRemove;
}
public boolean isCloud() {
return isCloud;
}
public void setCloud(boolean cloud) {
isCloud = cloud;
}
public boolean isHasAd() {
return hasAd;
}
public void setHasAd(boolean hasAd) {
this.hasAd = hasAd;
}
public int getBackAdTime() {
return backAdTime;
}
public void setBackAdTime(int backAdTime) {
this.backAdTime = backAdTime;
}
public int getIntervalAdTime() {
return intervalAdTime;
}
public void setIntervalAdTime(int intervalAdTime) {
this.intervalAdTime = intervalAdTime;
}
public int getExpireTime() {
return expireTime;
}
public void setExpireTime(int expireTime) {
this.expireTime = expireTime;
}
public int getRemoveAdTime() {
return removeAdTime;
}
public void setRemoveAdTime(int removeAdTime) {
this.removeAdTime = removeAdTime;
}
public int getMaxRemove() {
return maxRemove;
}
public void setMaxRemove(int maxRemove) {
this.maxRemove = maxRemove;
}
public int getTotalRemove() {
return totalRemove;
}
public void setTotalRemove(int totalRemove) {
this.totalRemove = totalRemove;
}
public AdBean getDetail() {
if (detail == null) {
detail = new AdBean(2, 60);
}
return detail;
}
public void setDetail(AdBean detail) {
this.detail = detail;
}
public AdBean getSearch() {
if (search == null) {
search = new AdBean(0, 60);
}
return search;
}
public void setSearch(AdBean search) {
this.search = search;
}
@NonNull
@Override
public String toString() {
return GsonExtensionsKt.getGSON().toJson(this);
}
}

@ -0,0 +1,12 @@
package xyz.fycz.myreader.entity.lanzou
/**
* @author fengyue
* @date 2022/3/3 8:53
*/
data class LanZouFile(
var id: String,
var name_all: String,
var size: String,
var time: String
)

@ -1,10 +1,10 @@
package xyz.fycz.myreader.entity
package xyz.fycz.myreader.entity.lanzou
/**
* @author fengyue
* @date 2022/1/22 20:15
*/
data class LanZouBean(
data class LanZouParseBean(
var zt: Int,
var dom: String,
var url: String,

@ -6,28 +6,28 @@ public enum Font {
默认字体( "默认字体"),
本地字体( "默认字体"),
方正楷体( URLCONST.LAN_ZOUS_URL + "/ilLFMe6kefe"),
方正行楷( URLCONST.LAN_ZOUS_URL + "/imFvne6keji"),
经典宋体(URLCONST.LAN_ZOUS_URL + "/idhI5e6keqf"),
方正硬笔行书(URLCONST.LAN_ZOUS_URL + "/ilVh6ep9xja"),
包图小白体(URLCONST.LAN_ZOUS_URL + "/i5qgAicrirc"),
仓耳非白W02(URLCONST.LAN_ZOUS_URL + "/iHwRnicriuf"),
仓耳舒圆体W02(URLCONST.LAN_ZOUS_URL + "/i3GVPicrj3e"),
仓耳与墨W02(URLCONST.LAN_ZOUS_URL + "/ivhv9icrj7i"),
方正仿宋简体(URLCONST.LAN_ZOUS_URL + "/iEcCHicrjef"),
方正黑体简体(URLCONST.LAN_ZOUS_URL + "/iw8kKicrjij"),
方正书宋简体(URLCONST.LAN_ZOUS_URL + "/i5976icrjmd"),
品如手写体(URLCONST.LAN_ZOUS_URL + "/iZccuicrjyf"),
千图小兔体(URLCONST.LAN_ZOUS_URL + "/iOONMicrkda"),
手书体(URLCONST.LAN_ZOUS_URL + "/iqbmdicrkvi"),
演示春风楷(URLCONST.LAN_ZOUS_URL + "/ioRJSicrldg"),
演示秋鸿楷(URLCONST.LAN_ZOUS_URL + "/i8qnzicrlsb"),
演示夏行楷(URLCONST.LAN_ZOUS_URL + "/iyYUTicrm6f"),
演示悠然小楷(URLCONST.LAN_ZOUS_URL + "/ikKq7icrmrg"),
杨任东竹石体(URLCONST.LAN_ZOUS_URL + "/iiWdVicrnbg"),
站酷仓耳渔阳体(URLCONST.LAN_ZOUS_URL + "/if5weicrnje"),
迷你隶书( URLCONST.LAN_ZOUS_URL + "/ihaXVe6kekj"),
方正黄草(URLCONST.LAN_ZOUS_URL + "/iQg67e6keed");
方正楷体( URLCONST.LAN_ZOU_URL + "/ilLFMe6kefe"),
方正行楷( URLCONST.LAN_ZOU_URL + "/imFvne6keji"),
经典宋体(URLCONST.LAN_ZOU_URL + "/idhI5e6keqf"),
方正硬笔行书(URLCONST.LAN_ZOU_URL + "/ilVh6ep9xja"),
包图小白体(URLCONST.LAN_ZOU_URL + "/i5qgAicrirc"),
仓耳非白W02(URLCONST.LAN_ZOU_URL + "/iHwRnicriuf"),
仓耳舒圆体W02(URLCONST.LAN_ZOU_URL + "/i3GVPicrj3e"),
仓耳与墨W02(URLCONST.LAN_ZOU_URL + "/ivhv9icrj7i"),
方正仿宋简体(URLCONST.LAN_ZOU_URL + "/iEcCHicrjef"),
方正黑体简体(URLCONST.LAN_ZOU_URL + "/iw8kKicrjij"),
方正书宋简体(URLCONST.LAN_ZOU_URL + "/i5976icrjmd"),
品如手写体(URLCONST.LAN_ZOU_URL + "/iZccuicrjyf"),
千图小兔体(URLCONST.LAN_ZOU_URL + "/iOONMicrkda"),
手书体(URLCONST.LAN_ZOU_URL + "/iqbmdicrkvi"),
演示春风楷(URLCONST.LAN_ZOU_URL + "/ioRJSicrldg"),
演示秋鸿楷(URLCONST.LAN_ZOU_URL + "/i8qnzicrlsb"),
演示夏行楷(URLCONST.LAN_ZOU_URL + "/iyYUTicrm6f"),
演示悠然小楷(URLCONST.LAN_ZOU_URL + "/ikKq7icrmrg"),
杨任东竹石体(URLCONST.LAN_ZOU_URL + "/iiWdVicrnbg"),
站酷仓耳渔阳体(URLCONST.LAN_ZOU_URL + "/if5weicrnje"),
迷你隶书( URLCONST.LAN_ZOU_URL + "/ihaXVe6kekj"),
方正黄草(URLCONST.LAN_ZOU_URL + "/iQg67e6keed");
public String downloadPath;

@ -53,7 +53,7 @@ class BookWCEstimate {
cachedChapterSize++
}
}
if (cachedChapterSize < 20 && chapters.size > 50) return -2
if ((cachedChapterSize < 20 && chapters.size > 50) || cachedChapterSize == 0) return -2
chapters.forEach { chapter ->
if (ChapterService.isChapterCached(chapter.bookId, chapter.title)) {
sum += countChar(

@ -0,0 +1,77 @@
package xyz.fycz.myreader.greendao.entity;
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Generated;
/**
* @author fengyue
* @date 2022/3/3 14:40
*/
@Entity
public class SubscribeFile {
@Id
private String id;
private String name;
private String url;
private String date;
private String size;
@Generated(hash = 1850023033)
public SubscribeFile(String id, String name, String url, String date,
String size) {
this.id = id;
this.name = name;
this.url = url;
this.date = date;
this.size = size;
}
@Generated(hash = 1590903919)
public SubscribeFile() {
}
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return this.url;
}
public void setUrl(String url) {
this.url = url;
}
public String getDate() {
return this.date;
}
public void setDate(String date) {
this.date = date;
}
public String getSize() {
return this.size;
}
public void setSize(String size) {
this.size = size;
}
}

@ -39,7 +39,7 @@ public class MySQLiteOpenHelper extends DaoMaster.OpenHelper {
BookDao.class, ChapterDao.class, SearchHistoryDao.class,
BookMarkDao.class, BookGroupDao.class, ReplaceRuleBeanDao.class,
BookSourceDao.class, CookieBeanDao.class, ReadRecordDao.class,
SearchWordDao.class
SearchWordDao.class, SubscribeFileDao.class
);
}

@ -4,8 +4,6 @@ import android.database.Cursor;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
@ -19,7 +17,6 @@ import io.reactivex.SingleOnSubscribe;
import io.reactivex.functions.Function;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.App;
import xyz.fycz.myreader.entity.thirdsource.BookSource3Bean;
import xyz.fycz.myreader.entity.thirdsource.BookSourceBean;
import xyz.fycz.myreader.entity.thirdsource.ThirdSourceUtil;
import xyz.fycz.myreader.entity.thirdsource.source3.Source3;
@ -271,7 +268,7 @@ public class BookSourceManager {
}).compose(RxUtils::toSimpleSingle);
}
public static List<String> getEnableNoLocalGroupList() {
public static List<String> getEnableGroupList() {
List<String> groupList = new ArrayList<>();
String sql = "SELECT DISTINCT "
+ BookSourceDao.Properties.SourceGroup.columnName
@ -292,17 +289,24 @@ public class BookSourceManager {
return groupList;
}
public static List<String> getNoLocalGroupList() {
public static List<String> getGroupList(boolean isSubscribe) {
List<String> groupList = new ArrayList<>();
String sql = "SELECT DISTINCT " + BookSourceDao.Properties.SourceGroup.columnName + " FROM " + BookSourceDao.TABLENAME;
String sql = "SELECT DISTINCT " + BookSourceDao.Properties.SourceGroup.columnName + ","
+ BookSourceDao.Properties.SourceEName.columnName + " FROM " + BookSourceDao.TABLENAME;
Cursor cursor = DbManager.getDaoSession().getDatabase().rawQuery(sql, null);
if (!cursor.moveToFirst()) return groupList;
do {
String group = cursor.getString(0);
String eName = cursor.getString(1);
if (TextUtils.isEmpty(group) || TextUtils.isEmpty(group.trim())) continue;
for (String item : group.split("\\s*[,;,;]\\s*")) {
if (TextUtils.isEmpty(item) || groupList.contains(item) || item.equals("内置书源"))
continue;
if (isSubscribe) {
if (TextUtils.isEmpty(eName) || TextUtils.isEmpty(item) || groupList.contains(item))
continue;
} else {
if (!TextUtils.isEmpty(eName) || TextUtils.isEmpty(item) || groupList.contains(item) || item.equals("内置书源"))
continue;
}
groupList.add(item);
}
} while (cursor.moveToNext());
@ -326,7 +330,7 @@ public class BookSourceManager {
return importSource(FileUtils.readText(string));
}
if (string.matches("https://.+\\.lanzou[a-z]\\.com/[\\s\\S]*")) {
return LanZouApi.INSTANCE.getUrl(string)
return LanZouApi.INSTANCE.getFileUrl(string)
.flatMap((Function<String, ObservableSource<String>>) s -> Observable.create(emitter -> {
emitter.onNext(OkHttpUtils.getHtml(s));
emitter.onComplete();

@ -133,13 +133,13 @@ fun Request.Builder.get(url: String, queryMap: Map<String, String>, encoded: Boo
url(httpBuilder.build())
}
fun Request.Builder.postForm(form: Map<String, String>, encoded: Boolean = false) {
fun Request.Builder.postForm(form: Map<String, Any>, encoded: Boolean = false) {
val formBody = FormBody.Builder()
form.forEach {
if (encoded) {
formBody.addEncoded(it.key, it.value)
formBody.addEncoded(it.key, it.value.toString())
} else {
formBody.add(it.key, it.value)
formBody.add(it.key, it.value.toString())
}
}
post(formBody.build())

@ -3,7 +3,6 @@ package xyz.fycz.myreader.ui.activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.view.View;
@ -33,7 +32,6 @@ import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.ZipUtils;
import xyz.fycz.myreader.util.utils.FileUtils;
import xyz.fycz.myreader.util.utils.ImageLoader;
import xyz.fycz.myreader.util.utils.OkHttpUtils;
import xyz.fycz.myreader.util.utils.RxUtils;
import xyz.fycz.myreader.webapi.LanZouApi;
@ -74,7 +72,7 @@ public class AboutActivity extends BaseActivity {
binding.il.rlUpdateLog.setOnClickListener(v -> DialogCreator.createAssetTipDialog(this, "更新日志", "updatelog.fy"));
binding.il.rlShare.setOnClickListener(v -> ShareUtils.share(this, getString(R.string.share_text) +
SharedPreUtils.getInstance().getString(getString(R.string.downloadLink), URLCONST.LAN_ZOUS_URL)));
SharedPreUtils.getInstance().getString(getString(R.string.downloadLink), URLCONST.LAN_ZOU_URL)));
binding.il.rlQq.setOnClickListener(v -> {
if (!App.joinQQGroup(this, "8PIOnHFuH6A38hgxvD_Rp2Bu-Ke1ToBn")) {
//数据
@ -120,7 +118,7 @@ public class AboutActivity extends BaseActivity {
MyAlertDialog.createInputDia(this, getString(R.string.lan_zou_parse),
"格式:链接+逗号+密码(没有密码就不用填)", "", true,
100, text -> str[0] = text, (dialog, which) -> {
LanZouApi.INSTANCE.getUrl(str[0])
LanZouApi.INSTANCE.getFileUrl(str[0])
.compose(RxUtils::toSimpleSingle)
.subscribe(new MyObserver<String>() {
@Override

@ -42,6 +42,7 @@ import xyz.fycz.myreader.base.observer.MyObserver;
import xyz.fycz.myreader.base.observer.MySingleObserver;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.databinding.ActivityBookDetailBinding;
import xyz.fycz.myreader.entity.ad.AdBean;
import xyz.fycz.myreader.experiment.BookWCEstimate;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
@ -55,6 +56,7 @@ import xyz.fycz.myreader.ui.dialog.BookGroupDialog;
import xyz.fycz.myreader.ui.dialog.DialogCreator;
import xyz.fycz.myreader.ui.dialog.LoadingDialog;
import xyz.fycz.myreader.ui.dialog.SourceExchangeDialog;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.help.StringHelper;
import xyz.fycz.myreader.util.utils.AdUtils;
@ -91,6 +93,7 @@ public class BookDetailedActivity extends BaseActivity {
private List<String> tagList = new ArrayList<>();
private Disposable chaptersDis;
private Disposable wcDis;
private AdBean adBean;
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@ -257,7 +260,8 @@ public class BookDetailedActivity extends BaseActivity {
}
mSourceDialog.setABooks(aBooks);
mSourceDialog.setSourceIndex(sourceIndex);
if (AdUtils.getAdConfig().isHasAd() && AdUtils.getAdConfig().isShowFlowAd()){
adBean = AdUtils.getAdConfig().getDetail();
if (AdUtils.getAdConfig().isHasAd() && AdUtils.adTime("detail", adBean)) {
initAd();
}
}
@ -267,26 +271,12 @@ public class BookDetailedActivity extends BaseActivity {
@Override
public void onSuccess(@NonNull Boolean aBoolean) {
if (aBoolean) {
new DdSdkFlowAd().getFlowViews(BookDetailedActivity.this, 1, new DdSdkFlowAd.FlowCallback() {
// 信息流广告拉取完毕后返回的 views
@Override
public void getFlowView(View view) {
binding.ic.getRoot().addView(view, 2);
}
// 信息流广告展示后调用
@Override
public void show() {
AdUtils.adRecord("flow", "adShow");
Log.d(TAG, "信息流广告展示成功");
}
// 广告拉取失败调用
@Override
public void error(String msg) {
Log.d(TAG, "广告拉取失败\n" + msg);
}
});
if (adBean.getStatus() == 1) {
AdUtils.getFlowAd(BookDetailedActivity.this, 1,
view -> binding.ic.getRoot().addView(view, 2), "detail");
} else if (adBean.getStatus() == 2) {
AdUtils.showInterAd(BookDetailedActivity.this, "detail");
}
}
}
});

@ -23,6 +23,7 @@ import xyz.fycz.myreader.base.BaseTabActivity;
import xyz.fycz.myreader.databinding.ActivityBooksourceBinding;
import xyz.fycz.myreader.ui.fragment.DIYSourceFragment;
import xyz.fycz.myreader.ui.fragment.LocalSourceFragment;
import xyz.fycz.myreader.ui.fragment.SubscribeSourceFragment;
/**
* @author fengyue
@ -42,13 +43,13 @@ public class BookSourceActivity extends BaseTabActivity {
@Override
protected List<Fragment> createTabFragments() {
return Arrays.asList(new LocalSourceFragment(this),
return Arrays.asList(new SubscribeSourceFragment(this),
new DIYSourceFragment(this));
}
@Override
protected List<String> createTabTitles() {
return Arrays.asList("内置书源", "DIY书源");
return Arrays.asList("订阅书源", "DIY书源");
}
@Override
@ -73,7 +74,7 @@ public class BookSourceActivity extends BaseTabActivity {
List<Fragment> fragments = getSupportFragmentManager().getFragments();
switch (tab.getPosition()) {
case 0:
((LocalSourceFragment) fragments.get(0)).startSearch("");
((SubscribeSourceFragment) fragments.get(0)).startSearch("");
break;
case 1:
((DIYSourceFragment) fragments.get(1)).startSearch("");
@ -112,7 +113,7 @@ public class BookSourceActivity extends BaseTabActivity {
List<Fragment> fragments = getSupportFragmentManager().getFragments();
switch (binding.tabVp.getCurrentItem()) {
case 0:
((LocalSourceFragment) fragments.get(0)).startSearch(newText);
((SubscribeSourceFragment) fragments.get(0)).startSearch(newText);
break;
case 1:
((DIYSourceFragment) fragments.get(1)).startSearch(newText);

@ -53,7 +53,6 @@ public class DonateActivity extends BaseActivity {
@Override
public void onSuccess(@NonNull Boolean aBoolean) {
if (aBoolean) {
//AdUtils.initAd();
initAd();
}
}
@ -82,7 +81,7 @@ public class DonateActivity extends BaseActivity {
Log.d(TAG, "广告拉取失败\n" + msg);
}
});*/
}
}
@Override
protected void initClick() {
@ -93,70 +92,11 @@ public class DonateActivity extends BaseActivity {
MyAlertDialog.showFullWebViewDia(this, URLCONST.THANKS_URL,
false, null));
binding.llRewardedVideo.setOnClickListener(v -> {
DdSdkRewardAd.show(this, new DdSdkRewardAd.DdSdkRewardCallback() {
@Override
public void show() {
Log.i(TAG, "激励视频展示成功");
AdUtils.adRecord("rewardVideo","adShow");
}
@Override
public void click() {
Log.i(TAG, "激励视频被点击");
AdUtils.adRecord("rewardVideo","adClick");
}
@Override
public void error(String msg) {
}
@Override
public void skip() {
Log.i(TAG, "激励视频被跳过");
AdUtils.adRecord("rewardVideo","adSkip");
}
@Override
public void reward() {
Log.i(TAG, "激励视频计时完成");
AdUtils.adRecord("rewardVideo","adFinishCount");
}
});
});
binding.llInterAd.setOnClickListener(v -> {
/*
* 参数 1 activity
* 参数 2 marginDp (float)插屏默认 margin 全屏幕的 24dp此处允许开发者手动调节 margin 大小单位为 dp允许范围为 0dp (全屏) ~ 48dp请开发者按需填写
*/
DdSdkInterAd.show(this, 48f, new DdSdkInterAd.Callback() {
@Override
public void show() {
Log.i(TAG, "插屏广告展示成功");
AdUtils.adRecord("inter","adShow");
}
@Override
public void click() {
Log.i(TAG, "插屏广告");
AdUtils.adRecord("inter","adClick");
}
binding.llRewardedVideo.setOnClickListener(v -> AdUtils.showRewardVideoAd(this, null));
@Override
public void error(String msg) {
}
@Override
public void close() {
Log.i(TAG, "插屏广告被关闭");
AdUtils.adRecord("inter","adClose");
}
});
});
binding.llInterAd.setOnClickListener(v -> AdUtils.showInterAd(this, null));
}
private void goDonate(String address) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);

@ -71,6 +71,7 @@ public class MoreSettingActivity extends BaseActivity implements SharedPreferenc
private boolean upMenu;
private Setting mSetting;
private int mineShowMode;
private boolean isVolumeTurnPage;
private int resetScreenTime;
private int sortStyle;
@ -115,6 +116,7 @@ public class MoreSettingActivity extends BaseActivity implements SharedPreferenc
super.initData(savedInstanceState);
needRefresh = false;
mSetting = SysManager.getSetting();
mineShowMode = SharedPreUtils.getInstance().getInt("mineShowMode", 0);
isVolumeTurnPage = mSetting.isVolumeTurnPage();
alwaysNext = mSetting.isAlwaysNext();
resetScreenTime = mSetting.getResetScreen();
@ -155,6 +157,7 @@ public class MoreSettingActivity extends BaseActivity implements SharedPreferenc
protected void initWidget() {
super.initWidget();
initSwitchStatus();
initMineShowMode();
if (sortStyle == 1) {
binding.tvBookSort.setText(getString(R.string.time_sort));
} else if (sortStyle == 2) {
@ -169,6 +172,23 @@ public class MoreSettingActivity extends BaseActivity implements SharedPreferenc
binding.tvThreadNum.setText(getString(R.string.cur_thread_num, threadNum));
}
private void initMineShowMode() {
switch (mineShowMode){
case 1:
binding.tvMineShow.setText(getString(R.string.show_cloud_only));
break;
case 2:
binding.tvMineShow.setText(getString(R.string.show_user_cloud));
break;
case 3:
binding.tvMineShow.setText(getString(R.string.hide_user_cloud));
break;
default:
binding.tvMineShow.setText(getString(R.string.show_user_only));
break;
}
}
@Override
protected void processLogic() {
SharedPreUtils.getInstance().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
@ -234,6 +254,18 @@ public class MoreSettingActivity extends BaseActivity implements SharedPreferenc
setUpToolbar();
});
binding.llMineShow.setOnClickListener(v -> {
BottomMenu.show(getString(R.string.mine_show_mode), getResources().getStringArray(R.array.mine_show))
.setSelection(mineShowMode)
.setOnMenuItemClickListener((dialog, text, which) -> {
mineShowMode = which;
SharedPreUtils.getInstance().putInt("mineShowMode", mineShowMode);
initMineShowMode();
needRefresh = true;
return false;
}).setCancelButton(R.string.cancel);
});
binding.rlVolume.setOnClickListener(
(v) -> {
isVolumeTurnPage = !isVolumeTurnPage;

@ -46,6 +46,7 @@ import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.databinding.ActivitySearchBookBinding;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.entity.Setting;
import xyz.fycz.myreader.entity.ad.AdBean;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.SearchHistory;
import xyz.fycz.myreader.greendao.entity.rule.BookSource;
@ -55,13 +56,12 @@ import xyz.fycz.myreader.model.SearchEngine;
import xyz.fycz.myreader.model.mulvalmap.ConMVMap;
import xyz.fycz.myreader.model.sourceAnalyzer.BookSourceManager;
import xyz.fycz.myreader.ui.adapter.SearchAdapter;
import xyz.fycz.myreader.ui.adapter.SearchBookAdapter;
import xyz.fycz.myreader.ui.adapter.SearchHistoryAdapter;
import xyz.fycz.myreader.ui.dialog.DialogCreator;
import xyz.fycz.myreader.ui.dialog.MultiChoiceDialog;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.help.StringHelper;
import xyz.fycz.myreader.util.utils.AdUtils;
import xyz.fycz.myreader.util.utils.OkHttpUtils;
import xyz.fycz.myreader.util.utils.RxUtils;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
@ -115,6 +115,7 @@ public class SearchBookActivity extends BaseActivity {
private boolean foldSuggest;
private boolean foldHistory;
private boolean needReGetHistory;
private AdBean adBean;
@Override
protected void bindView() {
@ -278,6 +279,26 @@ public class SearchBookActivity extends BaseActivity {
SharedPreUtils.getInstance().putBoolean("foldHistory", foldHistory);
});
initHistoryList();
adBean = AdUtils.getAdConfig().getSearch();
if (AdUtils.getAdConfig().isHasAd() && AdUtils.adTime("search", adBean)) {
initAd();
}
}
private void initAd() {
AdUtils.checkHasAd().subscribe(new MySingleObserver<Boolean>() {
@Override
public void onSuccess(@NonNull Boolean aBoolean) {
if (aBoolean) {
if (adBean.getStatus() == 1) {
AdUtils.getFlowAd(SearchBookActivity.this, 1, view ->{
binding.getRoot().addView(view, 6);
}, "search");
} else if (adBean.getStatus() == 2) {
AdUtils.showInterAd(SearchBookActivity.this, "search");
}
}
}
});
}
@Override
@ -397,16 +418,17 @@ public class SearchBookActivity extends BaseActivity {
String searchGroup = SharedPreUtils.getInstance().getString("searchGroup");
menu.removeGroup(R.id.source_group);
MenuItem item = menu.add(R.id.source_group, Menu.NONE, Menu.NONE, R.string.all_source);
MenuItem localItem = menu.add(R.id.source_group, Menu.NONE, Menu.NONE, R.string.local_source);
if ("".equals(searchGroup)) {
item.setChecked(true);
} else if (getString(R.string.local_source).equals(searchGroup)) {
localItem.setChecked(true);
}
List<String> groupList = BookSourceManager.getEnableNoLocalGroupList();
boolean hasChecked = false;
List<String> groupList = BookSourceManager.getEnableGroupList();
for (String groupName : groupList) {
item = menu.add(R.id.source_group, Menu.NONE, Menu.NONE, groupName);
if (groupName.equals(searchGroup)) item.setChecked(true);
if (groupName.equals(searchGroup)) {
item.setChecked(true);
hasChecked = true;
}
}
if (!hasChecked || "".equals(searchGroup)) {
item.setChecked(true);
}
menu.setGroupCheckable(R.id.source_group, true, true);
}

@ -0,0 +1,116 @@
package xyz.fycz.myreader.ui.activity
import android.os.Bundle
import androidx.appcompat.widget.Toolbar
import androidx.recyclerview.widget.LinearLayoutManager
import xyz.fycz.myreader.R
import xyz.fycz.myreader.base.BaseActivity
import xyz.fycz.myreader.base.adapter.BaseListAdapter
import xyz.fycz.myreader.base.adapter.IViewHolder
import xyz.fycz.myreader.common.URLCONST
import xyz.fycz.myreader.databinding.ActivitySourceSubscribeBinding
import xyz.fycz.myreader.entity.lanzou.LanZouFile
import xyz.fycz.myreader.greendao.entity.SubscribeFile
import xyz.fycz.myreader.ui.adapter.holder.SourceFileHolder
import xyz.fycz.myreader.util.ToastUtils
import xyz.fycz.myreader.webapi.LanZouApi
/**
* @author fengyue
* @date 2022/3/3 9:56
*/
class SourceSubscribeActivity : BaseActivity() {
private lateinit var binding: ActivitySourceSubscribeBinding
private lateinit var fileAdapter: BaseListAdapter<SubscribeFile>
private var page = 1
override fun bindView() {
binding = ActivitySourceSubscribeBinding.inflate(layoutInflater)
setContentView(binding.root)
}
override fun setUpToolbar(toolbar: Toolbar?) {
super.setUpToolbar(toolbar)
setStatusBarColor(R.color.colorPrimary, true)
supportActionBar?.title = "书源订阅"
}
override fun initData(savedInstanceState: Bundle?) {
super.initData(savedInstanceState)
fileAdapter = object : BaseListAdapter<SubscribeFile>() {
override fun createViewHolder(viewType: Int): IViewHolder<SubscribeFile> {
return SourceFileHolder()
}
}
binding.rvFiles.layoutManager = LinearLayoutManager(this)
binding.rvFiles.adapter = fileAdapter
loadFiles()
}
override fun initWidget() {
super.initWidget()
binding.srlFiles.setOnLoadMoreListener { loadFiles() }
binding.srlFiles.setOnRefreshListener {
page = 1
loadFiles()
}
binding.loading.setOnReloadingListener {
page = 1
loadFiles()
}
}
private fun loadFiles() {
LanZouApi.getFoldFiles(URLCONST.SUB_SOURCE_URL, page, "fm9a")
.onSuccess {
if (it != null) {
if (page == 1) {
if (it.isEmpty()) {
binding.loading.showEmpty()
} else {
binding.loading.showFinish()
fileAdapter.refreshItems(lanZouFile2SubscribeFile(it))
if (it.size < 50) {
binding.srlFiles.finishRefreshWithNoMoreData()
} else {
binding.srlFiles.finishRefresh()
}
}
} else {
fileAdapter.addItems(lanZouFile2SubscribeFile(it))
if (it.size < 50) {
binding.srlFiles.finishLoadMoreWithNoMoreData()
} else {
binding.srlFiles.finishLoadMore()
}
}
page++
} else {
binding.loading.showError()
}
}.onError {
ToastUtils.showError("" + it.localizedMessage)
}
}
override fun initClick() {
super.initClick()
}
private fun lanZouFile2SubscribeFile(lanZouFile: List<LanZouFile>): ArrayList<SubscribeFile> {
val files = ArrayList<SubscribeFile>()
lanZouFile.forEach {
val param = it.name_all.removeSuffix(".txt").split("#")
files.add(
SubscribeFile(
param[0],
param[1],
URLCONST.LAN_ZOU_URL + "/${it.id}",
param[2],
it.size
)
)
}
return files
}
}

@ -179,7 +179,6 @@ public class SplashActivity extends BaseActivity {
@Override
public void onSuccess(@NonNull Boolean aBoolean) {
if (aBoolean) {
//AdUtils.initAd();
startWithAd();
binding.ivSplash.setVisibility(View.GONE);
binding.llAd.setVisibility(View.VISIBLE);

@ -0,0 +1,58 @@
package xyz.fycz.myreader.ui.adapter
import android.widget.Filter
import xyz.fycz.myreader.base.adapter.IViewHolder
import xyz.fycz.myreader.greendao.entity.rule.BookSource
import xyz.fycz.myreader.ui.adapter.holder.SubscribeSourceHolder
import java.util.*
/**
* @author fengyue
* @date 2022/3/3 12:08
*/
class SubscribeSourceAdapter(
val sources: List<BookSource>,
private val onDelListener: OnDelListener
) : BaseSourceAdapter() {
override fun createViewHolder(viewType: Int): IViewHolder<BookSource> {
return SubscribeSourceHolder(checkMap, onDelListener)
}
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(constraint: CharSequence): FilterResults {
val charString = constraint.toString()
var mFilterList: MutableList<BookSource> = ArrayList()
if (charString.isEmpty()) {
//没有过滤的内容,则使用源数据
mFilterList = sources.toMutableList()
} else {
for (source in sources) {
//这里根据需求,添加匹配规则
if (source.sourceName.contains(charString) ||
source.sourceGroup.contains(charString)
) {
mFilterList.add(source)
}
}
}
val filterResults = FilterResults()
filterResults.values = mFilterList
return filterResults
}
//把过滤后的值返回出来
override fun publishResults(constraint: CharSequence, results: FilterResults) {
refreshItems(results.values as List<BookSource>)
}
}
}
fun removeItem(pos: Int) {
mList.removeAt(pos)
notifyItemRemoved(pos)
if (pos != mList.size) notifyItemRangeChanged(pos, mList.size - pos)
}
interface OnDelListener {
fun onDel(which: Int, source: BookSource)
}
}

@ -0,0 +1,36 @@
package xyz.fycz.myreader.ui.adapter.holder
import android.annotation.SuppressLint
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import xyz.fycz.myreader.R
import xyz.fycz.myreader.base.adapter.ViewHolderImpl
import xyz.fycz.myreader.entity.lanzou.LanZouFile
import xyz.fycz.myreader.greendao.entity.SubscribeFile
/**
* @author fengyue
* @date 2022/3/3 10:17
*/
class SourceFileHolder : ViewHolderImpl<SubscribeFile>() {
private lateinit var name: TextView
private lateinit var sizeTime: TextView
override fun getItemLayoutId(): Int {
return R.layout.item_lan_zou_file
}
override fun initView() {
name = findById(R.id.tv_file_name)
sizeTime = findById(R.id.tv_file_size_time)
}
@SuppressLint("SetTextI18n")
override fun onBind(holder: RecyclerView.ViewHolder?, data: SubscribeFile?, pos: Int) {
data?.let {
name.text = data.name
sizeTime.text = "${data.size} ${data.date}"
}
}
}

@ -0,0 +1,96 @@
package xyz.fycz.myreader.ui.adapter.holder
import android.widget.CheckBox
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import io.reactivex.Observable
import io.reactivex.ObservableEmitter
import io.reactivex.ObservableOnSubscribe
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import xyz.fycz.myreader.R
import xyz.fycz.myreader.base.adapter.ViewHolderImpl
import xyz.fycz.myreader.base.adapter2.onClick
import xyz.fycz.myreader.base.observer.MyObserver
import xyz.fycz.myreader.greendao.DbManager
import xyz.fycz.myreader.greendao.entity.rule.BookSource
import xyz.fycz.myreader.model.sourceAnalyzer.BookSourceManager
import xyz.fycz.myreader.ui.adapter.SubscribeSourceAdapter
import xyz.fycz.myreader.util.ToastUtils
import xyz.fycz.myreader.util.help.StringHelper
import xyz.fycz.myreader.util.utils.RxUtils
import java.util.*
/**
* @author fengyue
* @date 2022/3/3 12:11
*/
class SubscribeSourceHolder(
private val mCheckMap: HashMap<BookSource, Boolean>,
private val onDelListener: SubscribeSourceAdapter.OnDelListener
) : ViewHolderImpl<BookSource>() {
private var cbSource: CheckBox? = null
private var tvEnable: TextView? = null
private var tvDisable: TextView? = null
private var tvDelete: TextView? = null
override fun getItemLayoutId(): Int {
return R.layout.item_subscribe_source
}
override fun initView() {
cbSource = findById(R.id.cb_source)
tvEnable = findById(R.id.tv_enable)
tvDisable = findById(R.id.tv_disable)
tvDelete = findById(R.id.tv_delete)
}
override fun onBind(holder: RecyclerView.ViewHolder, data: BookSource, pos: Int) {
banOrUse(data)
cbSource?.isChecked = mCheckMap[data] == true
tvEnable?.onClick {
data.enable = true
banOrUse(data)
DbManager.getDaoSession().bookSourceDao.insertOrReplace(data)
}
tvDisable?.onClick {
data.enable = false
banOrUse(data)
DbManager.getDaoSession().bookSourceDao.insertOrReplace(data)
}
tvDelete?.onClick {
Observable.create { e: ObservableEmitter<Boolean?> ->
BookSourceManager.removeBookSource(data)
e.onNext(true)
}.compose { RxUtils.toSimpleSingle(it) }
.subscribe(object : MyObserver<Boolean?>() {
override fun onNext(aBoolean: Boolean) {
onDelListener.onDel(pos, data)
}
override fun onError(e: Throwable) {
ToastUtils.showError("删除失败")
}
})
}
}
private fun banOrUse(data: BookSource) {
if (data.enable) {
cbSource?.setTextColor(context.resources.getColor(R.color.textPrimary))
if (!StringHelper.isEmpty(data.sourceGroup)) {
cbSource?.text = String.format("%s [%s]", data.sourceName, data.sourceGroup)
} else {
cbSource?.text = data.sourceName
}
} else {
cbSource?.setTextColor(context.resources.getColor(R.color.textSecondary))
if (!StringHelper.isEmpty(data.sourceGroup)) {
cbSource?.text = String.format("(禁用中)%s [%s]", data.sourceName, data.sourceGroup)
} else {
cbSource?.text = String.format("(禁用中)%s", data.sourceName)
}
}
}
}

@ -3,9 +3,7 @@ package xyz.fycz.myreader.ui.fragment;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MenuInflater;
@ -19,18 +17,12 @@ import androidx.annotation.Nullable;
import androidx.documentfile.provider.DocumentFile;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.hjq.permissions.OnPermissionCallback;
import com.hjq.permissions.XXPermissions;
import com.kongzue.dialogx.dialogs.BottomMenu;
import java.io.File;
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import io.reactivex.Observable;
@ -52,13 +44,11 @@ import xyz.fycz.myreader.ui.activity.BookSourceActivity;
import xyz.fycz.myreader.ui.activity.SourceEditActivity;
import xyz.fycz.myreader.ui.adapter.BookSourceAdapter;
import xyz.fycz.myreader.ui.adapter.helper.ItemTouchCallback;
import xyz.fycz.myreader.ui.adapter.helper.OnStartDragListener;
import xyz.fycz.myreader.ui.dialog.DialogCreator;
import xyz.fycz.myreader.ui.dialog.LoadingDialog;
import xyz.fycz.myreader.ui.dialog.MyAlertDialog;
import xyz.fycz.myreader.util.ShareUtils;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.UriFileUtil;
import xyz.fycz.myreader.util.utils.ClipBoardUtil;
import xyz.fycz.myreader.util.utils.DocumentUtil;
import xyz.fycz.myreader.util.utils.FileUtils;
@ -70,7 +60,6 @@ import xyz.fycz.myreader.widget.swipemenu.SwipeMenuLayout;
import static android.app.Activity.RESULT_OK;
import static android.text.TextUtils.isEmpty;
import static xyz.fycz.myreader.util.UriFileUtil.getPath;
/**
* @author fengyue
@ -364,7 +353,7 @@ public class DIYSourceFragment extends BaseFragment {
*/
public void showSourceGroupMenu(View view) {
PopupMenu popupMenu = new PopupMenu(sourceActivity, view, Gravity.END);
List<String> groupList = BookSourceManager.getNoLocalGroupList();
List<String> groupList = BookSourceManager.getGroupList(false);
popupMenu.getMenu().add(0, 0, 0, "所有书源");
for (int i = 0; i < groupList.size(); i++) {
popupMenu.getMenu().add(0, 0, i + 1, groupList.get(i));

@ -3,6 +3,7 @@ package xyz.fycz.myreader.ui.fragment;
import static android.app.Activity.RESULT_OK;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
@ -13,6 +14,8 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -136,6 +139,29 @@ public class MineFragment extends BaseFragment {
binding.tvUser.setText(user.getUserName());
}
binding.tvThemeModeSelect.setText(themeModeArr[themeMode]);
initShowMode();
}
private void initShowMode() {
int showMode = SharedPreUtils.getInstance().getInt("mineShowMode", 0);
switch (showMode){
case 1:
binding.mineLlUser.setVisibility(View.GONE);
binding.mineLlCloud.setVisibility(View.VISIBLE);
break;
case 2:
binding.mineLlUser.setVisibility(View.VISIBLE);
binding.mineLlCloud.setVisibility(View.VISIBLE);
break;
case 3:
binding.mineLlUser.setVisibility(View.GONE);
binding.mineLlCloud.setVisibility(View.GONE);
break;
default:
binding.mineLlUser.setVisibility(View.VISIBLE);
binding.mineLlCloud.setVisibility(View.GONE);
break;
}
}
@Override
@ -312,9 +338,10 @@ public class MineFragment extends BaseFragment {
binding.mineRlReadRecord.setOnClickListener(v -> {
startActivity(new Intent(getContext(), ReadRecordActivity.class));
});
binding.mineRlSetting.setOnClickListener(v -> {
Intent settingIntent = new Intent(getActivity(), MoreSettingActivity.class);
startActivity(settingIntent);
Intent intent = new Intent(getActivity(), MoreSettingActivity.class);
startActivityForResult(intent, APPCONST.REQUEST_SETTING);
});
binding.mineRlThemeMode.setOnClickListener(v -> {
/*if (themeModeDia != null) {
@ -586,15 +613,22 @@ public class MineFragment extends BaseFragment {
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (resultCode == RESULT_OK) {
if (data == null) {
return;
}
switch (requestCode) {
case APPCONST.REQUEST_LOGIN:
assert data != null;
isLogin = data.getBooleanExtra("isLogin", false);
user = UserService.INSTANCE.readConfig();
if (isLogin && user != null) {
binding.tvUser.setText(user.getUserName());
}
break;
case APPCONST.REQUEST_SETTING:
if (data.getBooleanExtra(APPCONST.RESULT_NEED_REFRESH, false)){
initShowMode();
}
break;
}
}
}

@ -0,0 +1,202 @@
package xyz.fycz.myreader.ui.fragment
import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle
import android.view.*
import android.widget.PopupMenu
import androidx.recyclerview.widget.LinearLayoutManager
import io.reactivex.Single
import io.reactivex.SingleEmitter
import xyz.fycz.myreader.R
import xyz.fycz.myreader.base.BaseFragment
import xyz.fycz.myreader.base.adapter2.onClick
import xyz.fycz.myreader.base.observer.MySingleObserver
import xyz.fycz.myreader.databinding.FragmentSubscribeSourceBinding
import xyz.fycz.myreader.greendao.DbManager
import xyz.fycz.myreader.greendao.entity.rule.BookSource
import xyz.fycz.myreader.model.sourceAnalyzer.BookSourceManager
import xyz.fycz.myreader.ui.activity.BookSourceActivity
import xyz.fycz.myreader.ui.activity.SourceSubscribeActivity
import xyz.fycz.myreader.ui.adapter.SubscribeSourceAdapter
import xyz.fycz.myreader.ui.dialog.DialogCreator
import xyz.fycz.myreader.util.ToastUtils
import xyz.fycz.myreader.util.utils.RxUtils
import xyz.fycz.myreader.widget.DividerItemDecoration
import java.util.ArrayList
/**
* @author fengyue
* @date 2022/3/3 11:36
*/
class SubscribeSourceFragment(private val sourceActivity: BookSourceActivity) : BaseFragment() {
private lateinit var binding: FragmentSubscribeSourceBinding
private var mBookSources: MutableList<BookSource>? = null
private var mAdapter: SubscribeSourceAdapter? = null
private var featuresMenu: PopupMenu? = null
override fun bindView(inflater: LayoutInflater, container: ViewGroup): View {
binding = FragmentSubscribeSourceBinding.inflate(inflater, container, false)
return binding.root
}
override fun initData(savedInstanceState: Bundle?) {
super.initData(savedInstanceState)
Single.create { emitter: SingleEmitter<List<BookSource>> ->
emitter.onSuccess(BookSourceManager.getAllLocalSource())
}.compose { RxUtils.toSimpleSingle(it) }
.subscribe(object : MySingleObserver<List<BookSource>>() {
override fun onSuccess(sources: List<BookSource>) {
mBookSources = sources.toMutableList()
initSourceList()
}
override fun onError(e: Throwable) {
ToastUtils.showError(" 数据加载失败\n${e.localizedMessage}")
}
})
}
private fun initSourceList() {
mAdapter =
SubscribeSourceAdapter(mBookSources!!, object : SubscribeSourceAdapter.OnDelListener {
override fun onDel(which: Int, source: BookSource) {
mBookSources?.remove(source)
mAdapter?.removeItem(which)
}
})
mAdapter?.setOnItemClickListener { _, pos ->
mAdapter?.setCheckedItem(pos)
}
binding.recyclerView.layoutManager = LinearLayoutManager(context)
binding.recyclerView.adapter = mAdapter
//设置分割线
binding.recyclerView.addItemDecoration(DividerItemDecoration(context))
mAdapter?.refreshItems(mBookSources)
}
override fun initWidget(savedInstanceState: Bundle?) {
super.initWidget(savedInstanceState)
}
override fun initClick() {
super.initClick()
binding.tvSubscribeSource.onClick {
startActivity(Intent(context, SourceSubscribeActivity::class.java))
}
binding.ivGroup.setOnClickListener { view: View? ->
showSourceGroupMenu(view)
}
binding.ivMenu.setOnClickListener { v ->
if (featuresMenu == null) {
initFeaturesMenu(v)
}
featuresMenu?.show()
}
}
/**
* 显示书源分组菜单
*/
private fun showSourceGroupMenu(view: View?) {
val popupMenu = PopupMenu(sourceActivity, view, Gravity.END)
val groupList = BookSourceManager.getGroupList(true)
popupMenu.menu.add(0, 0, 0, "所有书源")
for (i in groupList.indices) {
popupMenu.menu.add(0, 0, i + 1, groupList[i])
}
popupMenu.setOnMenuItemClickListener { menuItem: MenuItem ->
if (menuItem.order > 0) {
sourceActivity.searchView.onActionViewExpanded()
sourceActivity.searchView.clearFocus()
sourceActivity.searchView.setQuery(menuItem.title, false)
} else {
sourceActivity.searchView.onActionViewCollapsed()
}
true
}
popupMenu.show()
}
private fun initFeaturesMenu(view: View) {
featuresMenu = PopupMenu(sourceActivity, view, Gravity.END)
//获取菜单填充器
val inflater = featuresMenu?.menuInflater
//填充菜单
inflater?.inflate(R.menu.menu_subscribe_source, featuresMenu?.menu)
featuresMenu?.setOnMenuItemClickListener { item: MenuItem ->
when (item.itemId) {
R.id.action_select_all -> {
mAdapter?.setCheckedAll(true)
}
R.id.action_reverse_selected -> {
mAdapter?.reverseChecked()
}
R.id.action_reverse_enable_selected -> {
val bookSources =
mAdapter?.checkedBookSources
reverseSources(bookSources)
}
R.id.action_delete_selected -> {
val bookSources =
mAdapter?.checkedBookSources
deleteSources(bookSources, false)
}
}
true
}
}
private fun reverseSources(mBookSources: MutableList<BookSource>?) {
if (mBookSources != null) {
for (source in mBookSources) {
source.enable = !source.enable
}
DbManager.getDaoSession().bookSourceDao.insertOrReplaceInTx(mBookSources)
mAdapter?.notifyDataSetChanged()
}
}
private fun deleteSources(mBookSources: MutableList<BookSource>?, isDisabled: Boolean) {
if (mBookSources == null || mBookSources.size == 0) {
ToastUtils.showWarring("当前没有选择任何书源,无法删除!")
return
}
val title: String
val msg: String
val successTip: String
if (isDisabled) {
title = "删除禁用书源"
msg = "确定要删除所有禁用书源吗?"
successTip = "禁用书源删除成功"
} else {
title = "删除选中书源"
msg = "确定要删除所有选中书源吗?"
successTip = "选中书源删除成功"
}
DialogCreator.createCommonDialog(
sourceActivity, title,
msg, true,
{ _: DialogInterface?, _: Int ->
val sources: MutableList<BookSource> =
ArrayList()
if (isDisabled) {
for (source in mBookSources) {
if (!source.enable) {
sources.add(source)
}
}
} else {
sources.addAll(mBookSources)
}
BookSourceManager.removeBookSources(sources)
mBookSources.removeAll(sources)
mAdapter?.removeItems(sources)
ToastUtils.showSuccess(successTip)
}, null
)
}
fun startSearch(newText: String?) {
mAdapter?.filter?.filter(newText)
}
}

@ -1,7 +1,12 @@
package xyz.fycz.myreader.util.utils;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import com.weaction.ddsdk.ad.DdSdkFlowAd;
import com.weaction.ddsdk.ad.DdSdkInterAd;
import com.weaction.ddsdk.ad.DdSdkRewardAd;
import com.weaction.ddsdk.base.DdSdkHelper;
import com.weaction.ddsdk.bean.DDSDK;
@ -17,7 +22,8 @@ import okhttp3.RequestBody;
import xyz.fycz.myreader.application.App;
import xyz.fycz.myreader.base.observer.MySingleObserver;
import xyz.fycz.myreader.common.URLCONST;
import xyz.fycz.myreader.entity.AdBean;
import xyz.fycz.myreader.entity.ad.AdBean;
import xyz.fycz.myreader.entity.ad.AdConfig;
import xyz.fycz.myreader.model.user.UserService;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.help.DateHelper;
@ -29,20 +35,26 @@ import xyz.fycz.myreader.util.help.DateHelper;
public class AdUtils {
public static final String TAG = AdUtils.class.getSimpleName();
private static boolean hasInitAd = false;
private static AdBean adConfig;
private static AdConfig adConfig;
static {
String config = SharedPreUtils.getInstance(true).getString("adConfig");
adConfig = GsonExtensionsKt.getGSON().fromJson(config, AdBean.class);
String config = getSp().getString("adConfig");
adConfig = GsonExtensionsKt.getGSON().fromJson(config, AdConfig.class);
if (adConfig == null || adConfig.getBackAdTime() == 0) {
adConfig = new AdBean(false, 20, 60);
adConfig = new AdConfig(false, 60, 20,
60, 6, 3, 48);
}
}
public static SharedPreUtils getSp() {
return SharedPreUtils.getInstance(true);
}
public static Single<Boolean> checkHasAd() {
initAd();
return Single.create((SingleOnSubscribe<Boolean>) emitter -> {
boolean hasAd = false;
if (!adConfig.isCloud()) {
if (!adConfig.isCloud() || isExpire()) {
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
String body = "type=adConfig" + UserService.INSTANCE.makeAuth();
RequestBody requestBody = RequestBody.create(mediaType, body);
@ -57,12 +69,13 @@ public class AdUtils {
}
} else {
String res = jsonObject.getString("result");
SharedPreUtils.getInstance(true).putString("adConfig", res);
adConfig = GsonExtensionsKt.getGSON().fromJson(res, AdBean.class);
adConfig = GsonExtensionsKt.getGSON().fromJson(res, AdConfig.class);
adConfig.setCloud(true);
hasAd = adConfig.isHasAd();
getSp().putString("adConfig", res);
getSp().putLong("adConfigTime", System.currentTimeMillis());
}
Log.i(TAG, "hasAd:" + hasAd);
Log.i(TAG, "adConfig:" + adConfig);
} catch (JSONException e) {
e.printStackTrace();
}
@ -140,25 +153,152 @@ public class AdUtils {
}
public static void backTime() {
SharedPreUtils.getInstance(true).putLong("backTime", System.currentTimeMillis());
getSp().putLong("backTime", System.currentTimeMillis());
}
public static boolean backSplashAd() {
if (!adConfig.isHasAd()) return false;
SharedPreUtils sp = SharedPreUtils.getInstance(true);
Long splashAdTime = sp.getLong("splashAdTime");
Long backTime = sp.getLong("backTime");
Long currentTime = System.currentTimeMillis();
long splashAdTime = getSp().getLong("splashAdTime");
long backTime = getSp().getLong("backTime");
long currentTime = System.currentTimeMillis();
Log.d(TAG, "currentTime - splashAdTime=" + (currentTime - splashAdTime));
Log.d(TAG, "currentTime - backTime=" + (currentTime - splashAdTime));
Log.d(TAG, "adConfig.getIntervalAdTime()=" + (adConfig.getIntervalAdTime() * 60L * 1000));
Log.d(TAG, "adConfig.getBackAdTime()=" + (adConfig.getBackAdTime() * 60L * 1000));
return currentTime - splashAdTime >= adConfig.getIntervalAdTime() * 60L * 1000 ||
currentTime - backTime >= adConfig.getBackAdTime() * 60L * 1000;
}
public static AdBean getAdConfig() {
private static boolean isExpire() {
long adConfigTime = getSp().getLong("adConfigTime");
long currentTime = System.currentTimeMillis();
return currentTime - adConfigTime >= adConfig.getExpireTime() * 60L * 1000;
}
public static boolean adTime(String adTag, AdBean adBean){
if (adBean.getStatus() == 0) return false;
long adTime = getSp().getLong(adTag + "Time");
long currentTime = System.currentTimeMillis();
return currentTime - adTime >= adBean.getInterval() * 60L * 1000;
}
/**
* @param activity
* @param type 1小4中
* @param flowAd
*/
public static void getFlowAd(Activity activity, int type, FlowAd flowAd, String adTag) {
try {
new DdSdkFlowAd().getFlowViews(activity, type, new DdSdkFlowAd.FlowCallback() {
// 信息流广告拉取完毕后返回的 views
@Override
public void getFlowView(View view) {
flowAd.getView(view);
}
// 信息流广告展示后调用
@Override
public void show() {
AdUtils.adRecord("flow", "adShow");
Log.d(TAG, "信息流广告展示成功");
if (adTag != null) {
getSp().putLong(adTag + "Time", System.currentTimeMillis());
}
}
// 广告拉取失败调用
@Override
public void error(String msg) {
Log.d(TAG, "广告拉取失败\n" + msg);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
public static void showInterAd(Activity activity, String adTag) {
/*
* 参数 1 activity
* 参数 2 marginDp (float)插屏默认 margin 全屏幕的 24dp此处允许开发者手动调节 margin 大小单位为 dp允许范围为 0dp (全屏) ~ 48dp请开发者按需填写
*/
try {
DdSdkInterAd.show(activity, 48f, new DdSdkInterAd.Callback() {
@Override
public void show() {
Log.i(TAG, "插屏广告展示成功");
AdUtils.adRecord("inter", "adShow");
if (adTag != null) {
getSp().putLong(adTag + "Time", System.currentTimeMillis());
}
}
@Override
public void click() {
Log.i(TAG, "插屏广告");
AdUtils.adRecord("inter", "adClick");
}
@Override
public void error(String msg) {
}
@Override
public void close() {
Log.i(TAG, "插屏广告被关闭");
AdUtils.adRecord("inter", "adClose");
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
public static void showRewardVideoAd(Activity activity, RewardAd rewardAd) {
try {
DdSdkRewardAd.show(activity, new DdSdkRewardAd.DdSdkRewardCallback() {
@Override
public void show() {
Log.i(TAG, "激励视频展示成功");
AdUtils.adRecord("rewardVideo", "adShow");
}
@Override
public void click() {
Log.i(TAG, "激励视频被点击");
AdUtils.adRecord("rewardVideo", "adClick");
}
@Override
public void error(String msg) {
}
@Override
public void skip() {
Log.i(TAG, "激励视频被跳过");
AdUtils.adRecord("rewardVideo", "adSkip");
}
@Override
public void reward() {
if (rewardAd != null) {
rewardAd.reward();
}
Log.i(TAG, "激励视频计时完成");
AdUtils.adRecord("rewardVideo", "adFinishCount");
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
public static AdConfig getAdConfig() {
return adConfig;
}
public static void initAd() {
/*if (!hasInitAd) {
if (!hasInitAd) {
hasInitAd = true;
DdSdkHelper.init(new DDSDK.Builder()
.setUserId("1234")
@ -167,18 +307,17 @@ public class AdUtils {
.setCsjAppId("5273043")
.setApp(App.getApplication())
.setShowLog(App.isDebug())
.setCustomRequestPermission(true)
.create()
);
}*/
DdSdkHelper.init(new DDSDK.Builder()
.setUserId("1234")
.setAppId("216")
.setAppKey("51716a16fbdf50905704b6575b1b3b60")
.setCsjAppId("5273043")
.setApp(App.getApplication())
.setShowLog(App.isDebug())
.setCustomRequestPermission(true)
.create()
);
}
}
public interface FlowAd {
void getView(View view);
}
public interface RewardAd {
void reward();
}
}

@ -41,6 +41,7 @@ import xyz.fycz.myreader.entity.StrResponse;
import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.greendao.service.CookieStore;
import xyz.fycz.myreader.model.third2.analyzeRule.AnalyzeUrl;
import xyz.fycz.myreader.model.third3.http.HttpHelperKt;
import static xyz.fycz.myreader.util.help.SSLSocketClient.createSSLSocketFactory;
import static xyz.fycz.myreader.util.help.SSLSocketClient.createTrustAllManager;
@ -48,22 +49,8 @@ import static xyz.fycz.myreader.util.help.SSLSocketClient.getHeaderInterceptor;
public class OkHttpUtils {
public static OkHttpClient mClient;
public static synchronized OkHttpClient getOkHttpClient() {
if (mClient == null) {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(5, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.sslSocketFactory(createSSLSocketFactory(), createTrustAllManager())
.hostnameVerifier((hostname, session) -> true)
.protocols(Collections.singletonList(Protocol.HTTP_1_1))
.addInterceptor(getHeaderInterceptor());
mClient = builder
.build();
}
return mClient;
public static OkHttpClient getOkHttpClient() {
return HttpHelperKt.getOkHttpClient();
}
/**

@ -67,7 +67,7 @@ public class ShareBookUtil {
ToastUtils.showInfo("正在生成分享图片");
Single.create((SingleOnSubscribe<File>) emitter -> {
// 使用url
String url = SharedPreUtils.getInstance().getString(context.getString(R.string.downloadLink), URLCONST.LAN_ZOUS_URL);
String url = SharedPreUtils.getInstance().getString(context.getString(R.string.downloadLink), URLCONST.LAN_ZOU_URL);
if (url == null)
url = "";

@ -1,35 +1,94 @@
package xyz.fycz.myreader.webapi
import android.util.Log
import com.google.gson.JsonParser
import io.reactivex.Observable
import kotlinx.coroutines.runBlocking
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
import org.jsoup.Jsoup
import xyz.fycz.myreader.common.URLCONST
import xyz.fycz.myreader.entity.LanZouBean
import xyz.fycz.myreader.entity.lanzou.LanZouFile
import xyz.fycz.myreader.entity.lanzou.LanZouParseBean
import xyz.fycz.myreader.model.third3.Coroutine
import xyz.fycz.myreader.model.third3.http.getProxyClient
import xyz.fycz.myreader.model.third3.http.newCallResponseBody
import xyz.fycz.myreader.model.third3.http.postForm
import xyz.fycz.myreader.model.third3.http.text
import xyz.fycz.myreader.util.ToastUtils
import xyz.fycz.myreader.util.help.StringHelper
import xyz.fycz.myreader.util.utils.GSON
import xyz.fycz.myreader.util.utils.OkHttpUtils
import xyz.fycz.myreader.util.utils.fromJsonObject
import xyz.fycz.myreader.util.utils.splitNotBlank
import xyz.fycz.myreader.util.utils.*
import java.lang.Exception
import java.net.HttpURLConnection
import java.net.URL
import java.util.*
import kotlin.collections.HashMap
/**
* @author fengyue
* @date 2022/1/22 18:50
*/
object LanZouApi {
private val paramCathe = mutableMapOf<String, HashMap<String, Any>>()
fun getUrl(url: String): Observable<String> {
fun getFoldFiles(
foldUrl: String,
page: Int,
pwd: String? = null
): Coroutine<List<LanZouFile>?> {
return Coroutine.async {
val params = if (page == 1) {
getFoldParams(OkHttpUtils.getHtml(foldUrl), page, pwd)
} else {
paramCathe[foldUrl] ?: getFoldParams(OkHttpUtils.getHtml(foldUrl), page, pwd)
}
params["pg"] = page
paramCathe[foldUrl] = params
val res = getProxyClient().newCallResponseBody {
url(URLCONST.LAN_ZOU_URL + "/filemoreajax.php")
postForm(params)
}.text()
Log.d("getFoldFiles", params.toString())
val json = JsonParser.parseString(res).asJsonObject
val zt = json["zt"].asInt
val info = json["info"].asString
if (zt == 1) {
val file = json["text"].toString()
GSON.fromJsonArray(file)
} else {
throw Exception(info)
}
}
}
private fun getFoldParams(html: String, page: Int, pwd: String? = null): HashMap<String, Any> {
val params = HashMap<String, Any>()
params["lx"] = 2
params["pg"] = page
params["fid"] = StringUtils.getSubString(html, "'fid':", ",")
params["uid"] = StringUtils.getSubString(html, "'uid':'", "',")
params["rep"] = 0
val t = StringUtils.getSubString(html, "'t':", ",")
val k = StringUtils.getSubString(html, "'k':", ",")
params["t"] = StringUtils.getSubString(html, "var $t = '", "';")
params["k"] = StringUtils.getSubString(html, "var $k = '", "';")
params["up"] = 1
pwd?.let {
params["ls"] = 1
params["pwd"] = pwd
}
return params
}
fun getFileUrl(url: String): Observable<String> {
url.replace("\\s".toRegex(), "").let {
val regex = ",|,|密码:".toRegex()
if (it.contains(regex)) {
it.split(regex).let { arr ->
return getUrl(arr[0], arr[1])
return getFileUrl(arr[0], arr[1])
}
} else {
return getUrl(it, "")
return getFileUrl(it, "")
}
}
}
@ -40,7 +99,7 @@ object LanZouApi {
* @param url
* @param password
*/
private fun getUrl(url: String, password: String = ""): Observable<String> {
private fun getFileUrl(url: String, password: String = ""): Observable<String> {
return Observable.create {
val html = OkHttpUtils.getHtml(url)
val url2 = if (password.isEmpty()) {
@ -61,7 +120,7 @@ object LanZouApi {
private fun getUrl1(html: String): String {
val doc = Jsoup.parse(html)
return URLCONST.LAN_ZOUS_URL + doc.getElementsByTag("iframe").attr("src")
return URLCONST.LAN_ZOU_URL + doc.getElementsByTag("iframe").attr("src")
}
private fun getKey(html: String): String {
@ -89,7 +148,7 @@ object LanZouApi {
headers["Referer"] = referer
val html = OkHttpUtils.getHtml(
URLCONST.LAN_ZOUS_URL + "/ajaxm.php", requestBody,
URLCONST.LAN_ZOU_URL + "/ajaxm.php", requestBody,
"UTF-8", headers
)
return getUrl2(html)
@ -105,7 +164,7 @@ object LanZouApi {
var url = info[2].substring(info[2].indexOf(":") + 2, info[2].lastIndexOf("\""))
dom = dom.replace("\\", "")
url = url.replace("\\", "")*/
val lanZouBean = GSON.fromJsonObject<LanZouBean>(o)
val lanZouBean = GSON.fromJsonObject<LanZouParseBean>(o)
lanZouBean?.run {
return if (zt == 1) {
"$dom/file/$url"

@ -133,7 +133,7 @@ public class LanZousApi {
HashMap<String, String> headers = new HashMap<>();
headers.put("Referer", referer);
String html = OkHttpUtils.getHtml(URLCONST.LAN_ZOUS_URL + "/ajaxm.php", requestBody,
String html = OkHttpUtils.getHtml(URLCONST.LAN_ZOU_URL + "/ajaxm.php", requestBody,
"UTF-8", headers);
emitter.onSuccess(getUrl2(html));
}).compose(RxUtils::toSimpleSingle).subscribe(new MySingleObserver<String>() {
@ -151,7 +151,7 @@ public class LanZousApi {
private static String getUrl1(String html) {
Document doc = Jsoup.parse(html);
return URLCONST.LAN_ZOUS_URL + doc.getElementsByClass("ifr2").attr("src");
return URLCONST.LAN_ZOU_URL + doc.getElementsByClass("ifr2").attr("src");
}
private static String getKey(String html) {

@ -208,6 +208,9 @@ public class ReadCrawlerUtil {
return new BaseSourceCrawlerNoInfo(crawler);
}
} else {
if (THIRD_3_SOURCE.equals(source.getSourceType())) {
return new Third3Crawler(source);
}
Class clz = Class.forName(source.getSourceUrl());
return (ReadCrawler) clz.newInstance();
}

@ -49,6 +49,32 @@
android:textColor="@color/textAssist" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_mine_show"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="@drawable/selector_common_bg"
android:orientation="vertical"
android:paddingLeft="20dp"
android:paddingTop="8dp"
android:paddingRight="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/mine_show_mode"
android:textColor="@color/textSecondary"
android:textSize="@dimen/text_normal_size" />
<TextView
android:id="@+id/tv_mine_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:text="@string/show_user_only"
android:textColor="@color/textAssist" />
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="25dp"

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/toolbar" />
<xyz.fycz.myreader.widget.RefreshLayout
android:id="@+id/loading"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.scwang.smartrefresh.layout.SmartRefreshLayout
android:id="@+id/srl_files"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants">
<com.scwang.smartrefresh.header.MaterialHeader
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_files"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.scwang.smartrefresh.layout.footer.ClassicsFooter
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:srlAccentColor="@color/textSecondary"
app:srlTextFailed="@string/loading_tip"
app:srlTextLoading="@string/loading_tip"
app:srlTextNothing="总得有个结尾吧" />
</com.scwang.smartrefresh.layout.SmartRefreshLayout>
</xyz.fycz.myreader.widget.RefreshLayout>
</LinearLayout>

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorBackground"
@ -13,13 +12,18 @@
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
<LinearLayout
android:id="@+id/mine_ll_user"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="25dp"
android:paddingLeft="5dp"
android:paddingRight="5dp">
<TextView
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
@ -27,8 +31,8 @@
android:textColor="@color/textPrimary"
android:text="用户"/>
</RelativeLayout>
<RelativeLayout
</RelativeLayout>
<RelativeLayout
android:id="@+id/mine_rl_user"
android:layout_width="match_parent"
android:layout_height="50dp"
@ -36,7 +40,7 @@
android:paddingRight="20dp"
android:background="@drawable/selector_common_bg">
<ImageView
<ImageView
android:id="@+id/iv_user"
android:layout_alignParentStart="true"
android:layout_width="wrap_content"
@ -44,124 +48,134 @@
android:layout_centerVertical="true"
app:tint="@color/textPrimary"
android:src="@drawable/ic_user"
/>
/>
<TextView
android:id="@+id/tv_user"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="15dp"
android:layout_toEndOf="@id/iv_user"
android:text="登录/注册"
android:textColor="@color/textSecondary"
android:textSize="@dimen/text_normal_size" />
<TextView
android:id="@+id/tv_user"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="15dp"
android:layout_toEndOf="@id/iv_user"
android:text="登录/注册"
android:textColor="@color/textSecondary"
android:textSize="@dimen/text_normal_size" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/mine_rl_syn"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/selector_common_bg"
android:paddingLeft="20dp"
android:paddingRight="20dp">
</RelativeLayout>
<RelativeLayout
android:id="@+id/mine_rl_syn"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/selector_common_bg"
android:paddingLeft="20dp"
android:paddingRight="20dp">
<ImageView
android:id="@+id/iv_syn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_online_syn"
app:tint="@color/textPrimary" />
<ImageView
android:id="@+id/iv_syn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_online_syn"
app:tint="@color/textPrimary" />
<TextView
android:id="@+id/tv_syn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="15dp"
android:layout_toEndOf="@id/iv_syn"
android:text="@string/menu_bookcase_syn"
android:textColor="@color/textSecondary"
android:textSize="@dimen/text_normal_size" />
<TextView
android:id="@+id/tv_syn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="15dp"
android:layout_toEndOf="@id/iv_syn"
android:text="@string/menu_bookcase_syn"
android:textColor="@color/textSecondary"
android:textSize="@dimen/text_normal_size" />
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
<LinearLayout
android:id="@+id/mine_ll_cloud"
android:layout_width="match_parent"
android:layout_height="25dp"
android:paddingLeft="5dp"
android:paddingRight="5dp">
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="25dp"
android:paddingLeft="5dp"
android:paddingRight="5dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerInParent="true"
android:text="WebDav云服务"
android:textColor="@color/textPrimary" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerInParent="true"
android:text="WebDav云服务"
android:textColor="@color/textPrimary" />
</RelativeLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/mine_rl_webdav"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/selector_common_bg"
android:paddingLeft="20dp"
android:paddingRight="20dp">
<RelativeLayout
android:id="@+id/mine_rl_webdav"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/selector_common_bg"
android:paddingLeft="20dp"
android:paddingRight="20dp">
<ImageView
android:id="@+id/iv_webdav"
android:layout_width="21dp"
android:layout_height="21dp"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_yun"
app:tint="@color/textPrimary" />
<ImageView
android:id="@+id/iv_webdav"
android:layout_width="21dp"
android:layout_height="21dp"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_yun"
app:tint="@color/textPrimary" />
<TextView
android:id="@+id/tv_webdav"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="18dp"
android:layout_toEndOf="@id/iv_webdav"
android:text="@string/webdav_setting"
android:textColor="@color/textSecondary"
android:textSize="@dimen/text_normal_size" />
<TextView
android:id="@+id/tv_webdav"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="18dp"
android:layout_toEndOf="@id/iv_webdav"
android:text="@string/webdav_setting"
android:textColor="@color/textSecondary"
android:textSize="@dimen/text_normal_size" />
</RelativeLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/mine_rl_syn_webdav"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/selector_common_bg"
android:paddingLeft="20dp"
android:paddingRight="20dp">
<RelativeLayout
android:id="@+id/mine_rl_syn_webdav"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/selector_common_bg"
android:paddingLeft="20dp"
android:paddingRight="20dp">
<ImageView
android:id="@+id/iv_syn_webdav"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_restore"
app:tint="@color/textPrimary" />
<ImageView
android:id="@+id/iv_syn_webdav"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_restore"
app:tint="@color/textPrimary" />
<TextView
android:id="@+id/tv_syn_webdav"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="15dp"
android:layout_toEndOf="@id/iv_syn_webdav"
android:text="@string/webdav_restore_tip"
android:textColor="@color/textSecondary"
android:textSize="@dimen/text_normal_size" />
<TextView
android:id="@+id/tv_syn_webdav"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="15dp"
android:layout_toEndOf="@id/iv_syn_webdav"
android:text="@string/webdav_restore_tip"
android:textColor="@color/textSecondary"
android:textSize="@dimen/text_normal_size" />
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorForeground"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="35dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_subscribe_source"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:text="@string/subscribe_source"
android:textColor="@color/colorAccent"
android:textSize="@dimen/text_small_size" />
<TextView
android:id="@+id/tv_subscribe_source_tip"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:text="@string/subscribe_source_tip"
android:textColor="@color/colorAccent"
android:textSize="@dimen/text_small_size" />
</LinearLayout>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_group"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_toStartOf="@+id/iv_menu"
android:background="?android:attr/selectableItemBackground"
android:paddingStart="5dp"
android:paddingEnd="5dp"
app:srcCompat="@drawable/ic_filter"
app:tint="@color/colorAccent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_menu"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:layout_gravity="end"
android:background="?android:attr/selectableItemBackground"
android:paddingStart="5dp"
android:paddingEnd="5dp"
app:srcCompat="@drawable/ic_menu"
app:tint="@color/colorAccent" />
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/colorBackground" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<xyz.fycz.myreader.widget.scroller.FastScrollRecyclerView
android:id="@+id/recycler_view"
android:background="@color/colorForeground"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
</LinearLayout>

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:paddingHorizontal="5dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingVertical="10dp"
android:paddingHorizontal="5dp">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_file_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/textPrimary"
android:textSize="@dimen/text_normal_size" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_file_size_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/textSecondary"
android:textSize="@dimen/text_small_size" />
</LinearLayout>
<View
android:layout_width="fill_parent"
android:layout_height="0.5dp"
android:background="@color/sys_window_back" />
</LinearLayout>

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:paddingStart="10dp"
android:paddingEnd="10dp">
<androidx.appcompat.widget.AppCompatCheckBox
android:id="@+id/cb_source"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_toStartOf="@+id/tv_enable"
android:clickable="false"
android:textColor="@color/textPrimary"
android:ellipsize="end"
android:maxLines="2"
android:textSize="@dimen/text_normal_size" />
<TextView
android:id="@+id/tv_enable"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_toStartOf="@+id/tv_disable"
android:background="?android:attr/selectableItemBackground"
android:gravity="center"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/enable_use"
android:textColor="@color/textSecondary"
android:textSize="@dimen/text_small_size" />
<TextView
android:id="@+id/tv_disable"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_toStartOf="@+id/tv_delete"
android:background="?android:attr/selectableItemBackground"
android:gravity="center"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/ban"
android:textColor="@color/textSecondary"
android:textSize="@dimen/text_small_size" />
<TextView
android:id="@+id/tv_delete"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:background="?android:attr/selectableItemBackground"
android:gravity="center"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:text="@string/delete"
android:textColor="@color/textSecondary"
android:textSize="@dimen/text_small_size" />
</RelativeLayout>

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_select_all"
android:title="@string/select_all" />
<item
android:id="@+id/action_reverse_selected"
android:title="@string/reverse_selected" />
<item
android:id="@+id/action_reverse_enable_selected"
android:title="@string/reverse_enable_selected" />
<item
android:id="@+id/action_delete_selected"
android:title="@string/delete_selected" />
</menu>

@ -434,7 +434,9 @@
<string name="check">校验</string>
<string name="new_source">新建书源</string>
<string name="import_source">导入书源</string>
<string name="subscribe_source">书源订阅</string>
<string name="source_tip">书源说明</string>
<string name="subscribe_source_tip">订阅书源说明</string>
<string name="cancle_select_all">取消全选</string>
<string name="delete_ban_source">删除禁用书源</string>
<string name="reverse_source">反转书源可用性</string>
@ -526,6 +528,13 @@
<string name="clear_search">清除搜索记录</string>
<string name="fold">收起</string>
<string name="unfold">展开</string>
<string name="copy_source">拷贝书源</string>
<string name="lan_zou_parse">蓝奏云直链解析</string>
<string name="mine_show_mode">我的界面显示方式</string>
<string name="show_user_only">仅显示用户</string>
<string name="show_cloud_only">仅显示云服务</string>
<string name="show_user_cloud">显示用户及云服务</string>
<string name="hide_user_cloud">隐藏用户及云服务</string>
<!--error string start-->
@ -541,10 +550,9 @@
<string name="net_error_10001">没有网络</string>
<string name="net_error_10002">网络连接超时</string>
<string name="net_error_10003">数据解析失败</string>
<string name="copy_source">拷贝书源</string>
<string name="lan_zou_parse">蓝奏云直链解析</string>
<!--error string end-->
<string-array name="reset_screen_time">
<item>跟随系统</item>
<item>常亮</item>
@ -634,4 +642,11 @@
<item>默认路径</item>
<item>系统文件夹选择器</item>
</string-array>
<string-array name="mine_show">
<item>@string/show_user_only</item>
<item>@string/show_cloud_only</item>
<item>@string/show_user_cloud</item>
<item>@string/hide_user_cloud</item>
</string-array>
</resources>

Loading…
Cancel
Save