多渠道打包及主API过期策略

This commit is contained in:
mwang 2019-05-18 23:02:33 +08:00
parent 58f9f26eca
commit 65d75da6db
50 changed files with 810 additions and 249 deletions

View File

@ -2,6 +2,14 @@ apply plugin: 'com.android.application'
//apply plugin: 'com.jakewharton.butterknife'
// apply plugin: 'com.neenbedankt.android-apt'
android {
signingConfigs {
releaseConfig {
keyAlias 'key0'
keyPassword 'hello123'
storeFile file('E:/reading/android/asProjects/zhuike/mykeystore.jks')
storePassword 'hello123'
}
}
compileSdkVersion 28
buildToolsVersion "28.0.3"
defaultConfig {
@ -22,14 +30,15 @@ android {
renderscriptSupportModeEnabled true //blurkit
multiDexEnabled true //65535
manifestPlaceholders = [UMENG_CHANNEL_CALUE:"umeng"] //uMeng
// flavorDimensions "default" //debug时注销
manifestPlaceholders = [UMENG_CHANNEL_CALUE: "umeng"] //uMeng
// flavorDimensions "default" //debug时注销
}
buildTypes {
debug {
// Log
buildConfigField "boolean", "LOG_DEBUG", "true"
buildConfigField "String", "MAIN_HOST", '"http://xiaoshuofenxiang.com/api/"'
buildConfigField "String", "API_HOST", '"{\\"master\\":[\\"http:\\\\/\\\\/xiaoshuofenxiang.com\\"],\\"page\\":[\\"http:\\\\/\\\\/p.xiaoshuofenxiang.com\\"],\\"report\\":[\\"http:\\\\/\\\\/r.xiaoshuofenxiang.com\\"],\\"search\\":[\\"http:\\\\/\\\\/s.xiaoshuofenxiang.com\\"],\\"novel\\":[\\"http:\\\\/\\\\/n.xiaoshuofenxiang.com\\"],\\"novelsbydot\\":[\\"http:\\\\/\\\\/nbd.xiaoshuofenxiang.com\\"],\\"user\\":[\\"http:\\\\/\\\\/u.xiaoshuofenxiang.com\\"]}"'
versionNameSuffix "-debug"
minifyEnabled false
zipAlignEnabled false
@ -43,47 +52,64 @@ android {
minifyEnabled true
//Zipalign优化
zipAlignEnabled true
// resource文件
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
/* applicationVariants.all{ variant ->
variant.outputs.all{ output ->
/* applicationVariants.all { variant ->
variant.outputs.all { output ->
def outFile = output.outputFile
if (outFile != null && outFile.name.endsWith(".apk")){
def fileName = "${variant.productFlavors[0].name}" + "${releaseTime()}" + ".apk"
outputFileName = fileName;
// output.outputFile = new File(outFile.parent, fileName);
if (outFile != null && outFile.name.endsWith(".apk")) {
def fileName = "${variant.productFlavors[0].name}" + "-${defaultConfig.versionName}-" + "${releaseTime()}" + ".apk"
outputFileName = fileName;
}
}
}*/
signingConfig signingConfigs.releaseConfig
}
}
//
/* productFlavors {
// googleplay {}
huawei { applicationId "com.novelbook.android.huawei"
versionName "version-a-1.0"}
xiaomi { applicationId "com.novelbook.android.xiaomi"
versionName "version-a-1.0"}
//
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
//
/* productFlavors {
// googleplay {}
A {
applicationId "com.novelbook.android.a"
versionName "version-a-1.0"
buildConfigField "String", "MAIN_HOST", '"http://xiaoshuofenxiang.com/api/"'
buildConfigField "String", "API_HOST", '"{\\"master\\":[\\"http:\\\\/\\\\/xiaoshuofenxiang.com\\"],\\"page\\":[\\"http:\\\\/\\\\/p.xiaoshuofenxiang.com\\"],\\"report\\":[\\"http:\\\\/\\\\/r.xiaoshuofenxiang.com\\"],\\"search\\":[\\"http:\\\\/\\\\/s.xiaoshuofenxiang.com\\"],\\"novel\\":[\\"http:\\\\/\\\\/n.xiaoshuofenxiang.com\\"],\\"novelsbydot\\":[\\"http:\\\\/\\\\/nbd.xiaoshuofenxiang.com\\"],\\"user\\":[\\"http:\\\\/\\\\/u.xiaoshuofenxiang.com\\"]}"'
}
*/
B {
applicationId "com.novelbook.android.b"
versionName "version-b-1.0"
buildConfigField "String", "MAIN_HOST", '"http://xiaoshuofenxiang.com/api/"'
buildConfigField "String", "API_HOST", '"{\\"master\\":[\\"http:\\\\/\\\\/xiaoshuofenxiang.com\\"],\\"page\\":[\\"http:\\\\/\\\\/p.xiaoshuofenxiang.com\\"],\\"report\\":[\\"http:\\\\/\\\\/r.xiaoshuofenxiang.com\\"],\\"search\\":[\\"http:\\\\/\\\\/s.xiaoshuofenxiang.com\\"],\\"novel\\":[\\"http:\\\\/\\\\/n.xiaoshuofenxiang.com\\"],\\"novelsbydot\\":[\\"http:\\\\/\\\\/nbd.xiaoshuofenxiang.com\\"],\\"user\\":[\\"http:\\\\/\\\\/u.xiaoshuofenxiang.com\\"]}"'
}
C {
applicationId "com.novelbook.android.c"
versionName "version-c-1.0"
buildConfigField "String", "MAIN_HOST", '"http://xiaoshuofenxiang.com/api/"'
buildConfigField "String", "API_HOST", '"{\\"master\\":[\\"http:\\\\/\\\\/xiaoshuofenxiang.com\\"],\\"page\\":[\\"http:\\\\/\\\\/p.xiaoshuofenxiang.com\\"],\\"report\\":[\\"http:\\\\/\\\\/r.xiaoshuofenxiang.com\\"],\\"search\\":[\\"http:\\\\/\\\\/s.xiaoshuofenxiang.com\\"],\\"novel\\":[\\"http:\\\\/\\\\/n.xiaoshuofenxiang.com\\"],\\"novelsbydot\\":[\\"http:\\\\/\\\\/nbd.xiaoshuofenxiang.com\\"],\\"user\\":[\\"http:\\\\/\\\\/u.xiaoshuofenxiang.com\\"]}"'
}
D {
applicationId "com.novelbook.android.d"
versionName "version-d-1.0"
buildConfigField "String", "MAIN_HOST", '"http://xiaoshuofenxiang.com/api/"'
buildConfigField "String", "API_HOST", '"{\\"master\\":[\\"http:\\\\/\\\\/xiaoshuofenxiang.com\\"],\\"page\\":[\\"http:\\\\/\\\\/p.xiaoshuofenxiang.com\\"],\\"report\\":[\\"http:\\\\/\\\\/r.xiaoshuofenxiang.com\\"],\\"search\\":[\\"http:\\\\/\\\\/s.xiaoshuofenxiang.com\\"],\\"novel\\":[\\"http:\\\\/\\\\/n.xiaoshuofenxiang.com\\"],\\"novelsbydot\\":[\\"http:\\\\/\\\\/nbd.xiaoshuofenxiang.com\\"],\\"user\\":[\\"http:\\\\/\\\\/u.xiaoshuofenxiang.com\\"]}"'
}
//
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
}*/
android {
lintOptions {
abortOnError false
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
@ -94,12 +120,11 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
}
}
def releaseTime() {
return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
return new Date().format("yyyyMMdd", TimeZone.getTimeZone("UTC"))
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:28.0.0'

View File

@ -43,6 +43,7 @@
android:label="@string/title_Activity_ChgSource" />
<activity
android:name=".BookActivity"
android:label="@string/title_activity_book"
android:theme="@style/ToolBarTheme.NoActionBar" />
<activity
@ -52,6 +53,7 @@
<activity
android:name=".Main2Activity"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:theme="@style/ToolBarTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -84,7 +86,9 @@
<!-- UMENG -->
<meta-data android:value="5cd6238a570df375c3000cc9" android:name="UMENG_APPKEY"/>
<!--<meta-data android:name="UMENG_CHANNEL" android:value="${UMENG_CHANNEL_VALUE}"/>-->
<meta-data android:value="debug" android:name="UMENG_CHANNEL"/>
<!-- <meta-data android:name="MAINHOST" android:value="${main_host}"/>
<meta-data android:name="DEFAULTHOST" android:value="${default_host}"/>-->
</application>
</manifest>

View File

@ -2,7 +2,7 @@
<litepal>
<dbname value="book" ></dbname>
<version value="15" ></version>
<version value="16" ></version>
<list>
<mapping class="com.novelbook.android.db.Chapter"></mapping>

View File

@ -1,6 +1,7 @@
package com.novelbook.android;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
@ -42,8 +43,9 @@ public class Activity_ChgSource extends Activity_base {
public final static String EXTR_ID="id";
public final static String EXTR_SITE="site";
//public static final String EXTR_NAME ="" ;
public final static String EXTR_cate ="cate";
PageFactory pageFactory;
boolean isFromCate;
List<Site> mSites;
@Override
@ -69,6 +71,9 @@ public class Activity_ChgSource extends Activity_base {
chaptId = getIntent().getIntExtra(EXTR_ID,1);
domain = getIntent().getStringExtra(EXTR_SITE);
isFromCate =getIntent().getBooleanExtra(EXTR_cate,false);
// name = getIntent().getStringExtra(EXTR_NAME);
this.setTitle(chaptTitle);
}
@ -84,8 +89,15 @@ public class Activity_ChgSource extends Activity_base {
Site site = mSites.get(position);
Log.d(TAG, String.format("changing Source:target site name %s, site domain %s " ,site.getName(), site.getDomain()));
pageFactory.changeSource(site.getName(),site.getDomain(),chaptId,chaptTitle);
if(isFromCate){
pageFactory.changeSourceForCate(site.getName(),site.getDomain());
Intent intent = new Intent(Activity_ChgSource.this, MarkActivity.class);
// intent.putExtra(Activity_ChgSource.EXTR_NAME, pageFactory.getSite().getName());
startActivity(intent);
}else{
pageFactory.changeSource(site.getName(),site.getDomain(),chaptId,chaptTitle);
}
finish();
}
});

View File

@ -97,6 +97,12 @@ public abstract class Activity_base extends AppCompatActivity {
hideProgress();
// MobclickAgent.onPause(this);
}
protected void closeCurrentActitivty(){
if( this instanceof BookActivity ) {
// return;
}
finish();
}
protected BookListAdapter getBookListAdapter(List<Novel> mDatas,int itemResourceId){
BookListAdapter mAdapter = new BookListAdapter(this ,mDatas,itemResourceId,new OnItemClickListener()
{
@ -107,7 +113,7 @@ public abstract class Activity_base extends AppCompatActivity {
// showBook("射雕" +position);
showBookDetail(mDatas.get(position));
finish();
closeCurrentActitivty();
}
@Override

View File

@ -221,9 +221,11 @@ public class BookActivity extends Activity_base {
return;
}
rvBooklistAuthor.setVisibility(View.VISIBLE);
// mAdapterAuthor = getBookListAdapter(mDataAuthor,R.layout.recycle_list_item_horizon);
// rvBooklistAuthor.setLayoutManager(new LinearLayoutManager(this));
mAdapterAuthor = getBookListAdapter(mDataAuthor,R.layout.recycle_list_item_horizon);
rvBooklistAuthor.setLayoutManager(new LinearLayoutManager(this));
rvBooklistAuthor.setAdapter(mAdapterAuthor);
}
@ -237,10 +239,10 @@ public class BookActivity extends Activity_base {
return;
}
rvBooklistRelated.setVisibility(View.VISIBLE);
mAdapterRelated = getBookListAdapter(mDataRelated,R.layout.recycle_list_item);
rvBooklistRelated.setLayoutManager(new GridLayoutManager(this, Constants.NOVEL_SPAN_CNT));
/* mAdapterRelated = getBookListAdapter(mDataRelated,R.layout.recycle_list_item);
rvBooklistRelated.setLayoutManager(new GridLayoutManager(this, Constants.NOVEL_SPAN_CNT));*/
mAdapterRelated = getBookListAdapter(mDataRelated,R.layout.recycle_list_item_horizon);
rvBooklistRelated.setLayoutManager(new LinearLayoutManager(this));
rvBooklistRelated.setAdapter(mAdapterRelated);
}
/**
@ -707,6 +709,7 @@ void onResponseProcess( String content ,String url){
if( pageFactory.isWorking() && ( pageFactory.getNovle()==null || mNovel.getId() !=pageFactory.getNovle().getId())){
pageFactory.prepareBook(mNovel);
}
setShelfButtonText();
}
// View v =findViewById(R.id.head_img);

View File

@ -3,6 +3,7 @@ package com.novelbook.android.Fragments;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
@ -27,6 +28,7 @@ import butterknife.BindView;
* Created by Administrator on 2016/8/31 0031.
*/
public class BookMarkFragment extends BasicFragment implements MarkActivity.Sortmark{
public static String TAG=BookMarkFragment.class.getSimpleName();
public static final String ARGUMENT = "argument";
@BindView(R.id.lv_bookmark)
@ -51,7 +53,14 @@ public class BookMarkFragment extends BasicFragment implements MarkActivity.Sor
novelId = bundle.getInt(ARGUMENT);
}
bookMarksList = new ArrayList<>();
bookMarksList = LitePal.where("novelId = ? and domain= ?", novelId+"",pageFactory.getSite().getDomain()).order(String.format("id %s",isAsc ?"asc" :"desc")). find(BookMarks.class);
String domain =pageFactory.getSite().getDomain();
if(TextUtils.isEmpty(domain)){
Novel nv = LitePal.find(Novel.class,novelId);
if(nv!=null) {
domain = nv.getDomain();
}
}
bookMarksList = LitePal.where("novelId = ? and domain= ?", novelId+"",domain).order(String.format("id %s",isAsc ?"asc" :"desc")). find(BookMarks.class);
Log.d(TAG, "initData: bookmark size " +bookMarksList.size());
markAdapter = new MarkAdapter(getActivity(), bookMarksList);
lv_bookmark.setAdapter(markAdapter);

View File

@ -154,7 +154,16 @@ public class CatalogFragment extends BasicFragment implements MarkActivity.Sortc
@Override
public void run() {
// ArrayList<Chapter> list =(ArrayList<Chapter>) LitePal.where("novelId=? and domain =? " ,pageFactory.getNovle().getId()+"",pageFactory.getSite().getDomain()).find(Chapter.class);
ArrayList<Chapter> list =(ArrayList<Chapter>) LitePal.where("novelId=? and domain =? " ,pageFactory.getNovle().getId()+"",pageFactory.getNovle().getDomain()).find(Chapter.class);
String domain =pageFactory.getNovle().getDomain();
if(TextUtils.isEmpty(domain)){
domain="";
}
ArrayList<Chapter> list = new ArrayList<Chapter>();
if(!TextUtils.isEmpty(domain)) {
list = (ArrayList<Chapter>) LitePal.where("novelId=? and domain =? ", pageFactory.getNovle().getId() + "", domain).find(Chapter.class);
}
File file;
for(Chapter cp : list){
if(!TextUtils.isEmpty(cp.getChapterPath())) {

View File

@ -62,7 +62,7 @@ import okhttp3.ResponseBody;
public class Fragment_Shelf extends BasicFragment {
public static String TAG=Fragment_Shelf.class.getSimpleName();
public static String getFTag() {
return "com.novelbook.android.Fragments.Fragment_Shelf";
}
@ -448,6 +448,7 @@ void test(int maxAge){
}else{
Log.d(TAG, "shelfZhengliSubmit: to delete novel " + nv.getName());
nv.setToDefault("isOnShelf");
nv.setToDefault("isTop");
//nv.setOnShelf(false);
nv.update(nv.getId());
// nv.update(nv.getId()); //not work,,,If you set a default value to a field, the corresponding column won't be updated.

View File

@ -18,7 +18,7 @@ import butterknife.BindView;
public class Fragment_bookStore extends BasicFragment {
public static String TAG=Fragment_bookStore.class.getSimpleName();
public static String getFTag() {
return "com.novelbook.android.Fragments.Fragment_bookStore";
}

View File

@ -61,7 +61,7 @@ import butterknife.OnClick;
public class Fragment_jingxuan extends BasicFragment implements OnBannerListener {
public static String TAG=Fragment_jingxuan.class.getSimpleName();
private String mParam1;
private String mParam2;

View File

@ -18,7 +18,7 @@ import butterknife.ButterKnife;
import butterknife.OnClick;
public class Fragment_jingxuan_tuijian extends BasicFragment {
public static String TAG=Fragment_jingxuan.class.getSimpleName();
@BindView(R.id.imageGallary1)
ImageView imageView1;
@BindView(R.id.imageGallary2)

View File

@ -22,6 +22,7 @@ import butterknife.BindView;
public class Fragment_shudan extends BasicFragment {
public static String TAG=Fragment_shudan.class.getSimpleName();
@BindView(R.id.fab)
FloatingActionButton fab;

View File

@ -29,6 +29,7 @@ import com.novelbook.android.Fragments.Fragment_bookStore;
import com.novelbook.android.Fragments.Fragment_booklist;
import com.novelbook.android.Fragments.Fragment_paihang;
import com.novelbook.android.netsubscribe.BookSubscribe;
import com.novelbook.android.netutils.NetUtil;
import com.novelbook.android.netutils.OnSuccessAndFaultListener;
import com.novelbook.android.netutils.OnSuccessAndFaultSub;
import com.novelbook.android.service.ServiceDownload;
@ -40,6 +41,8 @@ import com.novelbook.android.utils.PageFactory;
import org.json.JSONObject;
import java.util.Date;
import butterknife.BindView;
import butterknife.OnClick;
@ -72,7 +75,7 @@ public class Main2Activity extends Activity_base
@Override
protected void onCreate(Bundle savedInstanceState) {
getHostPolicy();
NetUtil.getHostPolicy();
super.onCreate(savedInstanceState);
//PageFactory.createPageFactory(this);
app =(MyApp) getApplicationContext();
@ -536,33 +539,5 @@ private int bottomSelectedIndex;
//----get master domain
private void getHostPolicy(){ //TODO: get masterdomain info
BookSubscribe.getMastDomain(new OnSuccessAndFaultSub(new OnSuccessAndFaultListener() {
@Override
public void onSuccess(String result) {
// mFirstPage= gson.fromJson(result, FirstPage.class);
try {
JSONObject jsonObject = new JSONObject(result);
String resultstr = jsonObject.getString("hosts");
Config config =Config.createConfig(Main2Activity.this);
config.setBaseUrl(resultstr);
// config.setRootUrl( jsonObject.getString("masterDomains"));
} catch (Exception e) {
e.printStackTrace();
}
handler.sendEmptyMessage(1);
}
@Override
public void onFault(String errorMsg) {
//失败
Log.d(TAG, "error on get firstpage: " + errorMsg);
handler.sendEmptyMessage(2);
}
}, this));
}
}

View File

@ -1,11 +1,14 @@
package com.novelbook.android;
import android.content.Intent;
import android.graphics.Typeface;
import android.support.design.widget.AppBarLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.Toolbar;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageButton;
@ -144,4 +147,29 @@ public class MarkActivity extends Activity_base {
public void sortList();
public void refresh();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.catalogemark, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_change_source) {
Intent intent = new Intent(MarkActivity.this, Activity_ChgSource.class);
intent.putExtra(Activity_ChgSource.EXTR_ID, pageFactory.getChapter().getIndex());
intent.putExtra(Activity_ChgSource.EXTR_TITLE, pageFactory.getChapter().getChapterName());
intent.putExtra(Activity_ChgSource.EXTR_SITE, pageFactory.getChapter().getDomain());
intent.putExtra(Activity_ChgSource.EXTR_cate,true);
startActivity(intent);
finish();
}
return super.onOptionsItemSelected(item);
}
}

View File

@ -18,14 +18,17 @@ public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
HttpMethods.USERAGENT = NetUtil.getUserAgent();
applicationContext = getApplicationContext();
HttpMethods.USERAGENT = NetUtil.getUserAgent();
HttpMethods.LOCALUSERAGENT = NetUtil.getUserAgent(applicationContext);
Config.createConfig(this);
PageFactory.createPageFactory(this);
LogcatHelper.getInstance(this).start();
// BlurKit.init(this);
LitePal.initialize(this);
initApi();
}
public void initApi(){

View File

@ -47,6 +47,7 @@ import com.novelbook.android.utils.Config;
import com.novelbook.android.utils.Constants;
import com.novelbook.android.utils.PageFactory;
import com.novelbook.android.view.PageWidget;
import com.umeng.analytics.MobclickAgent;
import org.litepal.LitePal;
@ -55,7 +56,9 @@ import java.io.IOException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import butterknife.BindView;
import butterknife.OnClick;
@ -121,7 +124,7 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
private PageModeDialog mPageModeDialog;
private Boolean mDayOrNight;
// 语音合成客户端
private SpeechSynthesizer mSpeechSynthesizer;
// private SpeechSynthesizer mSpeechSynthesizer;
private boolean isSpeaking = false;
@ -225,7 +228,7 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
bookpage.setPageMode(config.getPageMode());
pageFactory.setPageWidget(bookpage);
sb_progress.setVisibility(book.isLocalBook()?View.VISIBLE:View.INVISIBLE);
Log.d(TAG, String .format("prepare Book: set pagewidget %s" , book.getName()));
Log.d(TAG, String .format("prepare book: set pagewidget %s, to open book" , book.getName()));
try {
hideSystemUI();
@ -457,35 +460,46 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
};
int startTime =0;
@Override
protected void onResume(){
super.onResume();
if (!isShow){
hideSystemUI();
}
if (mSpeechSynthesizer != null){
/* if (mSpeechSynthesizer != null){
mSpeechSynthesizer.resume();
}
}*/
startTime = (int) new Date().getTime();
}
@Override
public void onPause() {
super.onPause();
Map<String, String> map_value = new HashMap<String, String>();
map_value.put("bookname" , book!=null ? book.getName():"noname" );
MobclickAgent.onEventValue(MyApp.applicationContext, "novel_reading_time" , map_value, (int) new Date().getTime() - startTime);
}
@Override
protected void onStop(){
super.onStop();
if (mSpeechSynthesizer != null){
/* if (mSpeechSynthesizer != null){
mSpeechSynthesizer.stop();
}
}*/
}
@Override
protected void onDestroy() {
super.onDestroy();
pageFactory.clear();
// pageFactory.clear();
bookpage = null;
unregisterReceiver(myReceiver);
isSpeaking = false;
if (mSpeechSynthesizer != null){
/* if (mSpeechSynthesizer != null){
mSpeechSynthesizer.release();
}
}*/
}
@Override
@ -509,7 +523,11 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
if(!pageFactory.canExitSilent()){
showNormalDialog();
if(book.isOnShelf()){
finish();
}else {
showNormalDialog();
}
}
}
@ -524,19 +542,25 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
final AlertDialog.Builder normalDialog =
new AlertDialog.Builder(ReadActivity.this);
normalDialog.setTitle("退出阅读");
normalDialog.setMessage("确定退出阅读吗?");
normalDialog.setPositiveButton("继续阅读",
normalDialog.setTitle("提示");
normalDialog.setMessage("是否加入书架?");
normalDialog.setPositiveButton("确定",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
hideSystemUI();
book.setOnShelf(true);
book.update(book.getId());
finish();
}
});
normalDialog.setNegativeButton("退出阅读",
normalDialog.setNegativeButton("取消",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
public void onClick(DialogInterface dialog, int which)
{
finish();
}
});
@ -634,6 +658,11 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
// }else{
// Toast.makeText(this,"换源不可用,请返回重试...",Toast.LENGTH_SHORT);
// }
}else if(id == R.id.action_refresh){
pageFactory.refreshChapter();
}else if(id == R.id.action_bookdetail){
showBookDetail(this.book);
//finish();
}
return super.onOptionsItemSelected(item);
@ -898,11 +927,11 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
/* case R.id.rl_bottom:
break;*/
case R.id.tv_stop_read:
if (mSpeechSynthesizer!=null){
/* if (mSpeechSynthesizer!=null){
mSpeechSynthesizer.stop();
isSpeaking = false;
hideReadSetting();
}
}*/
case R.id.llTopAd:
Toast.makeText(this,"ad is clicked ",Toast.LENGTH_LONG).show();
Log.d(TAG,"Ad is clicked");
@ -992,14 +1021,14 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
*/
@Override
public void onSpeechFinish(String utteranceId) {
pageFactory.nextPage();
/* pageFactory.nextPage();
if (pageFactory.islastPage()) {
isSpeaking = false;
Toast.makeText(ReadActivity.this,"小说已经读完了",Toast.LENGTH_SHORT);
}else {
isSpeaking = true;
mSpeechSynthesizer.speak(pageFactory.getCurrentPage().getLineToString());
}
}*/
}
/**
@ -1010,9 +1039,9 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
*/
@Override
public void onError(String utteranceId, SpeechError error) {
mSpeechSynthesizer.stop();
/* mSpeechSynthesizer.stop();
isSpeaking = false;
Log.e(TAG,error.description);
Log.e(TAG,error.description);*/
}
final int contentAdHight=350;
@ -1041,4 +1070,6 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
}

View File

@ -22,6 +22,15 @@ public class SiteRule extends LitePalSupport {
private String chapterUrlPattern;
private long miniInterval4AccessChapter;
private String[] headers;
private String[] userAgents;
public String[] getUserAgents() {
return userAgents;
}
public void setUserAgents(String[] userAgents) {
this.userAgents = userAgents;
}
public int getId() {
return id;

View File

@ -14,15 +14,15 @@ import org.json.JSONObject;
public class URLConstant {
//存放全部的URL可分为开发测试正式
private static String ROOT_URL = Config.getInstance().getRootUrl() ;//https://api.douban.com/v2/movie/";
public static String[] BASE_URLS = {"http://xiaoshuofenxiang.com/api/"};
private static String ROOT_URL ;//= Config.getInstance().getRootUrl() ;//https://api.douban.com/v2/movie/";
// public static String[] BASE_URLS = {"http://xiaoshuofenxiang.com/api/"};
/**
* 取新的baseURL
* @return
*/
public static String newRootUrl(){
/* public static String newRootUrl(){
for (String url:BASE_URLS) {
if(!url.equals(ROOT_URL)){
@ -34,7 +34,7 @@ public class URLConstant {
Config.getInstance().setBaseUrl(ROOT_URL);
}
return ROOT_URL;
}
}*/
/**
* app初始化取上次保存的baseurl

View File

@ -45,8 +45,8 @@ import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import static com.novelbook.android.netapi.URLConstant.getRootUrl;
import static com.novelbook.android.netapi.URLConstant.newRootUrl;
import static com.novelbook.android.netutils.NetUtil.getHost;
//import static com.novelbook.android.netapi.URLConstant.newRootUrl;
//import static com.novelbook.android.netutils.NetUtil.getHost;
public class HttpMethods {
public String TAG = "HttpMethods";
@ -56,6 +56,7 @@ public class HttpMethods {
private static final int DEFAULT_WRITE_TIMEOUT = 5;
private static final int DEFAULT_READ_TIMEOUT = 5;
public static String USERAGENT="";
public static String LOCALUSERAGENT="";
private Retrofit retrofit;
private HttpApi httpApi;
/**
@ -102,6 +103,7 @@ public class HttpMethods {
// okHttpBuilder.addInterceptor(new RetryInterceptor());
okHttpBuilder.followRedirects(false);
okHttpBuilder.retryOnConnectionFailure(false);
retrofit = new Retrofit.Builder()
.client(okHttpBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
@ -165,6 +167,7 @@ public class HttpMethods {
private OkHttpClient getClient(){
//手动创建一个OkHttpClient并设置超时时间
okHttpBuilder = new OkHttpClient.Builder();
/**
* 设置缓存
*/
@ -173,7 +176,7 @@ public class HttpMethods {
Log.d(TAG, "getClient: to set cach control");
// okHttpBuilder.cache(cache).addInterceptor(cacheInterceptor);
okHttpBuilder.cache(cache)
.addNetworkInterceptor(REWRITE_RESPONSE_INTERCEPTOR)
// .addNetworkInterceptor(REWRITE_RESPONSE_INTERCEPTOR)
.addInterceptor(REWRITE_RESPONSE_INTERCEPTOR_OFFLINE);
/**
@ -181,17 +184,17 @@ public class HttpMethods {
*/
Interceptor headerInterceptor = new Interceptor() {
/* Interceptor headerInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
/* Request.Builder requestBuilder = originalRequest.newBuilder()
*//* Request.Builder requestBuilder = originalRequest.newBuilder()
.addHeader("Accept-Encoding", Locale.getDefault().toString())
// .addHeader("Host", "testapi.wujike.com.cn")
.addHeader("Connection", "Keep-Alive")
.addHeader("Device", "Android")
.method(originalRequest.method(), originalRequest.body());
*/
*//*
Request.Builder requestBuilder = originalRequest.newBuilder()
// .addHeader("Accept-Encoding", "gzip")
// .addHeader("Accept-Encoding", Locale.getDefault().toString() )
@ -206,8 +209,8 @@ public class HttpMethods {
Request request = requestBuilder.build();
return chain.proceed(request);
}
};
okHttpBuilder.addInterceptor(headerInterceptor);
};*/
// okHttpBuilder.addInterceptor(headerInterceptor);
// if (BuildConfig.DEBUG) {
@ -334,18 +337,7 @@ public class HttpMethods {
}
};
private static String getUserAgent(Context context) {
String userAgent = "";
// APP版本
String versionName = CommonUtil.getVersionName(context);
// 手机型号
String systemModel = CommonUtil.getSystemModel();
// 系统版本
String systemVersion = CommonUtil.getSystemVersion();
String deviceBrand = CommonUtil.getDeviceBrand();
userAgent = "Android/" + versionName + "/" + deviceBrand + "" + systemModel + "/" + systemVersion;
return userAgent;
}
final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
@Override

View File

@ -5,16 +5,16 @@ import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.text.TextUtils;
import android.util.Log;
import android.widget.ImageView;
import com.novelbook.android.MyApp;
import com.novelbook.android.netapi.RandomHost;
import com.novelbook.android.netapi.URLConstant;
import com.novelbook.android.netsubscribe.BookSubscribe;
import com.novelbook.android.utils.CommonUtil;
import com.novelbook.android.utils.Config;
import com.novelbook.android.utils.Constants;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Date;
import java.util.Random;
import okhttp3.Call;
@ -29,8 +29,8 @@ public class NetUtil {
private static final String TAG= NetUtil.class.getSimpleName();
public static int currentRequestTag =0;
public static String hosts;
public static String getUrl(String key){
public static boolean isRequestHosts;
/* public static String getUrl(String key){
try {
JSONObject jsonObject = getHost();
@ -48,10 +48,26 @@ public class NetUtil {
}
return "";
}*/
public static boolean isHostExpires(){
if(Constants.LAST_G==0){
return false;
}
long t =Constants.MAXAGE_G*1000 - (new Date().getTime() - Constants.LAST_G ) ;
Log.d(TAG, "isHostExpires: time left is " +CommonUtil.getTimeCnt4Read(t,true));
// t=0;
return t < 0;
}
public static JSONObject getHost() {
if (TextUtils.isEmpty(hosts)) {
public static JSONObject getHost(boolean isMainApi) {
if(!isMainApi && isHostExpires()){
Log.d(TAG, String.format("isHostExpires prepare book: main API maxAge %s, is expired, loading main API again ",CommonUtil.getTimeCnt4Read(Constants.MAXAGE_G*1000,true)));
getHostPolicy();
}
if (TextUtils.isEmpty(hosts)){
Config config = Config.getInstance();
hosts = config.getBaseUrl();
}
@ -251,7 +267,7 @@ public class NetUtil {
};
return uas[new Random().nextInt(uas.length-1)];
// return"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36";
// return"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36";
// return "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36";
}
@ -267,5 +283,57 @@ public class NetUtil {
return url;
}
public static String getUserAgent(Context context) {
String userAgent = "";
// APP版本
String versionName = CommonUtil.getVersionName(context);
// 手机型号
String systemModel = CommonUtil.getSystemModel();
// 系统版本
String systemVersion = CommonUtil.getSystemVersion();
String deviceBrand = CommonUtil.getDeviceBrand();
String packagenm = CommonUtil.getPackageName(context);
userAgent = "Android/" + versionName + "/"+packagenm+"/" + deviceBrand + "/" + systemModel + "/" + systemVersion;
return userAgent;
}
public static void getHostPolicy(){
if(isRequestHosts){
return;
}
isRequestHosts =true;
BookSubscribe.getMastDomain(new OnSuccessAndFaultSub(new OnSuccessAndFaultListener() {
@Override
public void onSuccess(String result) {
// mFirstPage= gson.fromJson(result, FirstPage.class);
try {
JSONObject jsonObject = new JSONObject(result);
String resultstr = jsonObject.getString("hosts");
Config config =Config.createConfig(MyApp.applicationContext);
config.setBaseUrl(resultstr);
//config.setBaseUrl(resultstr);
hosts="";
Constants.LAST_G = new Date().getTime();
Constants.announcement =jsonObject.getString("declare");
// config.setRootUrl( jsonObject.getString("masterDomains"));
isRequestHosts =false;
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onFault(String errorMsg) {
//失败
Log.d(TAG, "error on get firstpage: " + errorMsg);
isRequestHosts =false;
}
}, MyApp.applicationContext));
}
}

View File

@ -4,6 +4,7 @@ import android.text.TextUtils;
import android.util.Log;
import com.novelbook.android.netapi.RandomHost;
import com.novelbook.android.utils.Constants;
import com.novelbook.android.utils.REUtil;
import org.json.JSONException;
@ -44,7 +45,8 @@ public class RetryInterceptor implements Interceptor {
}
String path = oldUrl.substring(prefix.length());
RandomHost rh = null;
if(oldUrl.indexOf("xiaoshuofenxiang.com") == -1 || !path.startsWith("/api/") || NetUtil.getHost()==null){
boolean isMainApi =path.equals("/api/g/");
if(oldUrl.indexOf("xiaoshuofenxiang.com") == -1 || !path.startsWith("/api/") || NetUtil.getHost(isMainApi)==null){
// rh = null;
Response response = doRequest(chain, request);
if(response!=null)
@ -57,14 +59,14 @@ public class RetryInterceptor implements Interceptor {
}
}
try {
rh = new RandomHost(NetUtil.getHost(), path);
rh = new RandomHost(NetUtil.getHost(isMainApi), path);
Log.d(TAG, "HttpMethods intercept: api path is "+path);
Log.d(TAG, "HttpMethods intercept: create new RandomHost--------------------------");
} catch (JSONException e) {
Log.e(TAG, "intercept: ", e);
// TODO rh == null
}
@ -80,7 +82,20 @@ public class RetryInterceptor implements Interceptor {
Request newRequest = null;
try {
newRequest = request.newBuilder().url(newUrl).build();
Request.Builder requestBuilder = request.newBuilder();
requestBuilder.removeHeader("User-Agent").addHeader("User-Agent", HttpMethods.LOCALUSERAGENT)
.url(newUrl);
if (path.equals("/api/g/")) {
// if(new Date().getTime() - Constants.LAST_G > Constants.MAXAGE_G){ //
if (Constants.LAST_G == 0) {
requestBuilder.header("Cache-Control", "public, max-age=0");
Log.d(TAG, "prepare book access main api with force maxage=0");
}
}
newRequest = requestBuilder.build();
} catch (Exception e) {
Log.e(TAG, "HttpMethods intercept: " + newUrl);
Log.e(TAG, "HttpMethods intercept: ", e);
@ -100,6 +115,17 @@ public class RetryInterceptor implements Interceptor {
if (response != null && response.isSuccessful()) {
// rh = null;
Log.d(TAG, String.format("HttpMethods intercept: set rh null,return response"));
if (path.equals("/api/g")) {
String cacheControl = response.header("Cache-Control");
if(!TextUtils.isEmpty(cacheControl)) {
try {
Constants.MAXAGE_G = Integer.parseInt(cacheControl.substring("max-age=".length()));
}catch (Exception e)
{
Log.e(TAG, "intercept: parse max age error", e);
}
}
}
return response;
}
}

View File

@ -50,6 +50,7 @@ import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
@ -72,7 +73,7 @@ public class BookUtil {
private static final String charachterType = "utf-8";//"UTF-16LE";
private Context mContext;
private ProgressDialog progressDialog;
private MuluStatus mMuluStatus; //目录是否下载完成
MuluStatus mMuluStatus; //目录是否下载完成
private Gson gson = new Gson();
public void setContext(Context context) {
this.mContext = context;
@ -112,7 +113,9 @@ public class BookUtil {
}
private long bookLen;
private long chapterLen;
private long position;
// private long position;
private Map<Integer,Long> charPosition = new HashMap<Integer,Long>();
private Novel mNovel;
public void setNovel(Novel novel) {
@ -134,7 +137,7 @@ public class BookUtil {
public Chapter getChapter(int chapId){
chapId = chapId >0 ?chapId : 1;
if(chapId > mChapters.size() || mChapters.size() ==0){
return Chapter.getChapter(mNovel.getId(), mNovel.getDomain(),chapId);
return Chapter.getChapter(mNovel.getId(), mNovel.getDomain()==null?"":mNovel.getDomain(),chapId);
}else{
return mChapters.get(chapId-1);
}
@ -446,17 +449,8 @@ public class BookUtil {
private boolean isChangeSource =false;
private int mChangeChapId;
private String mChangeTitle;
public void changeSource(String domain,int chapId,String chapTitle) {
Log.d(TAG, String.format("changing Source: target domain %s chaptId %s, chapt title %s ",domain,chapId,chapTitle) );
this.muluRetryCount=0;
this.downloadStatus = DownloadStatus.notStart;
chaptDownStatus.clear();
chaptCache.clear();
// isDownloadChapt =false;
mChangeChapId = chapId;
mChangeTitle =chapTitle;
public void changeSite(String domain){
for (Site site:mNovelSites.getSites() ) {
if(site.getDomain().equals(domain)){
mSite = site;
@ -469,6 +463,15 @@ public class BookUtil {
isChangeSource = true;
mChapters.clear();
getSiteRule();
}
public void changeSource(String domain,int chapId,String chapTitle) {
Log.d(TAG, String.format("changing Source: target domain %s chaptId %s, chapt title %s ",domain,chapId,chapTitle) );
clearBook();
// isDownloadChapt =false;
mChangeChapId = chapId;
mChangeTitle =chapTitle;
changeSite(domain);
BookTask btsk = new BookTask();
btsk.execute( domain, chapId+"", chapTitle);
@ -477,6 +480,17 @@ public class BookUtil {
}
private void clearBook() {
charPosition.clear();
this.muluRetryCount=0;
this.downloadStatus = DownloadStatus.notStart;
chaptDownStatus.clear();
chaptCache.clear();
fileRetryCnt.clear();
siteRuleRetryCnt=0;
caprint.clear();
}
public Site getSite() {
@ -527,6 +541,21 @@ public class BookUtil {
}
/**
* delete cache chapter file
* and reload the chapter
*/
public void refreshChapter() {
File file = new File(fileChapterName(chapterNo));
if(file.exists()){
file.delete();
}
if(chaptCache.containsKey(chapterNo)){
chaptCache.remove(chapterNo);
}
pagefactory.changeChapter(chapterNo);
}
private class BookTask extends AsyncTask<String,Void,Boolean> {
private String domain;
@ -954,14 +983,16 @@ int muluRetryCount =0;
}
public int next(boolean back,int chaptId){
position += 1;
if (position > tmpChaptLen){
position = tmpChaptLen;
// Log.d(TAG, String.format(" loadchapt next() back %s, chaptId %s, position %s, tmpChaptLen %s",back,chaptId,charPosition.get(chaptId),tmpChaptLen ));
charPosition.put(chaptId,charPosition.get(chaptId)+1) ;
if (charPosition.get(chaptId) > tmpChaptLen){
charPosition.put(chaptId,tmpChaptLen) ;
return -1;
}
char result = chaptCurrent(chaptId); //current();
if (back) {
position -= 1;
charPosition.put(chaptId,charPosition.get(chaptId)-1) ;
}
return result;
}
@ -984,7 +1015,7 @@ int muluRetryCount =0;
line += wordChar;
}
return line.toCharArray();
}*/
}
public char[] preLine(){
if (position <= 0){
@ -1006,18 +1037,19 @@ int muluRetryCount =0;
}
return line.toCharArray();
}
}*/
public char chaptCurrent(int chaptId){
// chapterNo = mChapters.size() < chapterNo ? 1 : chapterNo;
// Log.d(TAG, String.format(" prepare book chaptCurrent() ,chapterNo %s, getChapters().size() %s " ,chapterNo , mChapters.size()) );
// Log.d(TAG, String.format(" loadchapt chaptCurrent() ,chapterNo %s, getChapters().size() %s " ,chaptId , mChapters.size()) );
char[] charArray = chaptChars(chaptId);
int i = (int)position-1;
int i = (int) (charPosition.get(chaptId) -1);//(int)position-1;
i =i>0?i:0;
i = i< charArray.length? i:charArray.length-1;
// Log.d(TAG, String.format(" loadchapt chaptCurrent() char position %s - %s, char '%s' " ,i,charPosition.get(chaptId) -1,charArray[i]) );
return charArray[i];
}
public char current(){
@ -1028,9 +1060,9 @@ int muluRetryCount =0;
int len = 0;
for (int i = 0;i < myArray.size();i++){
long size = myArray.get(i).getSize();
if (size + len - 1 >= position){
if (size + len - 1 >= charPosition.get(chaptId) ){
cachePos = i;
pos = (int) (position - len);
pos = (int) (charPosition.get(chaptId) - len);
break;
}
len += size;
@ -1040,7 +1072,7 @@ int muluRetryCount =0;
return charArray[pos];
}
public int pre(boolean back){
/* public int pre(boolean back){
position -= 1;
if (position < 0){
position = 0;
@ -1052,13 +1084,13 @@ int muluRetryCount =0;
}
return result;
}
public long getPosition(){
return position;
*/
public long getPosition(int chaptId){
return charPosition.get(chaptId);
}
public void setPostition(long position){
this.position = position;
public void setPostition(int chaptId,long position){
charPosition.put(chaptId,position) ;
}
//缓存书本
@ -1433,7 +1465,7 @@ int muluRetryCount =0;
return true;
}
List<Integer> caprint = new ArrayList<Integer>();
//获取chapter 缓存
public char[] chaptChars(final int index) {
@ -1441,7 +1473,12 @@ int muluRetryCount =0;
char[] block=null;
if(chaptCache.containsKey(Integer.valueOf(index))) {
block = chaptCache .get(index).getData().get();
Log.d(TAG, String.format("read content get block in cache, chapter: %s", index));
// Log.d(TAG, String.format("chaptChars get block in cache, chapter: %s", index));
if(!caprint.contains(index)) {
caprint.add(index);
// Log.d(TAG, String.format("chaptChars: load from cache chaptId %s,--->%s", index, new String(block)));
}
}
// Log.d(TAG, String.format("prepare book begin to load content for chapter %s", index));
if (block == null) {
@ -1592,6 +1629,11 @@ int muluRetryCount =0;
long l = reader.read(block);
// Log.d(TAG, String.format("loadchapt: load from file chaptId %s,--->%s",index, new String(block )));
/* for (char c :block
) {
Log.d(TAG, String.valueOf(c));
}*/
if (reader.read(block) != block.length) {
// throw new RuntimeException("Error during reading " + fileChapterName(index));
}
@ -1613,6 +1655,7 @@ int muluRetryCount =0;
cache.setData(new WeakReference<char[]>(block));
chaptCache.put(index, cache);
// myArray.set(index, new WeakReference<char[]>(block));
Log.d(TAG, String.format("prepare book content reading finish, chapter %s", index));
}
return block;
}
@ -1771,6 +1814,15 @@ private void loadChaptContent(final int chapterIndex) throws JSONException, Inte
}
if(mSiteRule.getUserAgents()!=null && mSiteRule.getUserAgents().length>0){
String siteAgent =mSiteRule.getUserAgents()[new Random().nextInt( mSiteRule.getUserAgents().length-1)];
Log.d(TAG, "prepare book on getTagRequest:add site user agent " + siteAgent);
builder.removeHeader("User-Agent").addHeader("User-Agent",siteAgent ); // 随机agent
}else{
builder.removeHeader("User-Agent").addHeader("User-Agent", HttpMethods.USERAGENT);
}
// .header( "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
// .header( "Upgrade-Insecure-Requests", "1")

View File

@ -2,11 +2,13 @@ package com.novelbook.android.utils;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Point;
import android.os.Build;
import android.support.v4.widget.ContentLoadingProgressBar;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
@ -343,6 +345,19 @@ public class CommonUtil {
return 0;
}
}
public static String getPackageName(Context context) {
try {
return context.getPackageName();
} catch (Exception e) {
e.printStackTrace();
return "";
}catch (NoSuchMethodError e){
e.printStackTrace();
return "";
}
}
/**
* 获取当前手机系统语言
*
@ -480,7 +495,24 @@ public class CommonUtil {
String date1 = format1.format(new Date(System.currentTimeMillis()));
return date1;// 2012-10-03 23:41:31
}
private String getChannel(Context context) {
try {
PackageManager pm = context.getPackageManager();
ApplicationInfo appInfo = pm.getApplicationInfo(getPackageName(context), PackageManager.GET_META_DATA);
return appInfo.metaData.getString("UMENG_CHANNEL");
} catch (PackageManager.NameNotFoundException ignored) {
}
return "";
}
public static String getMeta(Context context,String key) {
try {
PackageManager pm = context.getPackageManager();
ApplicationInfo appInfo = pm.getApplicationInfo(getPackageName(context), PackageManager.GET_META_DATA);
return appInfo.metaData.getString(key);
} catch (PackageManager.NameNotFoundException ignored) {
}
return "";
}
/* public static boolean isNavigationBarShow(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {

View File

@ -3,7 +3,10 @@ package com.novelbook.android.utils;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Typeface;
import android.text.style.BulletSpan;
import com.novelbook.android.BuildConfig;
import com.novelbook.android.MyApp;
import com.novelbook.android.R;
@ -187,14 +190,20 @@ public class Config {
sp.edit().putString(KEY_BASE_URY,baseUrl).commit();
}
public String getBaseUrl(){
String defaultHost ="{\"master\":[\"http:\\/\\/xiaoshuofenxiang.com\"],\"page\":[\"http:\\/\\/p.xiaoshuofenxiang.com\"],\"report\":[\"http:\\/\\/r.xiaoshuofenxiang.com\"],\"search\":[\"http:\\/\\/s.xiaoshuofenxiang.com\"],\"novel\":[\"http:\\/\\/n.xiaoshuofenxiang.com\"],\"novelsbydot\":[\"http:\\/\\/nbd.xiaoshuofenxiang.com\"],\"user\":[\"http:\\/\\/u.xiaoshuofenxiang.com\"]}";
// String defaultHost ="{\"master\":[\"http:\\/\\/xiaoshuofenxiang.com\"],\"page\":[\"http:\\/\\/p.xiaoshuofenxiang.com\"],\"report\":[\"http:\\/\\/r.xiaoshuofenxiang.com\"],\"search\":[\"http:\\/\\/s.xiaoshuofenxiang.com\"],\"novel\":[\"http:\\/\\/n.xiaoshuofenxiang.com\"],\"novelsbydot\":[\"http:\\/\\/nbd.xiaoshuofenxiang.com\"],\"user\":[\"http:\\/\\/u.xiaoshuofenxiang.com\"]}";
// String defaultHost =CommonUtil.getMeta(MyApp.applicationContext,"DEFAULTHOST");
String defaultHost =BuildConfig.API_HOST;
return sp.getString(KEY_BASE_URY,defaultHost);
}
public String getRootUrl(){
return sp.getString(KEY_ROOT_URL,"http://xiaoshuofenxiang.com/api/");
//String defaultHost =CommonUtil.getMeta(MyApp.applicationContext,"MAINHOST");
String defaultHost = BuildConfig.MAIN_HOST;
String rt =sp.getString(KEY_ROOT_URL,defaultHost);
return sp.getString(KEY_ROOT_URL,defaultHost);
}
public void setRootUrl(String baseUrl){

View File

@ -12,6 +12,8 @@ public class Constants {
public static final int MAXAGE_MAX =60*60*24*28; //28 ;
public static final int MAXAGE_MULU = 60*60*24*7*2; //2周;;
public static final String VERSION_ADDRESS ="version.xml";
public static long LAST_G = 0;//主目录API上次访问时间
public static long MAXAGE_G = 3600;//主目录API上次访问时间
public static String[] HOT_KEYS_VALUE = {};
public static int SEX=1; //1 2女
public static String A_Regex = "<a[^>]+href[\\s]*=[\\s]*['\"]?([^'\"]+)['\"\\s]?[^>]*>([^<]+)<"; //TODO: 从服务器更新
@ -25,5 +27,5 @@ public class Constants {
// public static List<String> lstProgress=null;
public static boolean showDialogOnUi =true;
public static boolean showDialogOnUiPage =false;
public static String announcement ="免责声明:阅读内容均来自互联网,本软件仅提供转码服务";
}

View File

@ -6,6 +6,7 @@ import android.util.Log;
import com.novelbook.android.db.Chapter;
import com.novelbook.android.db.SiteRule;
import com.novelbook.android.netutils.HttpMethods;
import com.novelbook.android.netutils.NetUtil;
import org.json.JSONArray;
import org.json.JSONException;
@ -22,6 +23,7 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import okhttp3.Request;
@ -292,6 +294,13 @@ public class NovelParseUtil {
builder.header(siteRule.getHeaders()[i],siteRule.getHeaders()[i+1]);
}
if(siteRule.getUserAgents()!=null && siteRule.getUserAgents().length>0){
builder.removeHeader("User-Agent").addHeader("User-Agent", siteRule.getUserAgents()[new Random().nextInt( siteRule.getUserAgents().length-1)]); // 随机agent
}else{
builder.removeHeader("User-Agent").addHeader("User-Agent", HttpMethods.USERAGENT);
}
Request request =builder.build() ;
Response response = null;
try {

View File

@ -13,6 +13,7 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.Typeface;
import android.opengl.Visibility;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
@ -26,6 +27,7 @@ import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;
import com.novelbook.android.MyApp;
import com.novelbook.android.R;
import com.novelbook.android.bean.NovelSites;
import com.novelbook.android.bean.Site;
@ -33,6 +35,7 @@ import com.novelbook.android.db.Chapter;
import com.novelbook.android.db.Novel;
import com.novelbook.android.netutils.NetUtil;
import com.novelbook.android.view.PageWidget;
import com.umeng.analytics.MobclickAgent;
import org.litepal.LitePal;
@ -89,7 +92,7 @@ public class PageFactory implements ChangeSource{
//段间距
private float paragraphSpace;
//段间距相对行间距的倍数
private final float prate = 1.3f;
private final float prate = 1.8f;
//字高度
private float fontHeight;
//字体
@ -179,6 +182,7 @@ public class PageFactory implements ChangeSource{
private AdInterface mAd;
private BookTask bookTask;
private int MSG_NEXTPAGE=2;
public AdInterface getmAd() {
return mAd;
@ -191,11 +195,11 @@ public class PageFactory implements ChangeSource{
@Override
public void handleMessage(Message msg) {
int wt = msg.what;
Log.d(TAG, "prepare book get handler msg:" +msg);
handlerMsg(msg);
dismissProgressDialog();
// dismissProgressDialog();
}
};
@ -203,14 +207,20 @@ public class PageFactory implements ChangeSource{
void handlerMsg(Message msg) {
if (msg.what == 1) {
Log.d(TAG, String.format("prepare book handler get notic to download chapter %s , getNovel() is null? %s",currentChapter, getNovel()==null ) );
Log.d(TAG, String.format("prepare book handler get notic to download chapter %s , getNovel() is null? %s", currentChapter, getNovel() == null));
if (getNovel() != null) {
changeChapter(currentChapter);
}else{
} else {
/* mStatus = Status.FAIL; // unknow error null Attempt to invoke virtual method 'android.graphics.Bitmap com.novelbook.android.view.PageWidget.getCurPage()' on a null object reference
drawStatus();
*/
}
} else if (msg.what == MSG_NEXTPAGE) {
mStatus =Status.FINISH;
// drawStatus();
Log.d(TAG, "prepare book to load next page");
nextPage();
}
}
Map<Integer,Integer> fileRetryCnt = new HashMap<Integer,Integer>();
@ -234,12 +244,13 @@ public class PageFactory implements ChangeSource{
}
chaptId = chaptId > 0 ? chaptId : 1;
final File file = new File(getChapterFileName(chaptId));
File file = new File(getChapterFileName(chaptId));
if (!file.exists() && getChapters().size()>0) { //待下载
chaptId = chaptId > getChapters().size() ? getChapters().size() : chaptId;
chaptId = chaptId > 0 ? chaptId : 1;
file = new File(getChapterFileName(chaptId));
}
@ -303,6 +314,7 @@ public class PageFactory implements ChangeSource{
@Override
public void run() {
int slepttime =0;
File file = new File(getChapterFileName(chid));
while( !file.exists() && slepttime <60 && mBookUtil.muluRetryCount<Constants.retryCnt){
try {
sleep(50);
@ -341,8 +353,7 @@ public class PageFactory implements ChangeSource{
Log.d(TAG, String.format("prepare book to load chapt %s, cost %s ",chaptId ,new Date().getTime() -starttime) );
mStatus = Status.FINISH;
Log.d(TAG, String.format("changing Source prepare book to draw chapter %s, currentChapter %s ",chaptId ,currentChapter ) );
/* drawStatus();
*/
// drawStatus();
return chaptPages;
}
@ -382,14 +393,17 @@ public class PageFactory implements ChangeSource{
*/
List<TRPage> readChaptCache(int chaptId){
List<TRPage> chaptPages = new ArrayList<TRPage>();
Log.d(TAG, String.format("changing Source prepare book to open chapter %s, currentChapter %s ",chaptId ,currentChapter ) );
Log.d(TAG, String.format("prepare book to open chapter %s, currentChapter %s ",chaptId ,currentChapter ) );
char[] chars = mBookUtil.chaptChars(chaptId);
mBookUtil.setTmpChaptLen(chars.length);
// mBookUtil.setChapterNo(chaptId);
// TRPage page = new TRPage();
long length =0;
int pageNo =0;
long starttime = new Date().getTime();
while(length <chars.length ) {
long starttime1 = new Date().getTime();
pageNo++;
TRPage page = getNextChapterPage(chaptId,length);
// Log.d(TAG,"prepare book page.getBegin :" + page.getBegin()+ ",chapter length "+ mBookUtil.getChapterLen());
@ -405,7 +419,9 @@ public class PageFactory implements ChangeSource{
page.setPageNo(pageNo);
chaptPages.add(page);
length= page.getEnd();
Log.d(TAG, String.format("prepare book build page %s ready for chapter %s,cost %s",pageNo, chaptId,new Date().getTime()-starttime1));
}
Log.d(TAG, String.format(" prepare book build pages ready for chapter %s,cost %s", chaptId,new Date().getTime()-starttime));
return chaptPages;
}
@ -413,14 +429,14 @@ public class PageFactory implements ChangeSource{
public TRPage getNextChapterPage(int chaptId,long position){
mBookUtil.setPostition(position);
mBookUtil.setPostition(chaptId,position);
TRPage trPage = new TRPage();
trPage.setBegin(position +1);
// Log.d(TAG,"page postion next begin:" + (position + 1) + "");
trPage.setLines(getNextLines(chaptId));
// Log.d(TAG,"page postion next end:" +mBookUtil.getPosition() + "");
trPage.setEnd(mBookUtil.getPosition());
trPage.setEnd(mBookUtil.getPosition(chaptId));
return trPage;
}
@ -452,13 +468,16 @@ public class PageFactory implements ChangeSource{
}
}
public void changeSource(String domainName,String domain,int chapId,String chapTitle) {
mAd.hideSystemUI();
hideSysUI();
fileRetryCnt.clear();
chaptMap.clear();
if(getSite().getDomain().equals(domain)){ //当前源
Log.d(TAG, "prepare book changing Source: same site with original " + domain);
return;
}
if(chaptMap!=null){
chaptMap.clear();
}
Log.d(TAG, String.format("prepare book changing Source:target site received: name %s, site domain %s ,chapterId %s " ,domainName, domain,chapId));
mStatus= Status.CHANGESOURCE;
statusChangeSource="正在换源...";
@ -485,6 +504,19 @@ public static boolean busy(){
return isBusy;
}
public void refreshChapter() {
mBookUtil.refreshChapter();
}
public void changeSourceForCate(String name, String domain) {
if(getSite().getDomain().equals(domain)){ //当前源
Log.d(TAG, "prepare book changing Source: same site with original " + domain);
return;
}
mBookUtil.changeSite(domain);
}
public enum Status {
OPENING,
FINISH,
@ -493,7 +525,12 @@ public static boolean busy(){
SERVERERROR,
CHANGESOURCE ;
}
private void hideSysUI(){
if(mAd!=null){
mAd.hideSystemUI();
// mAd.showRefresh(View.GONE);
}
}
public static synchronized PageFactory getInstance(Context context){
if(pageFactory==null){
createPageFactory(context);
@ -535,7 +572,7 @@ public static boolean busy(){
lineSpace = context.getResources().getDimension(R.dimen.reading_line_spacing);
paragraphSpace = context.getResources().getDimension(R.dimen.reading_paragraph_spacing);
mVisibleWidth = mWidth - marginWidth * 2;
mVisibleHeight = mHeight - marginHeight * 2;
mVisibleHeight = mHeight - marginHeight * 2 - CommonUtil.convertDpToPixel(mContext,10);;
mHeight +=screenHeihtDiff;
typeface = config.getTypeface();
m_fontSize = config.getFontSize();
@ -620,7 +657,7 @@ public static boolean busy(){
private String loadingTxt ="";
private String statusChangeSource ="正在换源...";
private void drawStatus(Bitmap bitmap){
mAd.hideSystemUI();
hideSysUI();
mAd.showRefresh(View.VISIBLE);
String status = "";
switch (mStatus){
@ -630,7 +667,7 @@ public static boolean busy(){
break;
case FAIL:
status = "读取错误,请稍后重试";
mAd.showRefresh(View.VISIBLE);
break;
case NETWORKFAILE:
status = "请开启网络";
@ -650,6 +687,7 @@ public static boolean busy(){
Canvas c = new Canvas(bitmap);
c.drawBitmap(getBgBitmap(), 0, 0, null);
waitPaint.setTextSize(mContext.getResources().getDimension(R.dimen.reading_max_text_size));// 字体大小
waitPaint.setColor(getTextColor());
waitPaint.setTextAlign(Paint.Align.CENTER);
@ -670,17 +708,19 @@ public static boolean busy(){
myStaticLayout.draw(c);*/
mBookPageWidget.postInvalidate();
mAd.hideSystemUI();
// hideSysUI();
}
//上次翻书时间
private long lastPageTime;
public void onDraw(Bitmap bitmap,List<String> m_lines,Boolean updateChapter) {
mAd.hideSystemUI();
hideSysUI();
// mAd.showRefresh(View.GONE);
if(m_lines.size()==0){
return;
}
// Log.d(TAG, String.format(" prepare book onDraw chapter %s, getChapters().size() %s ",currentChapter ,getChapters().size() ) );
mStatus =Status.FINISH;
// Log.d(TAG, String.format(" prepare book onDraw chapter %s, getChapters().size() %s ",currentChapter ,getChapters().size() ) );
if (getChapters().size() > 0 && updateChapter) {
// Log.d(TAG, String.format(" prepare book onDraw chapter to getCurrentChapter(),currentChapter %s ",currentChapter ) );
currentChapter = getCurrentChapter();
@ -689,6 +729,9 @@ public static boolean busy(){
// Log.d(TAG, String.format(" prepare book onDraw chapter _____________ %s ",currentChapter ) );
//更新数据库进度
if ( mStatus ==Status.FINISH && currentPage != null && getNovel() != null) {
new Thread() {
@Override
@ -747,6 +790,10 @@ public static boolean busy(){
float space =m_fontSize + lineSpace;
paragraphSpace = prate * lineSpace;
if(mAd!=null){
mAd.showRefresh(View.GONE);
}
if (m_lines.size() > 0) {
float y = marginHeight;
String lastLine ="";
@ -842,6 +889,21 @@ public static boolean busy(){
}
if(mBookPageWidget!=null)
mBookPageWidget.postInvalidate();
if(currentPage!=null && currentPage.getPageNo()==1){
String source =String.format("本章节内容来自网络");
if(getSite()!=null){
source =String.format("本章节内容来自第三方网站:%s",getSite().getName());
}
int anny= (int) CommonUtil.convertDpToPixel(mContext,40);
c.drawText(source, marginWidth, statusMarginBottom + mBatterryFontSize+anny, mBatterryPaint);
anny= (int) CommonUtil.convertDpToPixel(mContext,60);
c.drawText( Constants.announcement, marginWidth, statusMarginBottom + mBatterryFontSize+anny, mBatterryPaint);
}
}
private void showAd(int adHeight,int adY) {
@ -904,10 +966,38 @@ public static boolean busy(){
if (currentPage.getEnd() >= mBookUtil.getChapterLen()) {
Log.d(TAG,"已经是本章最后一页了");
if(mBookUtil.getChapters().size()==0){
m_islastPage =currentChapter == mBookUtil.getChapters().size() ||mBookUtil.getChapters().size()==0;
mStatus = Status.OPENING;
drawStatus();
new Thread() {
@Override
public void run() {
int slepttime = 0;
while (mBookUtil.getChapters().size()==0 && (mBookUtil.mMuluStatus == BookUtil.MuluStatus.isDownloading || mBookUtil.muluRetryCount < Constants.retryCnt)) {
try {
sleep(50);
slepttime++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Log.d(TAG, String.format("prepare book waiting for chapters slept %s, chapt size %s " , slepttime *50,mBookUtil.getChapters().size()));
if(mBookUtil.getChapters().size()>0){
handler.sendEmptyMessage(MSG_NEXTPAGE) ;
}
}}.start();
return;
}
m_islastPage =currentChapter == mBookUtil.getChapters().size();// ||mBookUtil.getChapters().size()==0;
if ( m_islastPage){
Toast.makeText(mContext, "已经是最后一页了", Toast.LENGTH_SHORT).show();
currentPage(false);
return;
} else {
@ -927,6 +1017,12 @@ public static boolean busy(){
}
onDraw(mBookPageWidget.getNextPage(),currentPage.getLines(),true);
Log.d("nextPage","nextPagenext");
HashMap<String,String> map = new HashMap<String,String>();
map.put("novel",bookName);
map.put("chapt",getChapter().getChapterName());
map.put("page",currentPage.getPageNo()+"");
MobclickAgent.onEvent(MyApp.applicationContext, "page_reading", map);
}
//取消翻页
@ -947,6 +1043,7 @@ public static boolean busy(){
Log.d(TAG, "prepare book: start prepare book " + book.getName());
clear();
if(getNovel()!=null &&getNovel().getNovelId() !=book.getNovelId()){ //取消未上本书完成的web请求待验证效果
try {
NetUtil.cancelRequest(getNovel().getNovelId() );
@ -986,8 +1083,8 @@ if(book==null){
NetUtil.cancelRequest(getNovel().getNovelId() );
}
bookPath = getNovel().getNovelPath();
bookName =getNovel().getName();// FileUtils.getFileName(bookPath);
bookPath = book.getNovelPath();
bookName =book.getName();// FileUtils.getFileName(bookPath);
// this.mCurrentChapter = chapter;
mStatus = Status.OPENING;
drawStatus();
@ -1076,7 +1173,11 @@ if(book==null){
preReadChaptCache(currentChapter + 1);
}
}
return currentChaptPages.get(nextPageNo);
if(currentChaptPages.size()>nextPageNo)
return currentChaptPages.get(nextPageNo);
else{
return new TRPage("没有了");
}
}
public TRPage getPrePage(){
@ -1097,7 +1198,7 @@ if(book==null){
prePageNo = currentChaptPages.size();
}else{
if(currentChapter-1>0) {
preReadChaptCache(currentChapter - 1);
preReadChaptCache(currentChapter - 1);
}
}
@ -1133,20 +1234,22 @@ if(book==null){
float width = 0;
float height = 0;
String line = "";
if(mBookUtil.getPosition()==0) {
if(mBookUtil.getPosition(chaptId)==0) {
lines.add("\n");lines.add("\n");
}
calculateLineCount();
while (mBookUtil.next(true,chaptId) != -1){
char word = (char) mBookUtil.next(false,chaptId);
// Log.d(TAG, String.format(" loadchapt getNextLines() chaptId %s, word '%s'", chaptId,word ));
//判断是否换行
if ((word + "" ).equals("\n") ){// if ((word + "" ).equals("\r") && (((char) mBookUtil.next(true)) + "").equals("\n")){
// mBookUtil.next(false);
if ( !line.isEmpty()){
if (showChapTitleOnTopWhenNextPage && lines.size() >0 && mBookUtil.isChapterTitle(line)) {
Log.d(TAG,String.format("title is %s\n,size is %s ,position is %s" ,line,line.length(),mBookUtil.getPosition() ));
Log.d(TAG,String.format("title is %s\n,size is %s ,position is %s" ,line,line.length(),mBookUtil.getPosition(chaptId) ));
break;
}
// Log.d(TAG, String.format(" loadchapt getNextLines()chaptId %s new line with enter '%s' ", chaptId, line+word ));
lines.add(line+word);
// lines.add("\n");
line = "";
@ -1162,9 +1265,12 @@ if(book==null){
}else {
float widthChar = mPaint.measureText(word + "");
width += widthChar;
// Log.d(TAG, String.format(" loadchapt getNextLines(),widthChar %s ,width %s,mVisibleWidth %s",widthChar, width ,mVisibleWidth ));
if (width > mVisibleWidth) {
width = widthChar;
lines.add(line);
// Log.d(TAG, String.format(" loadchapt getNextLines()chaptId %snew line '%s' ",chaptId , line ));
/* if (lines.size() == mLineCount){
Log.d(TAG,String.format("lines count limit b %s,lines size %s",mLineCount,lines.size()));
line ="";
@ -1173,15 +1279,17 @@ if(book==null){
*/
line = word + "";
} else {
line += word;
// Log.d(TAG, String.format(" loadchapt getNextLines()chaptId %sgrowing line '%s' ",chaptId , line ));
}
}
if (lines.size() == mLineCount){
// Log.d(TAG,String.format("lines count limit c %s,lines size %s",mLineCount,lines.size()));
// Log.d(TAG,String.format("loadchapt lines count ,chaptId %s limit c %s,lines size %s",chaptId ,mLineCount,lines.size()));
if (!line.isEmpty()){
// mBookUtil.setPostition(mBookUtil.getPosition() - line.length()-2);// mBookUtil.setPostition(mBookUtil.getPosition() - 1);
mBookUtil.setPostition(mBookUtil.getPosition() - 1);
mBookUtil.setPostition(chaptId,mBookUtil.getPosition(chaptId) - 1);
}
break;
}
@ -1211,7 +1319,7 @@ if(book==null){
return lines;
}
public List<String> getPreLines(){
/*public List<String> getPreLines(){
List<String> lines = new ArrayList<>();
float width = 0;
String line = "";
@ -1233,11 +1341,11 @@ if(book==null){
// Log.d(TAG,"preLine is \n" + line);
}
/* if ( mBookUtil.isChapterTitle(line)) {
*//* if ( mBookUtil.isChapterTitle(line)) {
mBookUtil.setPostition(mBookUtil.getPosition() - line.length()-2);
break;
}*/
}*//*
// lines.add(line);
// Log.d(TAG,"preLine is \n" + line);
@ -1275,7 +1383,7 @@ if(book==null){
}
return reLines;
}
}*/
//上一章
@ -1359,7 +1467,7 @@ if(book==null){
//更新电量
public void updateBattery(int mLevel){
if(mAd!=null) mAd.hideSystemUI();
hideSysUI();
if (currentPage != null && mBookPageWidget != null && !mBookPageWidget.isRunning()) {
Log.d(TAG, String.format("updateBattery: level old %s, new %s",level,mLevel));
@ -1371,7 +1479,7 @@ if(book==null){
}
public void updateTime(){
if(mAd!=null) mAd.hideSystemUI();
hideSysUI();
if (currentPage != null && mBookPageWidget != null && !mBookPageWidget.isRunning()) {
String mDate = sdf.format(new java.util.Date());
if (date != mDate) {
@ -1518,7 +1626,7 @@ if(book==null){
}
public void clear(){
Log.d(TAG, String .format("prepare Book: clearing book info %s" , getNovle().getName()));
// Log.d(TAG, String .format("prepare Book: clearing book info %s" , getNovle().getName()));
fileRetryCnt.clear();
lastPageTime=0;
if(chaptMap!=null){
@ -1641,7 +1749,12 @@ if(book==null){
return new Novel();
}
public Site getSite(){
return mBookUtil.getSite();
if(mBookUtil!=null){
return mBookUtil.getSite();
}
else{
return new Site();
}
}
public boolean isWorking(){
return mBookUtil !=null;

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 实心 -->
<solid android:color="@color/colorPrimaryDark"/>
<!-- 渐变 -->
<gradient
android:startColor="@color/colorPrimary"
android:endColor="@color/colorPrimaryDark"
android:angle="270" />
<!-- 描边 -->
<stroke
android:width="2dp"
android:color="@color/white" />
<!-- 圆角 -->
<corners
android:radius="8dp" />
<padding
android:left="11dp"
android:top="2dp"
android:right="11dp"
android:bottom="3dp" />
</shape>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 实心 -->
<solid android:color="@color/read_dialog_bg"/>
<!-- 渐变 -->
<!--<gradient-->
<!--android:startColor="#ff8c00"-->
<!--android:endColor="#FFFFFF"-->
<!--android:angle="270" />-->
<!-- 描边 -->
<stroke
android:width="1dp"
android:color="@color/white" />
<!-- 圆角 -->
<corners
android:radius="6dp" />
<padding
android:left="5dp"
android:top="5dp"
android:right="5dp"
android:bottom="5dp" />
</shape>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M18,2H6c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4c0,-1.1 -0.9,-2 -2,-2zM6,4h5v8l-2.5,-1.5L6,12V4z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M17,3L7,3c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3L19,5c0,-1.1 -0.9,-2 -2,-2zM17,18l-5,-2.18L7,18L7,5h10v13z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M14,4l2.29,2.29 -2.88,2.88 1.42,1.42 2.88,-2.88L20,10L20,4zM10,4L4,4v6l2.29,-2.29 4.71,4.7L11,20h2v-8.41l-5.29,-5.3z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M4,6L2,6v14c0,1.1 0.9,2 2,2h14v-2L4,20L4,6zM20,2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM20,12l-2.5,-1.5L15,12L15,4h5v8z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M14,2L6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6zM16,18L8,18v-2h8v2zM16,14L8,14v-2h8v2zM13,9L13,3.5L18.5,9L13,9z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M10,20h4L14,4h-4v16zM4,20h4v-8L4,12v8zM16,9v11h4L20,9h-4z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M19,3L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM9,17L7,17v-7h2v7zM13,17h-2L11,7h2v10zM17,17h-2v-4h2v4z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M2,20h20v-4L2,16v4zM4,17h2v2L4,19v-2zM2,4v4h20L22,4L2,4zM6,7L4,7L4,5h2v2zM2,14h20v-4L2,10v4zM4,11h2v2L4,13v-2z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<shape android:shape="rectangle">
<solid android:color="#00000000" />
<stroke android:width="0.5dip" android:color="@color/colorPrimary" />
<corners android:radius="2.0dip" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="#00000000" />
<stroke android:width="0.30000007dip" android:color="#fff8f8f8" />
<corners android:radius="2.0dip" />
</shape>
</item>
</selector>

View File

@ -168,6 +168,7 @@
android:layout_height="@dimen/botoomNavi"
android:layout_gravity="bottom"
android:layout_weight="0"
android:background="@color/white"
android:orientation="horizontal">
<Button
@ -176,18 +177,14 @@
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/item_selector"
android:drawableTop="@drawable/ic_mood_black_24dp"
android:text="加入书架" />
<Button
android:id="@+id/btnRead"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.8"
android:background="@drawable/item_selector_red"
android:text="立即阅读"
android:textColor="@color/white"
android:textSize="15sp" />
android:text="加入书架" />
<View
android:layout_margin="2dp"
android:layout_width="2dp"
android:layout_height="wrap_content"
android:background="@color/whitesmoke"/>
<Button
android:id="@+id/btnCacheBook"
@ -195,9 +192,21 @@
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/item_selector"
android:drawableTop="@drawable/ic_mood_black_24dp"
android:text="全本缓存" />
<Button
android:id="@+id/btnRead"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="0.7"
android:background="@drawable/item_selector_red"
android:text="转码阅读"
android:textColor="@color/white"
android:textSize="15sp" />
</LinearLayout>

View File

@ -19,7 +19,8 @@
android:layout_height="50dp"
android:layout_gravity="bottom"
android:layout_weight="0"
android:orientation="horizontal">
android:orientation="horizontal"
android:visibility="gone">
<TextView
android:layout_width="match_parent"
@ -66,7 +67,7 @@
</LinearLayout>
<LinearLayout style="@style/llGraySplit.2dp" />
<LinearLayout style="@style/llGraySplit" />
<LinearLayout
@ -123,40 +124,41 @@
<LinearLayout style="@style/llGraySplit.2dp" />
<LinearLayout style="@style/llGraySplit" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- <LinearLayout
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone"
android:visibility="visible"
>
<TextView
android:layout_width="5dp"
android:layout_height="wrap_content"
android:background="@color/colorAccent"
android:visibility="gone"
/>
<TextView
style="@style/TextViewTitle"
android:layout_marginTop="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="目录" />
</LinearLayout>-->
</LinearLayout>
<LinearLayout
android:id="@+id/llCate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="10dp"
android:gravity="center_vertical"
android:orientation="horizontal">
@ -206,7 +208,7 @@
</LinearLayout>
</LinearLayout>
<LinearLayout style="@style/llGraySplit.2dp" />
<LinearLayout style="@style/llGraySplit" />
<!--
<LinearLayout
@ -270,6 +272,7 @@
android:id="@+id/tvAuthorMore"
style="@style/NovelBlockTitle"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:layout_weight="1"
android:text=" 其他作品" />
@ -280,11 +283,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:nestedScrollingEnabled="false"
android:paddingBottom="50dp"
android:paddingBottom="2dp"
/>
</LinearLayout>
<LinearLayout style="@style/llGraySplit" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -294,6 +297,7 @@
android:id="@+id/tvTonglei"
style="@style/NovelBlockTitle"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:layout_weight="1"
android:text="同类推荐" />

View File

@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="@style/llOutside"
android:layout_marginBottom ="0dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
>

View File

@ -25,7 +25,7 @@
android:layout_marginLeft="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_refresh_black_24dp"
app:srcCompat="@drawable/ic_refresh_black_24dp"
style="@style/buttonCates"/>
<ImageButton
@ -35,7 +35,7 @@
android:layout_marginRight="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_format_line_spacing_black_24dp"
app:srcCompat="@drawable/ic_format_line_spacing_black_24dp"
style="@style/buttonCates"/>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_change_source"
android:title="@string/action_change_source"
android:orderInCategory="90"
app:showAsAction="always" />
</menu>

View File

@ -3,17 +3,17 @@
<item
android:id="@+id/navigation_home"
android:icon="@drawable/ic_favorite_border_black_24dp"
android:icon="@drawable/ic_collections_bookmark_black_24dp"
android:title="@string/title_home" />
<item
android:id="@+id/navigation_dashboard"
android:icon="@drawable/ic_library_books_black_24dp"
android:icon="@drawable/ic_storage_black_24dp"
android:title="@string/title_dashboard" />
<item
android:id="@+id/navigation_notifications"
android:icon="@drawable/ic_star_border_black_24dp"
android:icon="@drawable/ic_rank_24dp"
android:title="@string/title_notifications" />
</menu>

View File

@ -1,16 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_change_source"
android:title="@string/action_change_source"
android:orderInCategory="90"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_add_bookmark"
android:title="@string/action_add_bookmark"
android:orderInCategory="90"
app:showAsAction="ifRoom" />
android:title=""
android:icon= "@drawable/ic_bookmark_border_black_24dp"
android:orderInCategory="10"
app:showAsAction="always" />
<item
android:id="@+id/action_refresh"
android:orderInCategory="20"
android:title=""
android:icon= "@drawable/ic_refresh_black_24dp"
app:showAsAction="always" />
<item
android:id="@+id/action_bookdetail"
android:orderInCategory="30"
android:title=""
android:icon= "@drawable/ic_description_black_24dp"
app:showAsAction="always" />
<item
android:id="@+id/action_change_source"
android:title="@string/action_change_source"
android:icon= "@drawable/ic_call_split_black_24dp"
android:orderInCategory="40"
app:showAsAction="always" />
</menu>

View File

@ -140,7 +140,7 @@
<string name="action_select_file">导入书本</string>
<string name="action_change_source">换源</string>
<string name="action_add_bookmark">添加书签</string>
<string name="action_add_bookmark">书签</string>
<string name="action_read_book">读书</string>
<string name="press_twice_to_exit">连续点击才能退出</string>
@ -198,6 +198,7 @@
<string name="soft_update_later">以后再说</string>
<string name="soft_updating">正在更新</string>
<string name="soft_update_cancel">取消更新</string>
<string name="action_novelDetail">详情</string>
<string-array name="voicer_cloud_entries">
<item>小燕—女青、中英、普通话</item>

View File

@ -131,9 +131,11 @@
</style>
<style name="TextViewTitle">
<item name="android:paddingLeft">5dp</item>
<item name="android:textColor">@color/darkcyan</item>
<item name="android:textSize">18sp</item>
<item name="android:textColor">@color/read_font_1</item>
<item name="android:textSize">15sp</item>
<item name="android:textStyle">bold</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
</style>

View File

@ -88,7 +88,6 @@
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/apk_list" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/build-info" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/builds" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundle_manifest" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/check_manifest_result" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/compatible_screen_manifest" />
@ -96,7 +95,6 @@
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-runtime-classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-verifier" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-apk" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-resources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_app_manifest" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_app_info_output_file" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_main_apk_resources" />