This commit is contained in:
mwang 2019-05-03 00:30:48 +08:00
parent dfbd75e655
commit ef85074f05
29 changed files with 704 additions and 242 deletions

View File

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

View File

@ -5,6 +5,7 @@ import android.os.Build;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@ -26,6 +27,7 @@ import butterknife.ButterKnife;
public class Activity_ChgSource extends Activity_base {
private static final String TAG = Activity_ChgSource.class.getSimpleName();
@BindView(R.id.recycleView)
@ -35,10 +37,11 @@ public class Activity_ChgSource extends Activity_base {
String chaptTitle;
int chaptId;
String domain;
// String name;
public final static String EXTR_TITLE="title";
public final static String EXTR_ID="id";
public final static String EXTR_SITE="site";
//public static final String EXTR_NAME ="" ;
PageFactory pageFactory;
List<Site> mSites;
@ -66,6 +69,7 @@ public class Activity_ChgSource extends Activity_base {
chaptId = getIntent().getIntExtra(EXTR_ID,1);
domain = getIntent().getStringExtra(EXTR_SITE);
// name = getIntent().getStringExtra(EXTR_NAME);
this.setTitle(chaptTitle);
}
@ -79,8 +83,8 @@ public class Activity_ChgSource extends Activity_base {
public void onItemClick(View view, int position) {
Site site = mSites.get(position);
Log.d(TAG, "changing Source: " + site.getDomain());
pageFactory.changeSource(site.getDomain(),chaptId,chaptTitle);
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);
finish();
}
@ -169,9 +173,13 @@ public class Activity_ChgSource extends Activity_base {
@Override
public void onBindViewHolder( SiteViewHolder holder, int position) {
String title =mDatas.get(position).getDomain();
String title =mDatas.get(position).getName();
if(TextUtils.isEmpty(title)) {
title = mDatas.get(position).getDomain();
}
Log.d(TAG, String.format("onBindViewHolder: domain is '%s', title is '%s'",domain ,title));
if(title.equals(domain)){
if(mDatas.get(position).getDomain().equals(domain)){
title +=" (当前源)";
}

View File

@ -202,7 +202,7 @@ public abstract class BasicFragment extends Fragment {
int novelId = novel.getNovelId();
long id = novel.getId();
showProgressDialog(false,"正在加载...");
BookSubscribe.getNovel(novel.getNovelId(),new OnSuccessAndFaultSub(new OnSuccessAndFaultListener() {
@Override
public void onSuccess(String result) {
@ -231,7 +231,7 @@ public abstract class BasicFragment extends Fragment {
Log.d(TAG, String.format("prepare book %s 开始open book.",nv.getName()) );
ReadActivity.openBook(nv ,activity);
handler.sendEmptyMessage(99);
}
@Override
@ -240,6 +240,7 @@ public abstract class BasicFragment extends Fragment {
Toast.makeText(getActivity(),"Novel 请求失败:"+errorMsg,Toast.LENGTH_SHORT).show();
PageFactory.getInstance(activity.getApplicationContext()).prepareBook(novel ); //打开本地小说内容
ReadActivity.openBook(novel ,activity);
handler.sendEmptyMessage(99);
}
},getActivity()));

View File

@ -49,7 +49,7 @@ public class BookMarkFragment extends BasicFragment implements MarkActivity.Sor
novelId = bundle.getInt(ARGUMENT);
}
bookMarksList = new ArrayList<>();
bookMarksList = LitePal.where("novelId = ?", novelId+"").order(String.format("id %s",isAsc ?"asc" :"desc")). find(BookMarks.class);
bookMarksList = LitePal.where("novelId = ? and domain= ?", novelId+"",pageFactory.getSite().getDomain()).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);
@ -135,4 +135,8 @@ public class BookMarkFragment extends BasicFragment implements MarkActivity.Sor
isAsc =!isAsc;
initData();
}
@Override
public void refresh() {
}
}

View File

@ -69,7 +69,7 @@ public class CatalogFragment extends BasicFragment implements MarkActivity.Sortc
boolean isFirstLoad = true;
@Override
protected void fillData() {
catalogueList.clear();
catalogueList.addAll(pageFactory.getChapters());
// int currentChp =pageFactory.getCurrentChapter()-1;
@ -153,7 +153,7 @@ public class CatalogFragment extends BasicFragment implements MarkActivity.Sortc
new Thread() {
@Override
public void run() {
ArrayList<Chapter> list =(ArrayList<Chapter>) LitePal.where("novelId=?" ,pageFactory.getNovle().getId()+"").find(Chapter.class);
ArrayList<Chapter> list =(ArrayList<Chapter>) LitePal.where("novelId=? and domain =? " ,pageFactory.getNovle().getId()+"",pageFactory.getSite().getDomain()).find(Chapter.class);
File file;
for(Chapter cp : list){
if(!TextUtils.isEmpty(cp.getChapterPath())) {
@ -234,7 +234,7 @@ public class CatalogFragment extends BasicFragment implements MarkActivity.Sortc
// 开始刷新设置当前为刷新状态
//swipeRefreshLayout.setRefreshing(true);
isAsc =true;
// isAsc =true;
refresh(btnRefresh);
}
@ -268,4 +268,9 @@ public class CatalogFragment extends BasicFragment implements MarkActivity.Sortc
}
@Override
public void refresh() {
refresh(null);
}
}

View File

@ -8,6 +8,7 @@ import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.BottomSheetDialog;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
@ -34,6 +35,7 @@ import com.novelbook.android.netutils.OnSuccessAndFaultListener;
import com.novelbook.android.netutils.OnSuccessAndFaultSub;
import com.novelbook.android.utils.Constants;
import com.novelbook.android.utils.GsonUtil;
import com.novelbook.android.utils.ImageUtil;
import com.novelbook.android.utils.MyImageLoader;
import com.novelbook.android.utils.OnItemClickListener;
import com.novelbook.android.adapter.BookListAdapter;
@ -92,6 +94,9 @@ public class Fragment_Shelf extends BasicFragment {
bookLists = Novel.getNovelsOnShelf();
noveIds="";
for(Novel novel:bookLists){
if(novel.isFinished()||novel.isLocalBook() ||novel.isUpdated() ){
continue;
}
noveIds+=novel.getNovelId()+",";
}
}
@ -135,34 +140,7 @@ void test(int maxAge){
* to get updated info from server,TODO: put it in service ,scheduled
*/
private void getUpdatedData(){
/* try {
test(3600);
Thread.sleep(1000);
test(3600);
Thread.sleep(1000);
test(0);
Thread.sleep(1000);
test(3600);
Thread.sleep(1000);
test(0);
Thread.sleep(1000);
test(-1);
Thread.sleep(1000);
test(3600);
Thread.sleep(1000);
test(-1);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
List<Integer> novelIds;
OnSuccessAndFaultListener successAndFaultListener = new OnSuccessAndFaultListener() {
@ -177,8 +155,13 @@ void test(int maxAge){
for (Novel novel2 : lstUpdate) {
novel2.checkAndUpdate();
}
loadNovelsOnShelf();
}
loadNovelsOnShelf();
/* for(Novel nove : bookLists){
nove.testUpdate();
}*/
} catch (Exception e) {
e.printStackTrace();
@ -196,8 +179,13 @@ void test(int maxAge){
};
if(TextUtils.isEmpty(noveIds)){
loadNovelsOnShelf();
}
if(!TextUtils.isEmpty(noveIds)){
BookSubscribe.getNovelsByIds(noveIds , new OnSuccessAndFaultSub(successAndFaultListener, getActivity()));
}else{
handler.sendEmptyMessage(1);
}
}
@ -210,7 +198,7 @@ void test(int maxAge){
// bookLists = LitePal.where("isOnShelf=? or novelId=? ","1","").find(Novel.class);
loadNovelsOnShelf();
getUpdatedData();
// getUpdatedData();
flag = new boolean[bookLists.size()];
/* if(bookLists.size()>0) { //TODO: to remove
@ -249,6 +237,22 @@ void test(int maxAge){
((Main2Activity) activity).setShelfFragment(this);
}
@Override
void initSwipeRefreshLayout(){
super.initSwipeRefreshLayout();
mSwipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
// 开始刷新设置当前为刷新状态
//swipeRefreshLayout.setRefreshing(true);
pageNo=1;
getUpdatedData();
// TODO 获取数据
}
});
}
@Override
public void initViews(){
initReceyleView();
@ -329,9 +333,14 @@ void test(int maxAge){
bottomSheetDialog.getDelegate().findViewById(android.support.design.R.id.design_bottom_sheet)
.setBackgroundColor(getResources().getColor(android.R.color.transparent));
TextView tv =(TextView) bottomSheetDialog.findViewById(R.id.bdTitle);
TextView tvTitle =(TextView) bottomSheetDialog.findViewById(R.id.bdTitle);
tv.setText(bookLists.get(position).getName());
tvTitle.setText(bookLists.get(position).getName());
TextView tvAuthor =(TextView) bottomSheetDialog.findViewById(R.id.tvAuthor);
tvAuthor.setText(bookLists.get(position).getAuthor());
ImageView imageView = (ImageView) bottomSheetDialog.findViewById(R.id.imageG1);
ImageUtil.loadImage(activity,bookLists.get(position).getCover(),imageView);
LinearLayout lldetail=(LinearLayout) bottomSheetDialog.findViewById(R.id.llBookdetail);
lldetail.setOnClickListener(new View.OnClickListener() {
@ -339,6 +348,9 @@ void test(int maxAge){
showBookDetail(bookLists.get(position));
}
});
bottomSheetDialog.show();
}
@ -416,6 +428,7 @@ void test(int maxAge){
@Override
public void onResume() {
super.onResume();
getUpdatedData(); //TODO: 更新书的状态是不有更新
}

View File

@ -38,6 +38,9 @@ public class MarkActivity extends Activity_base {
// ListView lv_catalogue;
@BindView(R.id.btnSort)
ImageButton ibSort;
@BindView(R.id.btnRefresh)
ImageButton btnRefresh;
private PageFactory pageFactory;
/* private Config config;
@ -97,7 +100,7 @@ public class MarkActivity extends Activity_base {
protected void initListener() {
}
@OnClick(R.id.btnSort)
@OnClick({R.id.btnSort,R.id.btnRefresh})
void Onclick(View view){
if(view.getId() == R.id.btnSort){
Log.d(TAG, "Onclick: sorted");
@ -108,6 +111,17 @@ public class MarkActivity extends Activity_base {
if(sortmark!=null){
sortmark.sortList();
}
}else{
if(view.getId() == R.id.btnRefresh){{
if(sortcat!=null){
sortcat.refresh();
}
if(sortmark!=null){
sortmark.refresh();
}
}}
}
}
@ -124,8 +138,10 @@ public class MarkActivity extends Activity_base {
}
public interface Sortmark {
public void sortList();
public void refresh();
}
public interface Sortcat {
public void sortList();
public void refresh();
}
}

View File

@ -4,6 +4,7 @@ import android.app.Application;
import android.content.Context;
import com.novelbook.android.utils.Config;
import com.novelbook.android.utils.LogcatHelper;
import com.novelbook.android.utils.PageFactory;
import org.litepal.LitePal;
@ -16,7 +17,7 @@ public class MyApp extends Application {
applicationContext = getApplicationContext();
Config.createConfig(this);
PageFactory.createPageFactory(this);
LogcatHelper.getInstance(this).start();
// BlurKit.init(this);
LitePal.initialize(this);

View File

@ -587,6 +587,7 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
bookMarks.setNovelId(pageFactory.getNovle().getId());
bookMarks.setChapt(pageFactory.getCurrentChapter());
bookMarks.setChaptName(((pageFactory.getChapters().get(bookMarks.getChapt()-1).getChapterName())));
bookMarks.setDomain(pageFactory.getSite().getDomain());
bookMarks.save();
Toast.makeText(ReadActivity.this, "书签添加成功", Toast.LENGTH_SHORT).show();
@ -620,15 +621,17 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
}
}*/
else if (id == R.id.action_change_source) {
// if( pageFactory.getChapters().size()>0) {
// if( pageFactory.getChapters().size()>0) {
Intent intent = new Intent(ReadActivity.this, Activity_ChgSource.class);
intent.putExtra(Activity_ChgSource.EXTR_ID, pageFactory.getCurrentChapter());
intent.putExtra(Activity_ChgSource.EXTR_TITLE, pageFactory.getChapterName());
intent.putExtra(Activity_ChgSource.EXTR_SITE, pageFactory.getSite());
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_NAME, pageFactory.getSite().getName());
startActivity(intent);
// }else{
// }
hideReadSetting();
// }else{
// Toast.makeText(this,"换源不可用,请返回重试...",Toast.LENGTH_SHORT);
// }
}
return super.onOptionsItemSelected(item);

View File

@ -210,7 +210,8 @@ public class BookListAdapter extends RecyclerView.Adapter< RecyclerView.ViewHol
if (holder.tvStatus != null) holder.tvStatus.setText(mDatas.get(position).getProgress());
if (holder.imageView != null && !TextUtils.isEmpty(mDatas.get(position).getCover())) {
ImageUtil.loadImage(context, mDatas.get(position).getCover(), holder.imageView);
} if (holder.imageUpdate != null) {
}
if (holder.imageUpdate != null) {
if( mDatas.get(position).isUpdated()){
holder.imageUpdate.setVisibility(View.VISIBLE);
}else{

View File

@ -14,6 +14,15 @@ public class BookMarks extends LitePalSupport {
private String text;
private String time;
private int novelId;
private String domain;
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
public int getId() {
return this.id;

View File

@ -20,6 +20,24 @@ public class Chapter extends LitePalSupport implements Serializable {
private String domain; //目标 site
private int index;//第几章
public static Chapter getChapter(int id, String domain, int chapId) {
// Chapter chapter =(Chapter)
List<Chapter> lst = LitePal.where("novelId=? and domain = ? and index = ?", id + "", domain, chapId + "").limit(1).find(Chapter.class);
if (lst.size() > 0) {
return lst.get(0);
}
Chapter chapter = new Chapter();
chapter.setDomain(domain);
chapter.setIndex(chapId);
chapter.setNovelId(id);
chapter.setChapterName("");
chapter.setChapterUrl("");
chapter.setChapterPath("");
return chapter;
}
public int getIndex() {
return index;
}

View File

@ -2,6 +2,7 @@ package com.novelbook.android.db;
import android.text.TextUtils;
import android.util.Log;
import com.novelbook.android.utils.Constants;
@ -274,7 +275,7 @@ public class Novel extends LitePalSupport implements Serializable{
}
public static List<Novel> getNovelsOnShelf(){
return LitePal.where("isOnShelf=?","1").find(Novel.class);
return LitePal.where("isOnShelf=?","1").order("isTop desc,isUpdated desc,lastVisit desc" ).find(Novel.class);
}
public static List<Novel> getLocalNovels(){
@ -310,12 +311,24 @@ public class Novel extends LitePalSupport implements Serializable{
setValues();
return super.update(id);
}
public void testUpdate(){
isUpdated=true;
super.update(id);
}
public int checkAndUpdate(){
Novel nv = getNovelBySvrId(novelId);
if(lastUpdateTime > nv.lastVisit || lastUpdateTime > nv.lastUpdateTime){
/* if(lastUpdateTime > nv.lastVisit && lastUpdateTime > nv.lastUpdateTime){
isUpdated =true;
}*/
isUpdated =lastUpdateTime > nv.lastVisit && lastUpdateTime > nv.lastUpdateTime;
Log.d("Novel", String.format("book %s server lastUpdateTime %s, local lastupdatetime %s, local lastvist %s" +
"is updated %s,diff1 %s,diff2 %s"
,name ,lastUpdateTime,nv.lastUpdateTime,nv.lastVisit,isUpdated,lastUpdateTime - nv.lastVisit,lastUpdateTime - nv.lastUpdateTime) );
if(!isUpdated){
setToDefault("isUpdated");
}
return super.update(nv.id);
}
public int getMaxAge(){

View File

@ -48,7 +48,7 @@ public class HttpMethods {
/**
* 请求失败重连次数
*/
private int RETRY_COUNT = 3;
private int RETRY_COUNT = 0;
private OkHttpClient.Builder okHttpBuilder;
private OkHttpClient okHttpClient;
//构造方法私有
@ -56,6 +56,7 @@ public class HttpMethods {
okHttpClient = getClient();
retrofit = new Retrofit.Builder()
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())//json转换成JavaBean
@ -131,12 +132,15 @@ public class HttpMethods {
Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
Log.d(TAG, "getClient: to set cach control");
// okHttpBuilder.cache(cache).addInterceptor(cacheInterceptor);
okHttpBuilder.cache(cache) .addNetworkInterceptor(REWRITE_RESPONSE_INTERCEPTOR)
okHttpBuilder.cache(cache)
//.addNetworkInterceptor(REWRITE_RESPONSE_INTERCEPTOR)
.addInterceptor(REWRITE_RESPONSE_INTERCEPTOR_OFFLINE);
/**
* 设置头信息
*/
Interceptor headerInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
@ -154,7 +158,7 @@ public class HttpMethods {
// .addHeader("Accept", "application/json")
// .addHeader("Content-Type", "application/json; charset=utf-8")
// .addHeader("Device", "Android")
.removeHeader("User-Agent").addHeader("User-Agent",NetUtil.getUserAgent()) // 随机agent
.removeHeader("User-Agent").addHeader("User-Agent",NetUtil.getUserAgent()) // 随机agent
.tag(NetUtil.currentRequestTag)
.method(originalRequest.method(), originalRequest.body());

View File

@ -205,8 +205,8 @@ public class NetUtil {
"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 (KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
};
return uas[new Random().nextInt(uas.length-1)];
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/73.0.3683.103 Safari/537.36";
}
public static String getCoverUrl(String url){

View File

@ -6,6 +6,7 @@ import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
@ -120,7 +121,13 @@ public class BookUtil {
private Map<Integer,DownloadStatus> chaptDownStatus = new HashMap<Integer, DownloadStatus>();
DownloadStatus downloadStatus = DownloadStatus.notStart;
public Chapter getChapter(int chapId){
if(chapId > mChapters.size() || mChapters.size() ==0){
return Chapter.getChapter(mNovel.getId(), mNovel.getDomain(),chapId);
}else{
return mChapters.get(chapId-1);
}
}
public NovelSites getmNovelSites() {
@ -162,6 +169,8 @@ public class BookUtil {
if( file.exists()){
Log.d(TAG, String.format("prepare book open chapter file %s, exist,not waiting more...to open file...",fileChapterName((int)chapter) ));
return;
}
@ -265,12 +274,14 @@ public class BookUtil {
}
},null));
}
int siteRuleRetryCnt =0;
public void getSiteRule() {
mSiteRule = null;
BookSubscribe.getSiteRule(mSite.getDomain(),new OnSuccessAndFaultSub(new OnSuccessAndFaultListener() {
@Override
public void onSuccess(String result) {
siteRuleRetryCnt =0;
Log.d(TAG, "prepare book siteRule:" +result);
//成功
SiteRule sr= new SiteRule();
@ -290,6 +301,9 @@ public class BookUtil {
sr.save();
}
mSiteRule =sr;
if(TextUtils.isEmpty(mSite.getName())){
mSite.setName(sr.getName());
};
setSiteInfo();
Log.d(TAG, String.format("prepare book %s 目录正则表达式下载完成,开始读章节信息. muluRegex size %s, thread %s ",mNovel.getName(),mSiteRule.getChapterUrlRegexOnMulu().length, Thread.currentThread().getName()) );
@ -309,13 +323,13 @@ public class BookUtil {
try {
JSONObject siteJson = new JSONObject(result);
mChapters = NovelParseUtil.getChapters(mSite.getMuluUrl(), siteJson,mSite.getDomain(),mNovel.getMaxAge(),mSiteRule.getEncoding());
mChapters = NovelParseUtil.getChapters(mSite.getMuluUrl(), siteJson,mSite.getDomain(),mNovel.getMaxAge(),mSiteRule);
if (mChapters != null){
/* if (mChapters != null){
for (Chapter chapter:mChapters) {
Log.d(TAG, String.format("prepare book to get chaps readChaptersAsync %s-->%s",chapter.getChapterUrl(), chapter.getChapterName()));
Log.i(TAG, String.format("prepare book to get chaps readChaptersAsync %s-->%s",chapter.getChapterUrl(), chapter.getChapterName()));
}
}
}*/
} catch (JSONException e) {
@ -345,7 +359,11 @@ public class BookUtil {
@Override
public void onFault(String errorMsg) {
//失败
Log.d(TAG,"error on get sitRule: "+errorMsg);
Log.e(TAG,"error on get sitRule: "+errorMsg);
siteRuleRetryCnt++;
if(siteRuleRetryCnt <Constants.retryCnt){
getSiteRule();
}
}
},mContext));
@ -371,11 +389,17 @@ public class BookUtil {
}
public int getChapterNo() {
if(chapterNo > mChapters.size()){
Log.d(TAG, String.format(" prepare book getChapterNo ,chapterNo %s, getChapters().size() %s " ,chapterNo , mChapters.size()) );
chapterNo =1;
Log.d(TAG, String.format(" prepare book getChapterNo ,chapterNo %s, getChapters().size() %s ,mChangeChapId %s" ,chapterNo , mChapters.size(),mChangeChapId) );
if(mChangeChapId>0){
return mChangeChapId;
}
// chapterNo=1;
}
Log.d(TAG, String.format(" prepare book getChapterNo ,chapterNo %s, getChapters().size() %s " ,chapterNo , mChapters.size()) );
chapterNo = chapterNo<=0 ?1 :chapterNo;
Log.d(TAG, String.format(" prepare book getChapterNo ,chapterNo %s, getChapters().size() %s " ,chapterNo , mChapters.size()) );
return chapterNo;
}
@ -409,16 +433,13 @@ public class BookUtil {
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) );
if(mSite.getDomain().equals(domain)){ //当前源
Log.d(TAG, "changing Source: same site with original " + domain);
return;
}
this.muluRetryCount=0;
this.downloadStatus = DownloadStatus.notStart;
chaptDownStatus.clear();
chaptCache.clear();
// isDownloadChapt =false;
mChangeChapId = chapId;
mChangeTitle =chapTitle;
for (Site site:mNovelSites.getSites() ) {
@ -443,8 +464,8 @@ public class BookUtil {
}
public String getSite() {
return mSite !=null? mSite.getDomain():"";
public Site getSite() {
return mSite !=null? mSite :new Site();
}
public boolean chaptCached(int num) {
@ -465,34 +486,67 @@ public class BookUtil {
return;
}
if (result) {
Log.d(TAG, "changing Source:successed get chapters for " + mSite.getDomain() );
Log.d(TAG, String.format("changing Source: target domain %s chaptId %s, chapt title %s,mChangeChapId %s "
,domain,chapId,chapTitle,mChangeChapId) );
int chId=chapterNo;
String title ="";
mChangeChapId = mChangeChapId >=1 ?mChangeChapId :1;//TODO: mChangeChapId 换源时不要变
if( mChapters.size() >= mChangeChapId && mChapters.get(mChangeChapId-1)!=null ){
title= mChapters.get(mChangeChapId-1).getChapterName();
Log.d(TAG, "changing Source:chapter name in new site " + title );
}
if(title.equals(mChangeTitle)) {
if(title.equals(mChangeTitle) || title.contains(mChangeTitle) || mChangeTitle.contains(title)) {
Log.d(TAG, "changing Source:successed find chapter by original chaptId " + mChangeChapId + ":" + mChangeTitle);
chId = mChangeChapId;
}
else {
int i = 1;
for (Chapter chapter : mChapters) {
Log.d(TAG, "changing Source: finding chapter " + i + ":" + chapter.getChapterName());
// Log.d(TAG, "changing Source: finding chapter " + i + ":" + chapter.getChapterName());
if (chapter.getChapterName().equals(mChangeTitle)) {
Log.d(TAG, "changing Source:successed find chapter by original title " + i + ":" + mChangeTitle);
chId = i;
title = mChangeTitle;
break;
}
i++;
}
if (!title.equals(mChangeTitle)) {
i = 1;
for (Chapter chapter : mChapters) {
// Log.d(TAG, "changing Source: finding chapter " + i + ":" + chapter.getChapterName());
if (chapter.getChapterName().contains(mChangeTitle)) {
Log.d(TAG, "changing Source:successed find chapter by original title " + i + ":" + mChangeTitle);
chId = i;
title = chapter.getChapterName();
break;
}
i++;
}
}
if (!title.contains(mChangeTitle)) {
i = 1;
for (Chapter chapter : mChapters) {
// Log.d(TAG, "changing Source: finding chapter " + i + ":" + chapter.getChapterName());
if (mChangeTitle.contains(chapter.getChapterName())) {
Log.d(TAG, "changing Source:successed find chapter by original title " + i + ":" + mChangeTitle);
chId = i;
title = chapter.getChapterName();
break;
}
i++;
}
}
}
chId = chId <= mChapters.size() ? chId: mChapters.size();
Log.d(TAG, "changing Source: to open chapter with new site source " + chId + " : "+ mChangeTitle );
pagefactory.changeChapter(chId);
mChangeChapId=0;
Toast.makeText(mContext,"换源成功",Toast.LENGTH_LONG).show();
}else{
Log.d(TAG, "changing Source: failed " );
@ -541,7 +595,7 @@ public class BookUtil {
* @param chapId
* @param chapTitle
*/
public void changeSourceNewThread(String domain,int chapId,String chapTitle) {
/* public void changeSourceNewThread(String domain,int chapId,String chapTitle) {
Log.d(TAG, String.format("changing Source: target domain %s chaptId %s, chapt title %s ",domain,chapId,chapTitle) );
if(mSite.getDomain().equals(domain)){ //当前源
Log.d(TAG, "changing Source: same site with original " + domain);
@ -568,7 +622,7 @@ public class BookUtil {
}.start();
/*
*//*
while(isChangeSource){
try {
Thread.sleep(50);
@ -584,10 +638,10 @@ public class BookUtil {
Log.d(TAG, "changing Source: to get site rule" );
getSiteRule();
}
}.start();*/
}.start();*//*
}
*/
enum MuluStatus{
isDownloading,
isDone,
@ -652,7 +706,7 @@ int muluRetryCount =0;
Log.e(TAG, "prepare book loadChapts---- failed: ", e);
Log.d(TAG, String.format("prepare book loadChapts---- failed %s 目录 from %s", mNovel.getName(), url));
handler.sendEmptyMessage(3);
// handler.sendEmptyMessage(3);
//TODO 如果是取消了访问则返回
if (e.toString().contains("closed") || e.getMessage().contains("Canceled")) {
@ -663,16 +717,24 @@ int muluRetryCount =0;
}
mMuluStatus = MuluStatus.failed;
if (muluRetryCount < Constants.retryCnt) {
if (muluRetryCount < Constants.muluRetryCnt) {
try {
Thread.sleep(50);
long sleeptime =500;
if(mSiteRule!=null) {
sleeptime = mSiteRule.getMiniInterval4AccessChapter();
}
Thread.sleep(sleeptime);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
muluRetryCount++;
Log.d(TAG,String.format("prepare book loadChapts----failed, retrying count %s",muluRetryCount ));
readChaptersAsync();
return;
}
Log.d(TAG,String.format("prepare book loadChapts----failed, site count %s",mNovelSites.getSites().length ));
if (mNovelSites.getSites().length == 1) { //仅有一个rule,且失败了
// mMuluStatus = MuluStatus.failed;
@ -681,17 +743,33 @@ int muluRetryCount =0;
}
//try next site
Message msg =Message.obtain();
msg.what =99;
msg.arg1 =chapterNo;
Bundle bundleData = new Bundle();
for (Site st : mNovelSites.getSites()) {
if (!st.getDomain().equals(mSite.getDomain())) {
mSite = st;
//mSite = st;
mNovel.setDomain(st.getDomain());
bundleData.putString("siteName", st.getName());
msg.setData(bundleData);
break;
}
}
// mNovel.setDomain(mSite.getDomain());
muluRetryCount=0;
fileRetryCnt.clear();
siteRuleRetryCnt=0;
chaptCache.clear();
handler.sendMessage(msg);
// handler.sendEmptyMessage(99);
// readChaptersAsync();
getSiteRule();
}
@ -701,7 +779,7 @@ int muluRetryCount =0;
if(response.code()!=200){
Log.d(TAG,String.format("prepare book loadChapts----failed, %s 目录 from %s,return code %s", mNovel.getName() ,url,response.code() ));
handler.sendEmptyMessage(3);
// handler.sendEmptyMessage(3);
mMuluStatus = MuluStatus.failed;
if(muluRetryCount <Constants.retryCnt){
Log.d(TAG,String.format("prepare book loadChapts----failed, response code %s retrying count %s",response.code(), muluRetryCount ));
@ -711,6 +789,7 @@ int muluRetryCount =0;
return;
}
// mChangeChapId =0;
muluRetryCount =0;
if (body != null) {
Log.d(TAG, String.format("prepare book %s 章节信息读取成功.thread %s",mNovel.getName(),Thread.currentThread().getName()) );
@ -725,12 +804,12 @@ int muluRetryCount =0;
Log.d(TAG,String.format("prepare book loadChapts----end download %s 目录, 目录数量 %s, cost %s", mNovel.getName() , mChapters.size(), new Date().getTime() -startTime ));
mMuluStatus = MuluStatus.isDone;
Log.d(TAG, String.format("prepare book %s 章节信息完成.",mNovel.getName()) );
handler.sendEmptyMessage(3); //通知换源过程已读到目录
} catch (IOException e) {
e.printStackTrace();
}finally {
body.close();
handler.sendEmptyMessage(3);
}
}
@ -1164,21 +1243,21 @@ int muluRetryCount =0;
return block;
}
boolean isDownloadChapt =false;
/*boolean isDownloadChapt =false;
synchronized boolean getDownloadStatus(){
return isDownloadChapt;
}
synchronized void setDownloadFlag(boolean flag){
isDownloadChapt = flag;
Log.d(TAG,String.format("set download flat",isDownloadChapt) );
}
}*/
public ChangeSource pagefactory;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
int wt = msg.what;
Log.d(TAG, String.format("prepare book get message what %s ,obj %s",msg.what,msg.obj));
handlerMsg(msg);
}
@ -1188,10 +1267,22 @@ int muluRetryCount =0;
void handlerMsg(Message msg){
if (msg.what == 123) {
isDownloadChapt =true;
Log.d(TAG,String.format("handler msg, download %s",isDownloadChapt) );
}else if(msg.what==1){
isDownloadChapt =true;
// isDownloadChapt =true;
Log.d(TAG,String.format("handler msg, download %s",true) );
}else if(msg.what==99){
// Toast.makeText(mContext,"网络拥堵,将帮您切换其它源",Toast.LENGTH_SHORT);
// getSiteRule();
// pagefactory .changeChapter(getChapterNo());
String targetSiteName = msg.getData().getString("siteName");
Log.d(TAG, String.format("prepare book changing Source:target %s -- %s to open chapter %s"
,mNovel.getDomain(),targetSiteName,msg.arg1));
pagefactory.changeSource(targetSiteName, mNovel.getDomain(),msg.arg1,getChapter(msg.arg1).getChapterName());
// isDownloadChapt =true;
// Toast.makeText(mContext,"网络错误",Toast.LENGTH_LONG).show();
}else if(msg.what==3){ //change source
isChangeSource =false;
@ -1292,9 +1383,14 @@ int muluRetryCount =0;
, Thread.currentThread().getName()));
if (mMuluStatus == null) {
Log.d(TAG, String.format("prepare book loadChapts---- 还未有目录信息,出错了 %s 目录, 目录数量 %s, MuluStatus %s ,thread %s", mNovel.getName(), mChapters.size(), mMuluStatus, Thread.currentThread().getName()));
Log.e(TAG, String.format("prepare book loadChapts---- 还未有目录信息,出错了 %s 目录, 目录数量 %s, MuluStatus %s ,thread %s", mNovel.getName(), mChapters.size(), mMuluStatus, Thread.currentThread().getName()));
// getTargetSites();
}
if( mChapters.size() ==0) {
if (mMuluStatus == MuluStatus.isDone){
getSiteRule();
}
}
int slept = 0;
while (NetUtil.isNetworkConnected() && slept < 100 && mMuluStatus == MuluStatus.isDownloading) {
try {
@ -1316,15 +1412,14 @@ int muluRetryCount =0;
Log.d(TAG, String.format("prepare book loadChaptContent----start %s", new Date().toString()));
Log.d(TAG, String.format("prepare book isDownloadChapt: %s", isDownloadChapt));
if (!chaptDownStatus.containsKey(Integer.valueOf(index))) {
chaptDownStatus.put(index, DownloadStatus.downloading);
Log.d(TAG, String.format("prepare book put chaptDownStatus index %s,start to load chapcontent", index));
loadChaptContent(index);
}
Log.d(TAG, String.format(" prepare book loadChaptContent %s for downloading,isDownload %s chaptDownStatus %s, thread %s ",
index,getDownloadStatus(), chaptDownStatus.get(Integer.valueOf(index)), Thread.currentThread().getName()));
Log.d(TAG, String.format(" prepare book loadChaptContent %s for downloading, chaptDownStatus %s, thread %s ",
index, chaptDownStatus.get(Integer.valueOf(index)), Thread.currentThread().getName()));
int maxSleep = 4500;
@ -1340,7 +1435,7 @@ int muluRetryCount =0;
while (!file.exists() && NetUtil.isNetworkConnected() && chaptDownStatus.get(Integer.valueOf(index)) == DownloadStatus.downloading && slepttime < maxSleep) {
Thread.sleep(50);
slepttime += 50;
Log.d(TAG, String.format(" prepare book loadChaptContent %s , slept %s for downloading,isDownload %s thread %s ",index, slepttime, getDownloadStatus(), Thread.currentThread().getName()));
Log.d(TAG, String.format(" prepare book loadChaptContent %s , slept %s for downloading, thread %s ",index, slepttime, Thread.currentThread().getName()));
}
Log.d(TAG, String.format("prepare book loadChaptContent slept %s for downloading ", slepttime));
@ -1353,8 +1448,9 @@ int muluRetryCount =0;
Log.d(TAG, String.format("prepare book loadChaptContent %s, rertying count %s ",index, fileRetryCnt.get(index)));
if (fileRetryCnt.get(index) < Constants.retryCnt) {
Log.d(TAG, String.format("prepare book loadChaptContent ,rertying to download chapt %s ", index));
loadChaptContent(index);
loadChaptContent(index);
Thread.sleep(mSiteRule.getMiniInterval4AccessChapter());
}
}
}
@ -1366,8 +1462,13 @@ int muluRetryCount =0;
error = "连不上网络";
}
loadChaptContent(index);
chaptDownStatus.put( index , DownloadStatus.failure);
Log.d(TAG, String.format("prepare book loadChaptContent retrying " ));
// return chaptChars( index);
return error.toCharArray();
}
if (mChapters.size() > index && NetUtil.isNetworkConnected()) {
@ -1397,7 +1498,7 @@ int muluRetryCount =0;
}
}
// mChangeChapId =0;
int size = (int) file.length();
if (size < 0) {
Log.e(TAG, "prepare book chaptChars: Error during reading"+ fileChapterName(index) );
@ -1464,15 +1565,15 @@ private void loadChaptContent(final int chapterIndex) throws JSONException, Inte
return ;
}
long startTime= new Date().getTime();
Log.d(TAG,String.format("loadChaptContent----start download %s from %s", chapter.getChapterName() ,url ));
Log.d(TAG,String.format("prepare book loadChaptContent----start download %s from %s", chapter.getChapterName() ,url ));
// setDownloadFlag(false);
setDownloadFlag(false);
Log.d( TAG,String.format("loadChaptContent isDownloadChapt: %s",isDownloadChapt));
JSONObject siteJson = new JSONObject();
siteJson.put("chapterContentRegex", mSiteRule.getChapterContentRegex());
siteJson.put("chapterContentDumpRegex", mSiteRule.getChapterContentDumpRegex());
Request request = getTagRequest(url, 0);
Request request = getTagRequest(url, -1);
HttpMethods.getOkClient().newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
@ -1486,8 +1587,8 @@ private void loadChaptContent(final int chapterIndex) throws JSONException, Inte
chaptDownStatus.put(index,DownloadStatus.failure);
setDownloadFlag(true);
Log.d( TAG,String.format("prepare book loadChaptContent fail, isDownloadChapt: %s",isDownloadChapt));
// setDownloadFlag(true);
Log.d( TAG,String.format("prepare book loadChaptContent fail, isDownloadChapt: %s",false));
e.printStackTrace();
// throw new RuntimeException("Error during writing " + fileChapterName( index));
}
@ -1499,22 +1600,27 @@ private void loadChaptContent(final int chapterIndex) throws JSONException, Inte
if (body != null ) {
if(response.code()!=200){
Log.d(TAG, "prepare book loadChaptContent----network failure returnCode " + response.code());
setDownloadFlag(true);
// setDownloadFlag(true);
chaptDownStatus.put(index,DownloadStatus.failure);
Log.d( TAG,String.format("prepare book loadChaptContent error %s ,isDownloadChapt: %s", response.code(),isDownloadChapt));
Log.d( TAG,String.format("prepare book loadChaptContent error %s ,isDownloadChapt: %s", response.code(),false));
handler.sendEmptyMessage(1);
return;
}
try {
Charset charset = body.contentType().charset();
/* Charset charset = body.contentType().charset();
if(charset!=null){
String name = charset.displayName();
}
}*/
// String bodyStr = body.string();
// bodyStr =NovelParseUtil.enconding(bodyStr,mSiteRule.getEncoding());
String bodyStr =NovelParseUtil.enconding(body,mSiteRule.getEncoding());
if(TextUtils.isEmpty(bodyStr)){
Log.d( TAG,String.format("prepare book loadChaptContent %s isEmpty,retry....", index, Thread.currentThread().getName()));
chaptDownStatus.put(index,DownloadStatus.failure);
return;
}
String title = chapter.getChapterName();
String chapterContent = title+ "\n" + NovelParseUtil.getChapterContent(bodyStr, siteJson);
char[] buf = chapterContent.toCharArray();
@ -1527,7 +1633,7 @@ private void loadChaptContent(final int chapterIndex) throws JSONException, Inte
writer.close();
Log.d( TAG,String.format("prepare book loadChaptContent file created: %s, thread %s", file.getPath(), Thread.currentThread().getName()));
handler.sendEmptyMessage(123);
setDownloadFlag(true);
// setDownloadFlag(true);
} catch (IOException | JSONException e) {
e.printStackTrace();
Log.e(TAG, "onResponse: prepare book error ",e );
@ -1539,16 +1645,17 @@ private void loadChaptContent(final int chapterIndex) throws JSONException, Inte
body.close();
handler.sendEmptyMessage(123);
setDownloadFlag(true);
// setDownloadFlag(true);
}
chapter.setNovelId(mNovel.getId());
chapter.setChapterPath(fileChapterName(index));
chapter.setDomain(mSite.getDomain());
if(chapter.getId()>0) {
chapter.update(chapter.getId());
}else{
chapter.save();
}
setDownloadFlag(true);
//setDownloadFlag(true);
chaptDownStatus.put(index,DownloadStatus.success);
Log.d(TAG,String.format(" prepare book loadChaptContent---- finished download %s, cost time %s ,content path %s ,thread %s", chapter.getChapterName(), new Date().getTime() -startTime ,chapter.getChapterPath() , Thread.currentThread().getName() ));
@ -1570,18 +1677,26 @@ private void loadChaptContent(final int chapterIndex) throws JSONException, Inte
Request.Builder builder = new Request.Builder()
.tag(mNovel.getNovelId()) //标记 请求的tag,切换小说或离开小说界面(BookActivity) 取消未执行完毕的 此tag的所有请求
.url(url)
.removeHeader("Pragma")
.header("Cache-Control", "public, max-age=" + maxAge)
.removeHeader("Pragma");
.header("Accept-Language","zh-CN,zh;q=0.9")
.header( "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
.header( "Upgrade-Insecure-Requests", "1")
for(int i=0;i<mSiteRule.getHeaders().length;i+=2){
builder.header(mSiteRule.getHeaders()[i],mSiteRule.getHeaders()[i+1]);
}
// .header( "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
// .header( "Upgrade-Insecure-Requests", "1")
// .header("content-type", "text/html; charset=utf-8")
// .header("Content-Type", "text/plain; charset=utf-8")
// .header( "Accept", "*/*")
;
/* if(mSiteRule!=null && !TextUtils.isEmpty(mSiteRule.getEncoding()) ){
builder.header("Accept-Encoding",mSiteRule.getEncoding());
}
*/
*/ if(maxAge>0) {
builder. header("Cache-Control", "public, max-age=" + maxAge);
}
return builder.build();
}

View File

@ -2,4 +2,5 @@ package com.novelbook.android.utils;
public interface ChangeSource {
public void changeChapter(int chapNum);
public void changeSource(String domainName,String domain,int chapId,String chapTitle);
}

View File

@ -457,6 +457,17 @@ public class CommonUtil {
return days;
}
public static String getFileName() {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
String date = format.format(new Date(System.currentTimeMillis()));
return date;// 2012年10月03日 23:41:31
}
public static String getDateEN() {
SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1 = format1.format(new Date(System.currentTimeMillis()));
return date1;// 2012-10-03 23:41:31
}
/* public static boolean isNavigationBarShow(){

View File

@ -20,6 +20,7 @@ public class Constants {
//public static List<Progress> lstProgress=null;
public static String[] lstProgress={"连载中","已完本","新书"};
public static int retryCnt =10;
public static int muluRetryCnt =3;
// public static List<String> lstProgress=null;
public static boolean showDialogOnUi =true;
public static boolean showDialogOnUiPage =false;

View File

@ -11,6 +11,6 @@ public class ImageUtil {
public static MyImageLoader loader = new MyImageLoader();
public static void loadImage(Context context, String url, ImageView imageView){
loader.displayImage(context, NetUtil.getCoverUrl(url), imageView);
Log.d(TAG,"loading image url: " + NetUtil.getCoverUrl(url));
//Log.i(TAG,"loading image url: " + NetUtil.getCoverUrl(url));
}
}

View File

@ -0,0 +1,162 @@
package com.novelbook.android.utils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import android.content.Context;
import android.os.Environment;
/**
* log日志统计保存
*
* @author way
*
*/
public class LogcatHelper {
private static LogcatHelper INSTANCE = null;
private static String PATH_LOGCAT;
private LogDumper mLogDumper = null;
private int mPId;
/**
*
* 初始化目录
*
* */
public void init(Context context) {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {// 优先保存到SD卡中
PATH_LOGCAT = Environment.getExternalStorageDirectory()
.getAbsolutePath() + File.separator + "novelLog";
} else {// 如果SD卡不存在就保存到本应用的目录下
PATH_LOGCAT = context.getFilesDir().getAbsolutePath()
+ File.separator + "novelLog";
}
File file = new File(PATH_LOGCAT);
if (!file.exists()) {
file.mkdirs();
}
}
public static LogcatHelper getInstance(Context context) {
if (INSTANCE == null) {
INSTANCE = new LogcatHelper(context);
}
return INSTANCE;
}
private LogcatHelper(Context context) {
init(context);
mPId = android.os.Process.myPid();
}
public void start() {
if (mLogDumper == null)
mLogDumper = new LogDumper(String.valueOf(mPId), PATH_LOGCAT);
mLogDumper.start();
}
public void stop() {
if (mLogDumper != null) {
mLogDumper.stopLogs();
mLogDumper = null;
}
}
private class LogDumper extends Thread {
private Process logcatProc;
private BufferedReader mReader = null;
private boolean mRunning = true;
String cmds = null;
private String mPID;
private FileOutputStream out = null;
public LogDumper(String pid, String dir) {
mPID = pid;
try {
out = new FileOutputStream(new File(dir, "Novel-"
+ CommonUtil.getFileName() + ".log"));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/**
*
* 日志等级*:v , *:d , *:w , *:e , *:f , *:s
*
* 显示当前mPID程序的 E和W等级的日志.
*
* */
// cmds = "logcat *:e *:w | grep \"(" + mPID + ")\"";
// cmds = "logcat | grep \"(" + mPID + ")\"";//打印所有日志信息
// cmds = "logcat -s way";//打印标签过滤信息
// cmds = "logcat *:e *:i | grep \"(" + mPID + ")\"";
cmds = "logcat *:D | grep \"(" + mPID + ")\"";
}
public void stopLogs() {
mRunning = false;
}
@Override
public void run() {
try {
logcatProc = Runtime.getRuntime().exec(cmds);
mReader = new BufferedReader(new InputStreamReader(
logcatProc.getInputStream()), 1024);
String line = null;
while (mRunning && (line = mReader.readLine()) != null) {
if (!mRunning) {
break;
}
if (line.length() == 0) {
continue;
}
if (out != null && line.contains(mPID)) {
out.write((CommonUtil.getDateEN() + " " + line + "\n")
.getBytes());
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (logcatProc != null) {
logcatProc.destroy();
logcatProc = null;
}
if (mReader != null) {
try {
mReader.close();
mReader = null;
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
out = null;
}
}
}
}
}

View File

@ -1,16 +1,20 @@
package com.novelbook.android.utils;
import android.app.Application;
import android.content.Context;
import android.util.Log;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.novelbook.android.MyApp;
import com.novelbook.android.R;
public class MyImageLoader extends com.youth.banner.loader.ImageLoader {
@Override
public void displayImage(Context context, Object path, ImageView imageView) {
try {
Glide.with(context).load((String) path).into(imageView);
Glide.with(MyApp.applicationContext).load((String) path).error(R.drawable.googleg_standard_color_18).into(imageView);
}catch (Exception e){
Log.e("MyImageLoader", "displayImage: ",e );
}

View File

@ -75,13 +75,13 @@ public class NovelParseUtil {
String chapterUrlRegexOnMulu = siteJson.getString("chapterUrlRegexOnMulu");
String chapterUrlPattern = siteJson.getString("chapterUrlPattern");
Log.d(TAG, "getChaptersMap: chapterUrlRegexOnMulu: " + chapterUrlRegexOnMulu);
//Log.i(TAG, "getChaptersMap: chapterUrlRegexOnMulu: " + chapterUrlRegexOnMulu);
Map<String, String> muluMap = new LinkedHashMap<String, String>();
String regex = A_Regex;
if (!isBlank(chapterUrlRegexOnMulu)) {
regex = chapterUrlRegexOnMulu;
}
Log.d(TAG, "getChaptersMap: regex: " + regex);
//Log.i(TAG, "getChaptersMap: regex: " + regex);
String[] rows = REUtil.matchs(regex, html);;
if (rows == null || rows.length == 0) return null;
for (int i = rows.length - 1; i >= 0; i--) {
@ -157,12 +157,12 @@ public class NovelParseUtil {
return lst;
}
public static List<Chapter> getChapters(String url, JSONObject siteJson,String domain,int maxAage,String encoding) throws JSONException {
return getChaptersLst(getChapters(url,siteJson,maxAage,encoding),domain);
public static List<Chapter> getChapters(String url, JSONObject siteJson,String siteName,int maxAage,SiteRule siteRule) throws JSONException {
return getChaptersLst(getChapters(url,siteJson,maxAage,siteRule),siteName);
}
public static String[] getChapters(String url, JSONObject siteJson, int maxAge,String encoding) throws JSONException {
public static String[] getChapters(String url, JSONObject siteJson, int maxAge,SiteRule siteRule) throws JSONException {
//if (!siteJson.keys().("chapterUrlRegexOnMulu")) return null;
String chapterUrlRegexOnMulu = siteJson.getString("chapterUrlRegexOnMulu");
// if(TextUtils.isEmpty(chapterUrlRegexOnMulu)) return null;
@ -172,11 +172,11 @@ public class NovelParseUtil {
JSONArray muluArray = siteJson.getJSONArray("chapterUrlRegexOnMulu");
if (muluArray == null || muluArray.length()== 0) return null;
Log.d(TAG, "to get chaps muluArray is null: " +( muluArray ==null) );
//Log.i(TAG, "to get chaps muluArray is null: " +( muluArray ==null) );
Map<String, Object> context = new HashMap<String, Object>();
context.put("url", url);
Log.d(TAG, "to get chaps url:" + url );
//Log.i(TAG, "to get chaps url:" + url );
List<String> result = new ArrayList<String>();
// 最外部的大的规则对象
for (int i = 0; i < muluArray.length(); i++) {
@ -184,57 +184,57 @@ public class NovelParseUtil {
JSONObject regexsJson = muluArray.getJSONObject(i);
String source = regexsJson.getString("source");
source = getContent(source, context);
Log.d(TAG, "to get chaps source:" + source );
//Log.i(TAG, "to get chaps source:" + source );
if (source.startsWith("html:")) {
String _url = source.substring("html:".length());
source = access(_url,maxAge,encoding);
Log.d(TAG, "to get chaps source:" + source );
source = access(_url,maxAge,siteRule );
//Log.i(TAG, "to get chaps source:" + source );
}
// 第一次Regex对象
JSONArray regexsArray = regexsJson.getJSONArray("regexs");
Log.d(TAG, "to get chaps regexsArray.length():" + regexsArray.length() );
//Log.i(TAG, "to get chaps regexsArray.length():" + regexsArray.length() );
for (int j = 0; j < regexsArray.length(); j++) {
JSONObject regexJson = regexsArray.getJSONObject(j);
String[] values = null;
Log.d(TAG, "to get chaps regexJson.getBoolean(\"group\"):" + regexJson.getBoolean("group") );
//Log.i(TAG, "to get chaps regexJson.getBoolean(\"group\"):" + regexJson.getBoolean("group") );
if (regexJson.getBoolean("group")) {
values = REUtil.groups(regexJson.getString("regex"), source);
} else {
values = REUtil.matchs(regexJson.getString("regex"), source);
}
Log.d(TAG, "to get chaps values==null? :" + (values==null) );
//Log.i(TAG, "to get chaps values==null? :" + (values==null) );
for(String s:values){
Log.d(TAG, "to get chaps value :" + s);
//Log.i(TAG, "to get chaps value :" + s);
}
if (values != null) context.put(regexJson.getString("name"), values);
// String child = siteJson.getString("child");
Log.d(TAG, "to get chaps siteJson.has(\"child\")? :" + siteJson.has("child"));
//Log.i(TAG, "to get chaps siteJson.has(\"child\")? :" + siteJson.has("child"));
if ( regexJson.has("child") ) {
// 一般用来做返回结果用的
JSONObject childJson = regexJson.getJSONObject("child");
Log.d(TAG, "to get chaps childJson :" + childJson.toString());
//Log.i(TAG, "to get chaps childJson :" + childJson.toString());
for (String value : values) {
Log.d(TAG, "to get chaps value in values :" + value);
//Log.i(TAG, "to get chaps value in values :" + value);
String[] values2 = null;
Log.d(TAG, "to get chaps childJson.getBoolean(\"group\") :" + childJson.getBoolean("group"));
//Log.i(TAG, "to get chaps childJson.getBoolean(\"group\") :" + childJson.getBoolean("group"));
if (childJson.getBoolean("group")) {
values2 = REUtil.groups(childJson.getString("regex"), value);
} else {
values2 = REUtil.matchs(childJson.getString("regex"), value);
}
Log.d(TAG, "to get chaps values2 != null :" + (values2 != null));
//Log.i(TAG, "to get chaps values2 != null :" + (values2 != null));
if (values2 != null) {
Log.d(TAG, "to get chaps value in values2 :" + value);
//Log.i(TAG, "to get chaps value in values2 :" + value);
context.put(childJson.getString("name"), values2);
Log.d(TAG, "to get chaps siteJson.has(\"output\") :" + siteJson.has("output"));
//Log.i(TAG, "to get chaps siteJson.has(\"output\") :" + siteJson.has("output"));
if (childJson.has("output")) {
JSONArray outputArray = childJson.getJSONArray("output");
for (int m = 0; m < outputArray.length(); m++) {
String v = getContent(outputArray.getString(m), context);
Log.d(TAG, "to get chaps v :" + v);
//Log.i(TAG, "to get chaps v :" + v);
if (v != null) result.add(v);
}
}
@ -243,7 +243,7 @@ public class NovelParseUtil {
}
}
}
Log.d(TAG, "to get chaps <---------------------------- result size :" + result.size());
//Log.i(TAG, "to get chaps <---------------------------- result size :" + result.size());
return result.toArray(new String[0]);
}
@ -276,7 +276,7 @@ public class NovelParseUtil {
}
private static String access(String url,int maxAge,String encoding) {
private static String access(String url,int maxAge, SiteRule siteRule) {
Request.Builder builder = new Request.Builder()
// .tag(mNovel.getNovelId()) //标记 请求的tag,切换小说或离开小说界面(BookActivity) 取消未执行完毕的 此tag的所有请求
.url(url)
@ -288,17 +288,20 @@ public class NovelParseUtil {
// .header( "Upgrade-Insecure-Requests", "1")
// .header("content-type", "text/html; charset=utf-8")
;
for(int i=0;i<siteRule.getHeaders().length;i+=2){
builder.header(siteRule.getHeaders()[i],siteRule.getHeaders()[i+1]);
}
Request request =builder.build() ;
Response response = null;
try {
response = HttpMethods.getOkClient().newCall(request).execute();
//String s =response.body().string();
String s = enconding(response.body(),encoding); //new String(response.body().bytes(), encoding);
String s = enconding(response.body(),siteRule.getEncoding()); //new String(response.body().bytes(), encoding);
// response.body().close();
long st = new java.util.Date().getTime();
Log.d(TAG, "to get chaps access result:" + s );
//Log.i(TAG, "to get chaps access result:" + s );
return s;
// return enconding(s,encoding);
// return info;
@ -329,21 +332,21 @@ public static String enconding(ResponseBody body, String encode) throws Unsupp
}
return s;
/* Log.d(TAG, " encoding covert from :" +source );
/* //Log.i(TAG, " encoding covert from :" +source );
long st = new java.util.Date().getTime();
byte[] b = source.getBytes("utf-8");
// String info = new String(b, "utf-8");
String info = new String(b);
Log.d(TAG, " encoding covert to :" +info );
Log.d(TAG, "encoding covert :" + encode +", cost " +( new Date().getTime() -st));
//Log.i(TAG, " encoding covert to :" +info );
//Log.i(TAG, "encoding covert :" + encode +", cost " +( new Date().getTime() -st));
return info;*/
/* long st = new java.util.Date().getTime();
byte[] b = source.getBytes(encode);
// String info = new String(b, "utf-8");
String info = new String(b,"utf-8");
Log.d(TAG, " encoding covert to :" +info );
Log.d(TAG, "encoding covert :" + encode +", cost " +( new Date().getTime() -st));
//Log.i(TAG, " encoding covert to :" +info );
//Log.i(TAG, "encoding covert :" + encode +", cost " +( new Date().getTime() -st));
return info;*/
}

View File

@ -19,6 +19,7 @@ import android.os.Message;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
@ -203,8 +204,8 @@ public class PageFactory implements ChangeSource{
changeChapter(currentChapter);
}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(mBookPageWidget.getCurPage());
drawStatus(mBookPageWidget.getNextPage());*/
drawStatus();
*/
}
}
}
@ -228,7 +229,7 @@ public class PageFactory implements ChangeSource{
return chaptMap.get(chaptId);
}
chaptId = chaptId > 0 ? chaptId : 1;
final File file = new File(getChapterFileName(chaptId));
if (!file.exists()) { //待下载
@ -261,26 +262,26 @@ public class PageFactory implements ChangeSource{
if(fileRetryCnt.get(chaptId) > Constants.retryCnt){
mStatus = Status.FAIL;
drawStatus(mBookPageWidget.getCurPage());
drawStatus(mBookPageWidget.getNextPage());
drawStatus();
return chaptPages;
}
drawStatus(mBookPageWidget.getCurPage());
drawStatus(mBookPageWidget.getNextPage());
drawStatus();
if( !NetUtil.isNetworkConnected()){ //TODO: 500错误处理
mStatus = Status.NETWORKFAILE;
drawStatus(mBookPageWidget.getCurPage());
drawStatus(mBookPageWidget.getNextPage());
drawStatus();
return chaptPages;
}
if(getChapters().size()==0 && mBookUtil.muluRetryCount>=Constants.retryCnt) {
Log.d(TAG, String.format("prepare book download mulu 失败,重试次数: %s ,thread.name %s",mBookUtil.muluRetryCount,Thread.currentThread().getName() ) );
mBookUtil.muluRetryCount=0;
mStatus = Status.FAIL;
drawStatus(mBookPageWidget.getCurPage());
drawStatus(mBookPageWidget.getNextPage());
drawStatus();
return chaptPages;
}
// showProgressDialog();
@ -320,8 +321,8 @@ public class PageFactory implements ChangeSource{
super.run();
}}.start();
drawStatus(mBookPageWidget.getCurPage());
drawStatus(mBookPageWidget.getNextPage());
drawStatus();
return chaptPages;
}
@ -336,8 +337,8 @@ 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(mBookPageWidget.getCurPage());
drawStatus(mBookPageWidget.getNextPage());*/
/* drawStatus();
*/
return chaptPages;
}
@ -440,22 +441,30 @@ public class PageFactory implements ChangeSource{
progressDialog.dismiss();
}
}
public void changeSource(String domain,int chapId,String chapTitle) {
public void changeSource(String domainName,String domain,int chapId,String chapTitle) {
mAd.hideSystemUI();
fileRetryCnt.clear();
chaptMap.clear();
if(getSite().getDomain().equals(domain)){ //当前源
Log.d(TAG, "prepare book changing Source: same site with original " + domain);
return;
}
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="正在换源...";
if(!TextUtils.isEmpty(domainName)) {
statusChangeSource = "前往 " + domainName + " ...";
}
drawStatus();
mBookUtil.changeSource(domain, chapId, chapTitle);
}
public String getChapterName() {
/* public String getChapterName() {
return getChapters().get(currentChapter-1).getChapterName();
}
public String getSite() {
return mBookUtil.getSite();
}
public String getChapterFileName(int chapid) {
return mBookUtil.fileChapterName(chapid);
}*/
public Chapter getChapter(){
return mBookUtil.getChapter(mBookUtil.getChapterNo());
}
private static boolean isBusy =false;
@ -471,7 +480,8 @@ public static boolean busy(){
FINISH,
FAIL,
NETWORKFAILE,
SERVERERROR
SERVERERROR,
CHANGESOURCE ;
}
public static synchronized PageFactory getInstance(Context context){
@ -591,10 +601,17 @@ public static boolean busy(){
mLineCount = (int) ((mVisibleHeight - paragrapheight ) / (m_fontSize + lineSpace));// 可显示的行数
// Log.d(TAG,"line count is " + mLineCount +" paragrapheight is " +paragrapheight);
}
private void drawStatus(){
if(mBookPageWidget!=null) {
drawStatus(mBookPageWidget.getCurPage());
drawStatus(mBookPageWidget.getNextPage());
}
}
private String loadingTxt ="";
private String statusChangeSource ="正在换源...";
private void drawStatus(Bitmap bitmap){
mAd.hideSystemUI();
mAd.showRefresh(View.VISIBLE);
mAd.showRefresh(View.VISIBLE);
String status = "";
switch (mStatus){
case OPENING:
@ -615,6 +632,10 @@ public static boolean busy(){
status = "加载成功";
mAd.showRefresh(View.GONE);
break;
case CHANGESOURCE:
status = statusChangeSource;
mAd.showRefresh(View.GONE);
break;
}
Canvas c = new Canvas(bitmap);
@ -645,6 +666,7 @@ public static boolean busy(){
private long lastPageTime;
public void onDraw(Bitmap bitmap,List<String> m_lines,Boolean updateChapter) {
mAd.hideSystemUI();
// mAd.showRefresh(View.GONE);
if(m_lines.size()==0){
return;
}
@ -684,8 +706,10 @@ public static boolean busy(){
// getNovel().save();
Novel nv = LitePal.find(Novel.class,getNovel().getId());
Log.d(TAG,String.format("prepare book %s saved lastchapt %s,lastpos %s, db lastchapt %s last pos %s",
getNovel().getId(), currentChapter,currentPage.getBegin(),nv.getLastReadChapt(),nv.getLastReadPos()));
Log.d(TAG,String.format("prepare book %s ,%s isUpdated %s,saved isUpdated %s, saved lastchapt %s,lastpos %s, db lastchapt %s last pos %s",
getNovel().getId(),
getNovel().getName(),getNovel().isUpdated(),nv.isUpdated(),
currentChapter,currentPage.getBegin(),nv.getLastReadChapt(),nv.getLastReadPos()));
lastPageTime = new Date().getTime();
@ -796,13 +820,14 @@ public static boolean busy(){
if(mCurrentChapter!=null){
chapterName = mCurrentChapter.getChapterName();
}else*/
if (getChapters().size() > 0)
// if (getChapters().size() > 0)
{
String chapterName = CommonUtil.subString(getChapterName(),16);
String chapterName =CommonUtil.subString(mBookUtil.getChapter(mBookUtil.getChapterNo()).getChapterName(),16); // CommonUtil.subString(getChapterName(),16);
int nChaterWidth = (int) mBatterryPaint.measureText(chapterName) + 1;
c.drawText(chapterName, mWidth - marginWidth - nChaterWidth, statusMarginBottom + mBatterryFontSize, mBatterryPaint);
}
if(mBookPageWidget!=null)
mBookPageWidget.postInvalidate();
}
@ -839,8 +864,14 @@ public static boolean busy(){
Log.d(TAG, "prepare book prePage: to open prepage: ");
cancelPage = currentPage;
if(mBookPageWidget==null){
return;
}
onDraw(mBookPageWidget.getCurPage(),currentPage.getLines(),true);
currentPage = getPrePage();
if(mBookPageWidget==null){
return;
}
onDraw(mBookPageWidget.getNextPage(),currentPage.getLines(),true);
}
@ -860,7 +891,7 @@ public static boolean busy(){
if (currentPage.getEnd() >= mBookUtil.getBookLen()) {
Log.d(TAG,"已经是本章最后一页了");
m_islastPage =currentChapter == mBookUtil.getChapters().size();
m_islastPage =currentChapter >= mBookUtil.getChapters().size();
if ( m_islastPage){
Toast.makeText(mContext, "已经是最后一页了", Toast.LENGTH_SHORT).show();
return;
@ -870,10 +901,16 @@ public static boolean busy(){
}
// Log.d(TAG, "prepare book nextPage: to open next page: ");
cancelPage = currentPage;
if(mBookPageWidget==null){
return;
}
onDraw(mBookPageWidget.getCurPage(),currentPage.getLines(),true);
prePage = currentPage;
currentPage = getNextPage();
// currentPage = currentChaptPages.get(currentPage.getPageNo()-1);
if(mBookPageWidget==null){
return;
}
onDraw(mBookPageWidget.getNextPage(),currentPage.getLines(),true);
Log.d("nextPage","nextPagenext");
}
@ -917,7 +954,9 @@ public static boolean busy(){
* @throws IOException
*/
public void openBook(Novel book ,Context context) throws IOException {
if(book==null){
return;
}
if(book.isLocalBook() || mBookUtil==null){ //离线书籍重新初始化加载mBookUtil
mBookUtil = new BookUtil();
}
@ -937,8 +976,8 @@ public static boolean busy(){
bookName =getNovel().getName();// FileUtils.getFileName(bookPath);
// this.mCurrentChapter = chapter;
mStatus = Status.OPENING;
drawStatus(mBookPageWidget.getCurPage());
drawStatus(mBookPageWidget.getNextPage());
drawStatus();
if (bookTask != null && bookTask.getStatus() != AsyncTask.Status.FINISHED){
bookTask.cancel(true);
@ -974,8 +1013,8 @@ public static boolean busy(){
// PageFactory.mStatus = PageFactory.Status.FINISH;
}else{
PageFactory.mStatus = PageFactory.Status.FAIL;
drawStatus(mBookPageWidget.getCurPage());
drawStatus(mBookPageWidget.getNextPage());
drawStatus();
Toast.makeText(mContext,"打开书本失败!",Toast.LENGTH_SHORT).show();
}
}
@ -1293,6 +1332,9 @@ public static boolean busy(){
//绘制当前页面
public void currentPage(Boolean updateChapter){
// Log.d(TAG, "prepare book currentPage: to open current Page : ");
if(mBookPageWidget==null){
return;
}
onDraw(mBookPageWidget.getCurPage(),currentPage.getLines(),updateChapter);
onDraw(mBookPageWidget.getNextPage(),currentPage.getLines(),updateChapter);
}
@ -1478,33 +1520,7 @@ public static boolean busy(){
return mStatus;
}
public long getBookLen(){
return mBookUtil.getBookLen();
}
public TRPage getCurrentPage(){
return currentPage;
}
//获取书本的章
public List<Chapter> getChapters(){
return mBookUtil.getChapters();
}
public boolean isReadingCatalogs(){
return mBookUtil.isReadingCatalogs();
}
public String getBookPath(){
return bookPath;
}
public String getBookName(){
return getNovle().getName();
}
public Novel getNovle(){
return mBookUtil.getNovel();
}
public boolean isWorking(){
return mBookUtil !=null;
}
//是否是第一页
@ -1565,15 +1581,49 @@ public static boolean busy(){
public interface PageEvent{
void changeProgress(float progress);
}
public Novel getNovel(){
public void refreshCate(){
mBookUtil.getChapters().clear();
mBookUtil.getSiteRule();
}
public long getBookLen(){
return mBookUtil.getBookLen();
}
public TRPage getCurrentPage(){
return currentPage;
}
//获取书本的章
public List<Chapter> getChapters(){
return mBookUtil.getChapters();
}
public boolean isReadingCatalogs(){
return mBookUtil.isReadingCatalogs();
}
public String getBookPath(){
return bookPath;
}
public String getBookName(){
return getNovel().getName();
}
public Novel getNovle(){
return getNovel();
}
private Novel getNovel(){
if(mBookUtil!=null){
return mBookUtil.getNovel();
}
return new Novel();
}
public void refreshCate(){
mBookUtil.getChapters().clear();
mBookUtil.getSiteRule();
public Site getSite(){
return mBookUtil.getSite();
}
public boolean isWorking(){
return mBookUtil !=null;
}
public String getChapterFileName(int chapid) {
return mBookUtil.fileChapterName(chapid);
}
}

View File

@ -118,7 +118,7 @@ public class PageWidget extends View {
protected void onDraw(Canvas canvas) {
// canvas.drawColor(0xFFAAAAAA);
canvas.drawColor(mBgColor);
Log.e("onDraw","isNext:" + isNext + " isRuning:" + isRuning);
// //Log.e("onDraw","isNext:" + isNext + " isRuning:" + isRuning);
if (isRuning) {
mAnimationProvider.drawMove(canvas);
} else {
@ -150,7 +150,7 @@ public class PageWidget extends View {
mAnimationProvider.setStartPoint(downX,downY);
abortAnimation();
mAnimationProvider.setCancel(false);
Log.e(TAG,"ACTION_DOWN");
//Log.e(TAG,"ACTION_DOWN");
}else if (event.getAction() == MotionEvent.ACTION_MOVE){
final int slop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
@ -163,7 +163,7 @@ public class PageWidget extends View {
if (isMove){
isMove = true;
if (moveX == 0 && moveY ==0) {
Log.e(TAG,"isMove");
//Log.e(TAG,"isMove");
//判断翻得是上一页还是下一页
if (x - downX >0){
isNext = false;
@ -189,7 +189,7 @@ public class PageWidget extends View {
return true;
}
}
Log.e(TAG,"isNext:" + isNext);
//Log.e(TAG,"isNext:" + isNext);
}else{
//判断是否取消翻页
if(mTouchListener.canCancel()) {
@ -213,8 +213,8 @@ public class PageWidget extends View {
}else{
noNext=true;
}
if(cancelPage)
Log.e(TAG,"cancelPage:" + cancelPage);
// if(cancelPage)
//Log.e(TAG,"cancelPage:" + cancelPage);
}
moveX = x;
@ -223,7 +223,7 @@ public class PageWidget extends View {
this.postInvalidate();
}
}else if (event.getAction() == MotionEvent.ACTION_UP){
Log.e(TAG,"ACTION_UP");
//Log.e(TAG,"ACTION_UP");
Log.d(TAG, String.format("onTouchEvent:ACTION_UP isMove %s, isbusy %s",isMove,PageFactory.busy()));
if (!isMove || PageFactory.busy()){
cancelPage = false;
@ -232,7 +232,7 @@ public class PageWidget extends View {
if (mTouchListener != null){
mTouchListener.center();
}
Log.e(TAG,"center");
//Log.e(TAG,"center");
// mCornerX = 1; // 拖拽点对应的页脚
// mCornerY = 1;
// mTouch.x = 0.1f;
@ -266,7 +266,7 @@ public class PageWidget extends View {
mTouchListener.cancel();
}
Log.e(TAG, "isNext:" + isNext);
//Log.e(TAG, "isNext:" + isNext);
if (!noNext) {
isRuning = true;
mAnimationProvider.startAnimation(mScroller);

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.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z"/>
</vector>

View File

@ -17,7 +17,10 @@
app:tl_indicator_width="45dp"
app:tl_textSelectColor="@color/tabSelected"
app:tl_textUnselectColor="@color/grey"
app:tl_textsize="17sp"
app:tl_textBold="SELECT"
app:tl_tab_space_equal ="true"
app:tl_indicator_bounce_enable ="true"
/>
<!-- app:tl_indicator_color="@color/crimson" -->
<android.support.v4.view.ViewPager

View File

@ -28,8 +28,9 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:paddingBottom="5dp"
android:layout_gravity="center_vertical"
android:paddingBottom="15dp"
android:orientation="vertical">
<TextView
@ -44,7 +45,7 @@
<TextView
android:id="@+id/tv_goods_no"
android:id="@+id/tvAuthor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="visible"
@ -58,8 +59,8 @@
<android.support.v7.widget.CardView
android:id="@+id/cardView"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_width="80dp"
android:layout_height="150dp"
android:layout_marginEnd="14dp"
android:layout_marginRight="14dp"
android:layout_marginStart="20dp"
@ -70,7 +71,7 @@
app:cardElevation="2dp">
<ImageView
android:id="@+id/iv_goods"
android:id="@+id/imageG1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"

View File

@ -17,6 +17,16 @@
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay">
<ImageButton
android:id="@+id/btnRefresh"
android:layout_weight="0"
android:layout_gravity ="right|center_vertical"
android:layout_marginRight="10dp"
android:layout_marginLeft="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_refresh_black_24dp"
style="@style/buttonCates"/>
<ImageButton
android:id="@+id/btnSort"