新增我的足迹

书架更新检查
maxAge设置
hotKey获取
This commit is contained in:
mwang 2019-04-28 00:18:56 +08:00
parent 193fa3550b
commit 4e66fa05d9
29 changed files with 630 additions and 191 deletions

View File

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

View File

@ -3,10 +3,20 @@ package com.novelbook.android;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import com.czp.searchmlist.mSearchLayout;
import com.novelbook.android.db.Novel;
import com.novelbook.android.netsubscribe.BookSubscribe;
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.HistoryCache;
import java.util.ArrayList;
@ -16,28 +26,86 @@ import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
public class Activity_Search extends AppCompatActivity {
public class Activity_Search extends Activity_base {
private static final String TAG=Activity_Search.class.getSimpleName();
@BindView(R.id.msearchlayout)
mSearchLayout searchLayout;
// SearchLayout searchLayout;
protected void setupToolbar(){
}
@Override
public int getLayoutRes() {
return R.layout.activity_search;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
ButterKnife.bind(this);
protected void initViews() {
}
@Override
protected void setTitle() {
}
@Override
protected void initData() {
getHotkeys();
}
@Override
public void fillData() {
initialSearch();
}
void getHotkeys(){
showProgressDialog(false,"正在加载");
OnSuccessAndFaultListener successAndFaultListener = new OnSuccessAndFaultListener() {
@Override
public void onSuccess(String result) {
// mFirstPage= gson.fromJson(result, FirstPage.class);
try {
List<String> keys = GsonUtil.parserStringBlocks(result, Constants.HOT_KEYS);
Constants.HOT_KEYS_VALUE = keys.toArray(new String[0]);
for (String s:Constants.HOT_KEYS_VALUE){
Log.d(TAG, "onSuccess: keys "+s);
}
} catch (Exception e) {
e.printStackTrace();
}
handler.sendEmptyMessage(1);
}
@Override
public void onFault(String errorMsg) {
//失败
Log.d(TAG, "error on get firstpage: " + errorMsg);
handler.sendEmptyMessage(1);
}
};
BookSubscribe.getHotKeyWords( new OnSuccessAndFaultSub(successAndFaultListener,this));
}
void initialSearch() {
List<String> skills = HistoryCache.toArray(getApplicationContext());
String shareHotData ="武动乾坤,校花高手,苍穹"; //TODO get hot keys from host
List<String> skillHots = Arrays.asList(shareHotData.split(","));
// String shareHotData ="武动乾坤,校花高手,苍穹"; //TODO get hot keys from host
List<String> skillHots = Arrays.asList(Constants.HOT_KEYS_VALUE);
this.searchLayout.initData(skills, skillHots, new mSearchLayout.setSearchCallBackListener() {
public void Search(String str) {
//进行或联网搜索 str搜索关键词

View File

@ -33,6 +33,7 @@ public static String TAG ="com.novelbook.android.paihangbang";
public static String EXTR_TITLE="title";
public static String EXTR_BANGDAN ="bangdan";
public static final String EXTR_SEARCH ="search";
public static final String EXTR_HISTORY ="history" ;
private ArrayList<Fragment> mFragments;
ArrayList<View> mList;
String[] mTitle;
@ -47,9 +48,8 @@ public static String TAG ="com.novelbook.android.paihangbang";
initTabs();
}
String bangdan;
String fn;
String keyword;
String bangdan,fn,keyword,histroy;
@Override
protected void setTitle() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
@ -64,7 +64,7 @@ public static String TAG ="com.novelbook.android.paihangbang";
String title = getIntent().getStringExtra(EXTR_TITLE);
keyword = getIntent().getStringExtra(EXTR_SEARCH);
histroy= getIntent().getStringExtra(EXTR_HISTORY);
//title+="";
this.setTitle(title);
}
@ -90,7 +90,10 @@ public static String TAG ="com.novelbook.android.paihangbang";
if(!TextUtils.isEmpty(keyword)){
mFragments.add( Fragment_booklist.search(keyword)); //搜索
}else {
}else if(!TextUtils.isEmpty(histroy)){
mFragments.add(Fragment_booklist.history()); //本地历史
}else if(!TextUtils.isEmpty(fn)){
mFragments.add(Fragment_booklist.newInstance(fn, bangdan)); //首页更多
}

View File

@ -263,7 +263,7 @@ public class BookActivity extends Activity_base {
// txtDesc2.setExpanded(false);
// txtDesc2.setSuffixTrigger(false);
this.txtLatestCate.setText(mNovel.getChapterName());
tvLastUpdate.setText(CommonUtil.getDateString( mNovel.getLastUpateTime()));
tvLastUpdate.setText(CommonUtil.getDateString( mNovel.getLastUpdateTime()));
loadImageView(mNovel.getCover(),imageView);
gaosiHeadPic();
}

View File

@ -9,6 +9,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;
@ -45,7 +46,8 @@ public class CatalogFragment extends BasicFragment implements MarkActivity.Sortc
ArrayList<Integer> catalogCached = new ArrayList<>();
@BindView(R.id.lv_catalogue)
ListView lv_catalogue;
@BindView(R.id.btnRefresh)
Button btnRefresh;
/* @BindView(R.id.tvTitle)
TextView tvTitle;
@BindView(R.id.tvChapts)
@ -92,10 +94,17 @@ public class CatalogFragment extends BasicFragment implements MarkActivity.Sortc
/* tvTitle.setText(pageFactory.getBookName());
tvChapters.setText(String.format("共%s章",catalogueList.size()));*/
if(catalogueList.size() ==0) {
btnRefresh.setVisibility(View.VISIBLE);
}else btnRefresh.setVisibility(View.GONE);
}
@OnClick(R.id.btnRefresh)
void refresh(View view){
loadData() ;
}
ArrayList<Chapter> revertArray(){
ArrayList<Chapter> tmp = new ArrayList<>();
@ -126,15 +135,18 @@ public class CatalogFragment extends BasicFragment implements MarkActivity.Sortc
@Override
protected void initData() {
((MarkActivity) getActivity()).setSortcat(this);
showProgressDialog(false,"请稍等");
pageFactory = PageFactory.getInstance(activity.getApplicationContext());
loadData();
}
public void loadData(){
showProgressDialog(false,"请稍等");
Log.d(TAG, String .format("prepare book: start to open book cate of %s" , pageFactory.getNovle().getName()));
new Thread() {
new Thread() {
@Override
public void run() {
ArrayList<Chapter> list =(ArrayList<Chapter>) LitePal.where("novelId=?" ,pageFactory.getNovle().getId()+"").find(Chapter.class);
@ -152,12 +164,13 @@ public class CatalogFragment extends BasicFragment implements MarkActivity.Sortc
}
int slepttime = 0;
while (NetUtil.isNetworkConnected() &&( slepttime < 100 && ( pageFactory.isReadingCatalogs() || pageFactory.getChapters().size() == 0))) {
while (NetUtil.isNetworkConnected() &&( slepttime < 200 && ( pageFactory.isReadingCatalogs() || pageFactory.getChapters().size() == 0))) {
try {
Log.d(TAG, String .format("prepare book: to open book cate to sleep %s" , 50));
sleep(50);
slepttime++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@ -169,16 +182,12 @@ public class CatalogFragment extends BasicFragment implements MarkActivity.Sortc
handler.sendEmptyMessage(1);
}
// Toast.makeText(BookActivity.this,"已加入下载队列2",Toast.LENGTH_LONG).show();
}
}.start();
}
@Override
protected void initListener() {
lv_catalogue.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@ -209,7 +218,7 @@ public class CatalogFragment extends BasicFragment implements MarkActivity.Sortc
@Override
protected void initViews() {
lv_catalogue.setFastScrollEnabled(true);
((MarkActivity) getActivity()).setSortcat(this);
//lv_catalogue.setFastScrollStyle(R.style.FastScrollTheme); //不起作用
}

View File

@ -67,7 +67,7 @@ public class Fragment_Shelf extends BasicFragment {
List<Novel> lstUpdate = new ArrayList<Novel>();
private List<Novel> bookLists;
// private ShelfAdapter adapter;
private String noveIds ;
public Fragment_Shelf() {
// Required empty public constructor
}
@ -83,6 +83,10 @@ public class Fragment_Shelf extends BasicFragment {
private void loadNovelsOnShelf(){
bookLists = Novel.getNovelsOnShelf();
noveIds="";
for(Novel novel:bookLists){
noveIds+=novel.getNovelId()+",";
}
}
@ -92,7 +96,7 @@ public class Fragment_Shelf extends BasicFragment {
}
/**
* to get updated info from server
* to get updated info from server,TODO: put it in service ,scheduled
*/
private void getUpdatedData(){
List<Integer> novelIds;
@ -106,14 +110,11 @@ public class Fragment_Shelf extends BasicFragment {
lstUpdate = GsonUtil. parserJsonArray(result, Constants.BLOCK_TITLE_NOVELS);
if(lstUpdate.size()>0) {
for (Novel novel2 : lstUpdate) {
novel2.save();//更新本地信息
novel2.checkAndUpdateShelf();
}
loadNovelsOnShelf();
}
} catch (Exception e) {
e.printStackTrace();
}
@ -129,7 +130,10 @@ public class Fragment_Shelf extends BasicFragment {
}
};
// BookSubscribe.getCateNovelList(cate, pageNo, tab1Pos+1, tab3Pos+1, new OnSuccessAndFaultSub(successAndFaultListener, getActivity()));
if(!TextUtils.isEmpty(noveIds)){
BookSubscribe.getNovelsByIds(noveIds , new OnSuccessAndFaultSub(successAndFaultListener, getActivity()));
}
}
@ -144,10 +148,10 @@ public class Fragment_Shelf extends BasicFragment {
getUpdatedData();
flag = new boolean[bookLists.size()];
if(bookLists.size()>0) { //TODO: to remove
/* if(bookLists.size()>0) { //TODO: to remove
bookLists.get(0).setUpdated(true);
// bookLists.get(bookLists.size()-1).setUpdated(true);
}
}*/
mAdapter = new BookListAdapter(activity,bookLists,R.layout.recycle_list_item,new OnItemClickListener()
{
@ -175,6 +179,8 @@ public class Fragment_Shelf extends BasicFragment {
});
mAdapter.setNorecord(R.string.noRecordInshelf);
((Main2Activity) activity).setShelfFragment(this);
}
@Override
@ -193,15 +199,8 @@ public class Fragment_Shelf extends BasicFragment {
@Override
protected void fillData() {
if(bookLists.size()==0){
// return;
}
mAdapter.setData(bookLists);
// mAdapter.notifyDataSetChanged();
}
public void initReceyleView() {

View File

@ -32,6 +32,7 @@ import com.novelbook.android.utils.OnItemClickListener;
import com.novelbook.android.adapter.BookListAdapter;
import org.json.JSONObject;
import org.litepal.LitePal;
import java.nio.file.Path;
import java.util.ArrayList;
@ -48,16 +49,15 @@ public class Fragment_booklist extends BasicFragment {
private static final String EXTR_SEARCH ="search";
private static final String EXTR_FN ="fn" ;
private static final String EXTR_BANGDAN ="bangdan" ;
private static final String EXTR_HISTORY ="history" ;
private BookListAdapter mAdapter;
// private BookListAdapter mAdapter;
private List<Novel> mData;;
private List<Novel> mMoreData;
private String cate;
private int progress;
private String keyWord;
private String fn;
private String bangdan;
private String keyWord ,fn,bangdan,history;
private int listItem =R.layout.recycle_list_item_horizon;
//private int pageNo=1;
private int totalCount;
// private int pageCount;
@ -99,7 +99,14 @@ public class Fragment_booklist extends BasicFragment {
fragment.setArguments(args);
return fragment;
}
public static Fragment_booklist history() {
Fragment_booklist fragment = new Fragment_booklist();
Bundle args = new Bundle();
args.putString(EXTR_HISTORY,EXTR_HISTORY);
fragment.setArguments(args);
return fragment;
}
protected void processArguments(){
if (getArguments() != null) {
Bundle bundle = getArguments() ;
@ -112,7 +119,10 @@ public class Fragment_booklist extends BasicFragment {
cate = bundle.getString(EXTR_CATE);
progress = bundle.getInt(EXTR_PROGRESS);
keyWord =bundle.getString(EXTR_SEARCH);
history =bundle.getString(EXTR_HISTORY);
if(!TextUtils.isEmpty(history)){
listItem = listItem =R.layout.recycle_list_item_history;
}
}
}
@ -159,7 +169,7 @@ public class Fragment_booklist extends BasicFragment {
} else {
mData = new ArrayList<Novel>();
mAdapter = new BookListAdapter(activity, mData, R.layout.recycle_list_item_horizon, new OnItemClickListener() {
mAdapter = new BookListAdapter(activity, mData, listItem, new OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
@ -261,6 +271,10 @@ public class Fragment_booklist extends BasicFragment {
}else if(!TextUtils.isEmpty(keyWord)){ //搜索
// showProgressDialog(true, "正在加载搜索");
BookSubscribe.getSearchNovelList( keyWord,pageNo, Constants.SEX, new OnSuccessAndFaultSub(successAndFaultListener, getActivity()));
}else if(!TextUtils.isEmpty(history)){
loadHistory();
}else{
handler.sendEmptyMessage(1);
}
@ -320,11 +334,31 @@ public class Fragment_booklist extends BasicFragment {
});
}
void loadHistory(){
new Thread() {
@Override
public void run() {
super.run();
mMoreData = Novel.getNovelsHistory();
pageCount=1;
handler.sendEmptyMessage(1);
}
}.start();
}
boolean isFirstLoad =true;
@Override
public void onResume(){
super.onResume();
pageNo=1;
if(!TextUtils.isEmpty(history)){
if(isFirstLoad) {
isFirstLoad=false;
}else{
initData();
}
}
}
}

View File

@ -26,6 +26,7 @@ import android.widget.Toast;
import com.novelbook.android.Fragments.BasicFragment;
import com.novelbook.android.Fragments.Fragment_Shelf;
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.OnSuccessAndFaultListener;
@ -170,6 +171,13 @@ public class Main2Activity extends Activity_base
startActivity(intent);
}
if(menuItemId==R.id.menuHistory){
Intent intent = new Intent(Main2Activity.this,Activity_paihangbang.class);
intent.putExtra(Activity_paihangbang.EXTR_HISTORY,"yes");
intent.putExtra(Activity_paihangbang.EXTR_TITLE,"我曾经看过的书");
startActivity(intent);
}
return true;
}
});
@ -256,7 +264,10 @@ public class Main2Activity extends Activity_base
if (id == R.id.nav_camera) {
// Handle the camera action
} else if (id == R.id.nav_gallery) {
Intent intent = new Intent(Main2Activity.this,Activity_paihangbang.class);
intent.putExtra(Activity_paihangbang.EXTR_HISTORY,"yes");
intent.putExtra(Activity_paihangbang.EXTR_TITLE,"我曾经看过的书");
startActivity(intent);
} else if (id == R.id.nav_slideshow) {
} else if (id == R.id.nav_manage) {
@ -341,6 +352,7 @@ private int bottomSelectedIndex;
// menu.findItem(R.id.menuFenlei).setVisible(false);
menu.findItem(R.id.menuMore).setVisible(false);
menu.findItem(R.id.menuSearch).setVisible(false);
menu.findItem(R.id.menuHistory).setVisible(false);
}else {
// menu.findItem(R.id.menuFenlei).setVisible(false);
menu.findItem(R.id.menuMore).setVisible(true);

View File

@ -24,6 +24,7 @@ import android.view.View;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
@ -66,6 +67,8 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
private final static String EXTRA_CHAPTER = "chapter";
private final static int MESSAGE_CHANGEPROGRESS = 1;
@BindView(R.id.btnRefresh)
Button btnRefresh;
@BindView(R.id.bookpage)
PageWidget bookpage;
// @BindView(R.id.btn_return)
@ -748,7 +751,7 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
| View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
| View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
// | View.SYSTEM_UI_FLAG_IMMERSIVE
);
@ -757,6 +760,11 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
pageFactory.setBusy(false);
}
@Override
public void showRefresh(int visible) {
btnRefresh.setVisibility(visible);
}
private void showSystemUI() {
getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
@ -837,7 +845,7 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
@OnClick({R.id.tv_progress, R.id.rl_progress, R.id.tv_pre, R.id.sb_progress, R.id.tv_next, R.id.tv_directory,
R.id.tv_dayornight,R.id.tv_pagemode, R.id.tv_setting, R.id.bookpop_bottom, /*R.id.rl_bottom,*/R.id.tv_stop_read
,R.id.llTopAd})
,R.id.llTopAd,R.id.btnRefresh})
public void onClick(View view) {
// if( pageFactory.isReady())
switch (view.getId()) {
@ -890,13 +898,10 @@ public class ReadActivity extends Activity_base implements SpeechSynthesizerLis
Toast.makeText(this,"ad is clicked ",Toast.LENGTH_LONG).show();
Log.d(TAG,"Ad is clicked");
// showProgressDialog();// sleep 结束后才显示dismiss 不工作
/* try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
// dismissProgressDialog();
break;
case R.id.btnRefresh:
pageFactory.retryChapt(pageFactory.getCurrentChapter());
btnRefresh.setVisibility(View.GONE);
break;
}
// hideSystemUI();

View File

@ -16,6 +16,7 @@ import com.novelbook.android.R;
import com.novelbook.android.db.Novel;
import com.novelbook.android.netutils.NetUtil;
import com.novelbook.android.utils.CommonUtil;
import com.novelbook.android.utils.ImageUtil;
import com.novelbook.android.utils.MyImageLoader;
import com.novelbook.android.utils.OnItemClickListener;
@ -25,6 +26,7 @@ import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import okhttp3.internal.Util;
public class BookListAdapter extends RecyclerView.Adapter< RecyclerView.ViewHolder> {
private final int EMPTY_VIEW = 1;
@ -199,6 +201,12 @@ public class BookListAdapter extends RecyclerView.Adapter< RecyclerView.ViewHol
if (holder.tvAuthor != null) holder.tvAuthor.setText(mDatas.get(position).getAuthor());
if (holder.tvCate != null) holder.tvCate.setText(mDatas.get(position).getNovelType());
if (holder.tvDesc != null) holder.tvDesc.setText(mDatas.get(position).getDesc());
if (holder.tvLastRead != null) holder.tvLastRead.setText(CommonUtil.getDateString( mDatas.get(position).getLastVisit() ));
if (holder.tvProgress != null) holder.tvProgress.setText( String.format("上次看到第 %s 章,共%s章",mDatas.get(position).getLastReadChapt(),mDatas.get(position).getChaptCnt()) );
if (holder.tvReadtime != null) holder.tvReadtime.setText( "总计阅读了 "+CommonUtil.getTimeCnt4Read( mDatas.get(position).getReadtime() ,true) );
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);

View File

@ -33,8 +33,18 @@ public class MyViewHolder extends RecyclerView.ViewHolder {
TextView tvDesc;
@Nullable
@BindView(R.id.tvCateNums)
TextView tvNum;
@Nullable
@BindView(R.id.tvProgress)
TextView tvProgress;
@Nullable
@BindView(R.id.tvReadtime)
TextView tvReadtime;
@Nullable
@BindView(R.id.tvLastRead)
TextView tvLastRead;
public MyViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);

View File

@ -9,6 +9,8 @@ import org.litepal.crud.LitePalSupport;
import org.w3c.dom.Text;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
@ -36,6 +38,35 @@ public class Novel extends LitePalSupport implements Serializable{
private boolean isFinished; //是否完本
private boolean isUpdated;
private boolean isTop;//置顶
private long readtime; //阅读时间
private int chaptCnt; //总章数
private long lastVisit;//最近浏览,如何设置默认时间
public int getChaptCnt() {
return chaptCnt;
}
public void setChaptCnt(int chaptCnt) {
this.chaptCnt = chaptCnt;
}
public long getReadtime() {
return readtime;
}
public void setReadtime(long readtime) {
this.readtime = readtime;
}
public long getLastVisit() {
return lastVisit;
}
public void setLastVisit(long lastVisit) {
this.lastVisit = lastVisit;
}
public boolean isTop() {
return isTop;
@ -204,11 +235,11 @@ public class Novel extends LitePalSupport implements Serializable{
}
public long getLastUpateTime() {
public long getLastUpdateTime() {
return lastUpdateTime;
}
public void setLastUpateTime(long lastUpateTime) {
public void setLastUpdateTime(long lastUpateTime) {
this.lastUpdateTime = lastUpateTime;
}
@ -250,7 +281,39 @@ public class Novel extends LitePalSupport implements Serializable{
}
public static List<Novel> getNovelsHistory(){
return LitePal.where("lastVisit>0").order("lastVisit desc").limit(50).find(Novel.class);
}
/**
* 有没有新的更新
* @return
*/
/* public boolean isUpdated(){
return lastUpdateTime2 >0 && lastUpdateTime > lastUpdateTime2;
}
*/
private void setValues(){
lastVisit = new Date().getTime();
}
@Override
public boolean save(){
setValues();
return super.save();
}
@Override
public int update(long id){
setValues();
return super.update(id);
}
public int checkAndUpdateShelf(){
Novel nv = getNovelBySvrId(novelId);
if(lastUpdateTime > nv.lastVisit){
isUpdated =true;
}
return super.update(nv.id);
}
}

View File

@ -84,5 +84,14 @@ public interface HttpApi {
// 搜索分类 http://xiaoshuofenxiang.com/api/page/topdata
@GET("page/topdata")
Observable<ResponseBody> getSearchTitles();
//返回指定id列表的小说列表api/novels/1,2
@GET("novels/{nvs}")
Observable<ResponseBody> getNovelsByIds(@Path("nvs")String nvs );
//返回指定id列表的小说列表
@GET("page/hot-keywords")
Observable<ResponseBody> getSearchHotKeys();
}

View File

@ -79,5 +79,14 @@ public class BookSubscribe {
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getSearchTitles();
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getHotKeyWords(DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getSearchHotKeys();
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getNovelsByIds(String ids,DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getNovelsByIds(ids);
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
}

View File

@ -79,6 +79,10 @@ public class HttpMethods {
public static OkHttpClient getOkClient() {
return SingletonHolder.INSTANCE.okHttpClient;
}
public static OkHttpClient getOkClient(int maxAge) {
maxAgeForce =maxAge;
return SingletonHolder.INSTANCE.okHttpClient;
}
/**
* 获取retrofit
@ -109,7 +113,13 @@ public class HttpMethods {
public HttpApi getHttpApi() {
return httpApi;
}
public HttpApi getHttpApi(int maxAge) {
maxAgeForce =maxAge;
return httpApi;
}
private static final int maxAge = 60*60; //一小时;
private static int maxAgeForce =0; //默认没有强制;
private OkHttpClient getClient(){
//手动创建一个OkHttpClient并设置超时时间
@ -119,37 +129,7 @@ public class HttpMethods {
*/
File cacheFile = new File(FileUtils.getDiskCacheDir(MyApp.applicationContext), CACHE_NAME);
Cache cache = new Cache(cacheFile, 1024 * 1024 * 50);
Interceptor cacheInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!NetUtil.isNetworkConnected()) {
request = request.newBuilder()
.removeHeader("Pragma")
.cacheControl(CacheControl.FORCE_CACHE)
.build();
}
Response response = chain.proceed(request);
if (NetUtil.isNetworkConnected()) {
int maxAge = 60*60;
// 有网络时 设置缓存超时时间0个小时
response.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, max-age=" + maxAge)
.removeHeader(CACHE_NAME)// 清除头信息因为服务器如果不支持会返回一些干扰信息不清除下面无法生效
.build();
} else {
// 无网络时设置超时为4周
int maxStale = 60 * 60 * 24 * 28;
response.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.removeHeader(CACHE_NAME)
.build();
}
return response;
}
};
// okHttpBuilder.cache(cache).addInterceptor(cacheInterceptor);
okHttpBuilder.cache(cache) .addNetworkInterceptor(REWRITE_RESPONSE_INTERCEPTOR)
.addInterceptor(REWRITE_RESPONSE_INTERCEPTOR_OFFLINE);
@ -173,7 +153,7 @@ public class HttpMethods {
.addHeader("Accept-Encoding", Locale.getDefault().toString() )
// .addHeader("Accept", "application/json")
// .addHeader("Content-Type", "application/json; charset=utf-8")
.addHeader("Device", "Android")
// .addHeader("Device", "Android")
.removeHeader("User-Agent").addHeader("User-Agent",NetUtil.getUserAgent()) // 随机agent
.tag(NetUtil.currentRequestTag)
.method(originalRequest.method(), originalRequest.body());
@ -212,20 +192,6 @@ public class HttpMethods {
}
/**
* 设置订阅 所在的线程环境
*/
@ -245,20 +211,24 @@ public class HttpMethods {
@Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
String cacheControl = originalResponse.header("Cache-Control");
int maxAge = 60*60; //一小时
if (cacheControl == null || cacheControl.contains("no-store") || cacheControl.contains("no-cache") ||
//int maxAge = 60*60; //一小时
if (maxAgeForce >0 ||cacheControl == null || cacheControl.contains("no-store") || cacheControl.contains("no-cache") ||
cacheControl.contains("must-revalidate") || cacheControl.contains("max-age=0")) { //目标网站禁用cache则设置为1小时
int age = maxAgeForce >0? maxAgeForce :maxAge;
Log.d(TAG, "intercept: add maxAge: "+ age);
return originalResponse.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, max-age=" + age)
.build();
} else {
return originalResponse.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, max-age=" + maxAge)
.build();
} else {
/* return originalResponse.newBuilder()
.removeHeader("Pragma")
.header("Cache-Control", "public, max-age=" + maxAge)
.build();*/
return originalResponse;
// return originalResponse;
}
}
};

View File

@ -8,4 +8,5 @@ public interface AdInterface {
*/
public void showAd(boolean showAd,int height,int adY);
public void hideSystemUI();
public void showRefresh(int visible);
}

View File

@ -559,7 +559,15 @@ public class BookUtil {
}
}
private int getMaxAge(){
int maxAge = Constants.MAXAGE_MULU;
if(mNovel.isFinished()){
maxAge =Constants.MAXAGE_MAX;
}else if(mNovel.isUpdated()){
maxAge = 0;
}
return maxAge;
}
int muluRetryCount =0;
@ -572,7 +580,7 @@ int muluRetryCount =0;
Request request = getTagRequest(url);
mMuluStatus = MuluStatus.isDownloading;
long startTime= new Date().getTime();
Log.d(TAG,String.format("prepare book loadChapts----start download %s 目录 from %s", mNovel.getName() ,url ));
Log.d(TAG,String.format("prepare book loadChapts----start download %s,maxAge %s, 目录 from %s", mNovel.getName() ,getMaxAge() ,url ));
/* if(muluRetryCount<3){
muluRetryCount++;
@ -583,7 +591,7 @@ int muluRetryCount =0;
return;
}*/
HttpMethods.getOkClient().newCall(request).enqueue(new Callback() {
HttpMethods.getOkClient(getMaxAge()).newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// Log.d(TAG, "onFailure: " + e.getMessage());
@ -695,15 +703,11 @@ int muluRetryCount =0;
mChapters = NovelParseUtil.getChapters(mSite.getDomain(),url, content, siteJson);
Log.d(TAG,String.format("mulu on Site %s download status %s",mSite.getDomain(),mMuluStatus));
/* if (mChapters != null) {
int lastReadChapt = mNovel.getLastReadChapt();
// int index =lastReadChapt*2-2;
if( mChapters.size()> mNovel.getChaptCnt()){
mNovel.setChaptCnt(mChapters.size());
mNovel.update(mNovel.getId());
}
lastReadChapt = lastReadChapt >=mChapters.size() ? mChapters.size() -1:lastReadChapt;
lastReadChapt = lastReadChapt <=0 ? 1:lastReadChapt;
mCurrentChapter =mChapters.get(lastReadChapt-1);
}*/
} catch (JSONException e) {
// } catch (JSONException | IOException e) {
Log.d(TAG,String.format("prepare book, mulu on Site %s download status %s",mSite.getDomain(),mMuluStatus));
@ -1457,7 +1461,10 @@ private void loadChaptContent(final int chapterIndex) throws JSONException, Inte
setDownloadFlag(true);
} catch (IOException | JSONException e) {
e.printStackTrace();
throw new RuntimeException("Error during writing " + fileChapterName( index));
Log.e(TAG, "onResponse: prepare book error ",e );
chaptDownStatus.put(index,DownloadStatus.failure);
return;
// throw new RuntimeException("Error during writing " + fileChapterName( index));
}
finally {
body.close();
@ -1467,7 +1474,11 @@ private void loadChaptContent(final int chapterIndex) throws JSONException, Inte
}
chapter.setNovelId(mNovel.getId());
chapter.setChapterPath(fileChapterName(index));
chapter.save();
if(chapter.getId()>0) {
chapter.update(chapter.getId());
}else{
chapter.save();
}
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() ));

View File

@ -399,12 +399,12 @@ public class CommonUtil {
Date dt = new Date(time);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String rt =sdf.format(dt);
Log.d(TAG, String.format("getDateString:timestamp %s, formated time %s",time,rt));
long time2 =System.currentTimeMillis();
String rt =sdf.format(dt);
Log.d(TAG, String.format("getDateString:timestamp %s, formated time %s",time,rt));
/* long time2 =System.currentTimeMillis();
dt = new Date(time2);
rt =sdf.format(dt);
Log.d(TAG, String.format("getDateString:timestamp %s, formated time %s",time2,rt));
Log.d(TAG, String.format("getDateString:timestamp %s, formated time %s",time2,rt));*/
return sdf.format(dt);
/* Timestamp ts = new Timestamp(time);
@ -426,6 +426,39 @@ public class CommonUtil {
return getDateString(time,"");
}
public static String getTimeCnt4Read(Long time,boolean isIncludeSec)
{
int ish = (int) (time/1000/60/60);
int ism = (int) ((time - ish*3600*1000)/1000/60);
int iss = (int) ((time -ish*3600*1000 - ism*60*1000)/1000);
// int ish =Integer.valueOf(String.valueOf(hour));
// int ism = Integer.valueOf(String.valueOf(minute));
// int iss = Integer.valueOf(String.valueOf(second));
String sh = String.valueOf( ish>0 ?ish+"小时" :"") ;
String sm = String.valueOf(ism>0 ? ism +"" :"") ;
String ss = String.valueOf(iss>=0 ?iss +"":"" ) ;
// if (10>ish && ish>0)sh ="0"+sh;
if (ish>0&& 10>ism && ism>0)sm ="0"+sm;
if (ism>0 && 10>iss && iss>0)ss ="0"+ss;
if(!isIncludeSec)
return sh + sm +(ish==0?(ism>0 ? "" :""):"");
return sh + sm +ss;
}
public static int getDayscnt(Long time )
{
int days =(int) (time/1000/60/60/24);
if(days>0){
days++;
}
return days;
}
/* public static boolean isNavigationBarShow(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
Display display = getActivity().getWindowManager().getDefaultDisplay();

View File

@ -6,8 +6,12 @@ import java.util.List;
public class Constants {
public static final String BLOCK_TITLE_NOVELS = "ns";
public static final String HOT_KEYS = "keywords";
public static final int NOVEL_SPAN_CNT =3 ; //grid columns
public static final boolean SHOWAD =false ;
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 String[] HOT_KEYS_VALUE = {};
public static int SEX=1; //1 2女
public static String A_Regex = "<a[^>]+href[\\s]*=[\\s]*['\"]?([^'\"]+)['\"\\s]?[^>]*>([^<]+)<"; //TODO: 从服务器更新
public static List<String> lstProperties =null;

View File

@ -25,7 +25,7 @@ public class GsonUtil {
try {
JSONObject jsonObject = new JSONObject(json);
nv.setNovelId(jsonObject.getInt("novelId"));
nv.setLastUpateTime(jsonObject.getLong("lastUpateTime"));
nv.setLastUpdateTime(jsonObject.getLong("lastUpateTime"));
nv.setAuthor(jsonObject.getString("author"));
nv.setName(jsonObject.getString("name"));
nv.setCover(jsonObject.getString("cover"));

View File

@ -16,8 +16,12 @@ import android.graphics.Typeface;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;
@ -148,7 +152,7 @@ public class PageFactory implements ChangeSource{
private String bookPath = "";
//书本名字
private String bookName = "";
private Novel mBook;
// private Novel mBook;
//书的目录列表
private List<Chapter> mChapters;
//当前章节
@ -194,13 +198,13 @@ 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 , mBook is null? %s",currentChapter, mBook==null ) );
if (mBook != 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{
mStatus = Status.FAIL;
/* 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(mBookPageWidget.getNextPage());*/
}
}
}
@ -234,7 +238,7 @@ public class PageFactory implements ChangeSource{
}
if(!mBook.isLocalBook()) {
if(!getNovel().isLocalBook()) {
mStatus = Status.OPENING;
@ -246,9 +250,11 @@ public class PageFactory implements ChangeSource{
if (fileRetryCnt.containsKey(chaptId)) {
fileRetryCnt.put(chaptId, fileRetryCnt.get(chaptId) + 1);
loadingTxt+=".";
} else {
fileRetryCnt.clear();//只保留一个章节数据
fileRetryCnt.put(chaptId, 1);
loadingTxt="";
}
Log.d(TAG, String.format("prepare book loadCurrentChapt %s, rertying count %s ",chaptId, fileRetryCnt.get(chaptId)));
@ -584,15 +590,19 @@ public static boolean busy(){
mLineCount = (int) ((mVisibleHeight - paragrapheight ) / (m_fontSize + lineSpace));// 可显示的行数
// Log.d(TAG,"line count is " + mLineCount +" paragrapheight is " +paragrapheight);
}
private String loadingTxt ="";
private void drawStatus(Bitmap bitmap){
mAd.hideSystemUI();
mAd.showRefresh(View.VISIBLE);
String status = "";
switch (mStatus){
case OPENING:
status = "正在拼命加载...";
status = "正在拼命加载"+loadingTxt;
mAd.showRefresh(View.GONE);
break;
case FAIL:
status = "读取错误,请稍后重试";
break;
case NETWORKFAILE:
status = "请开启网络";
@ -600,9 +610,10 @@ public static boolean busy(){
case SERVERERROR:
status = "服务器故障";
break;
/* case FINISH:
case FINISH:
status = "加载成功";
break;*/
mAd.showRefresh(View.GONE);
break;
}
Canvas c = new Canvas(bitmap);
@ -619,10 +630,18 @@ public static boolean busy(){
waitPaint.setTextAlign(Paint.Align.CENTER);
c.drawText(status, targetRect.centerX(), baseline, waitPaint);
// c.drawText("正在打开书本...", mHeight / 2, 0, waitPaint);
/* TextPaint tp = new TextPaint();
tp.setColor(getTextColor());
tp.setStyle(Paint.Style.FILL);
tp.setTextSize(50);
StaticLayout myStaticLayout = new StaticLayout(status, tp, c.getWidth(), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
myStaticLayout.draw(c);*/
mBookPageWidget.postInvalidate();
mAd.hideSystemUI();
}
//上次翻书时间
private long lastPageTime;
public void onDraw(Bitmap bitmap,List<String> m_lines,Boolean updateChapter) {
mAd.hideSystemUI();
if(m_lines.size()==0){
@ -636,40 +655,49 @@ public static boolean busy(){
}
// Log.d(TAG, String.format(" prepare book onDraw chapter _____________ %s ",currentChapter ) );
//更新数据库进度
if ( mStatus ==Status.FINISH && currentPage != null && mBook != null){
if ( mStatus ==Status.FINISH && currentPage != null && getNovel() != null) {
new Thread() {
@Override
public void run() {
super.run();
if(mBook.getLastReadChapt() !=currentChapter || mBook.getLastReadPos()!=currentPage.getBegin()) {
if(currentChapter >1) {
if (getNovel().getLastReadChapt() != currentChapter || getNovel().getLastReadPos() != currentPage.getBegin()) {
if (currentChapter > 1) {
mBook.setLastReadChapt(currentChapter);
getNovel().setLastReadChapt(currentChapter);
}else{
mBook.setToDefault("lastReadChapt");
} else {
getNovel().setToDefault("lastReadChapt");
}
mBook.setLastReadPos(currentPage.getBegin());
mBook.update(mBook.getId()); //If you set a default value to a field, the corresponding
if(lastPageTime>0) {
long time = new Date().getTime() - lastPageTime;
Log.d(TAG, String.format("prepare book read time last %s,current %s,spent %s",lastPageTime,new Date().getTime(), time));
if (time > 1000) {
getNovel().setReadtime(getNovel().getReadtime() + time);
}
}
getNovel().setToDefault("isUpdated"); //去除更新标志
getNovel().setLastReadPos(currentPage.getBegin());
getNovel().update(getNovel().getId()); //If you set a default value to a field, the corresponding
// * column won't be updated.
// mBook.save();
// getNovel().save();
/*Novel nv = LitePal.find(Novel.class,mBook.getId());
Log.d(TAG,String.format("prepare book saved lastchapt %s,lastpos %s, db lastchapt %s last pos %s",
currentChapter,currentPage.getBegin(),nv.getLastReadChapt(),nv.getLastReadPos()));
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()));
*/
lastPageTime = new Date().getTime();
}
/*
values.put("lastReadPos",currentPage.getBegin());
values.put("lastReadChapt",currentChapter);
Log.d(TAG,String.format("begin to update book %s chapter%s bigin %s ",mBook.getName(),currentChapter, currentPage.getBegin() ) );
int rows = LitePal.update(Novel.class,values,mBook.getId());
Log.d(TAG,String.format("update book %s chapter%s bigin %s, result %s",mBook.getName(),currentChapter, currentPage.getBegin(),rows) );
Log.d(TAG,String.format("begin to update book %s chapter%s bigin %s ",getNovel().getName(),currentChapter, currentPage.getBegin() ) );
int rows = LitePal.update(Novel.class,values,getNovel().getId());
Log.d(TAG,String.format("update book %s chapter%s bigin %s, result %s",getNovel().getName(),currentChapter, currentPage.getBegin(),rows) );
*/
}
}.start();
}
}.start();
}
Canvas c = new Canvas(bitmap);
@ -867,9 +895,9 @@ public static boolean busy(){
Log.d(TAG, "prepare book: start prepare book " + book.getName());
if(mBook!=null &&mBook.getNovelId() !=book.getNovelId()){ //取消未上本书完成的web请求待验证效果
if(getNovel()!=null &&getNovel().getNovelId() !=book.getNovelId()){ //取消未上本书完成的web请求待验证效果
try {
NetUtil.cancelRequest(mBook.getNovelId() );
NetUtil.cancelRequest(getNovel().getNovelId() );
}catch (Exception e)
{
Log.e(TAG, "prepare book: error on canceling request "+e.getMessage());
@ -877,8 +905,6 @@ public static boolean busy(){
}
}
this.mBook = book ;
mBookUtil = new BookUtil();
//this.mBookUtil.setContext(context);
this.mBookUtil.setNovel(book);
@ -902,13 +928,12 @@ public static boolean busy(){
// m_mbBufLen = 0;
initBg(config.getDayOrNight());
if(mBook!=null &&mBook.getNovelId() !=book.getNovelId()){ //取消未上本书完成的web请求
NetUtil.cancelRequest(mBook.getNovelId() );
if(getNovel()!=null &&getNovel().getNovelId() !=book.getNovelId()){ //取消未上本书完成的web请求
NetUtil.cancelRequest(getNovel().getNovelId() );
}
this.mBook = book ;
bookPath = mBook.getNovelPath();
bookName =mBook.getName();// FileUtils.getFileName(bookPath);
bookPath = getNovel().getNovelPath();
bookName =getNovel().getName();// FileUtils.getFileName(bookPath);
// this.mCurrentChapter = chapter;
mStatus = Status.OPENING;
drawStatus(mBookPageWidget.getCurPage());
@ -971,7 +996,7 @@ public static boolean busy(){
begin = params[1];
currentChapter = (int) chapter;
try {
mBookUtil.openBook(mBook,chapter);
mBookUtil.openBook(getNovel(),chapter);
} catch (Exception e) {
e.printStackTrace();
return false;
@ -1302,7 +1327,7 @@ public static boolean busy(){
//改变章节
public void changeChapter(int chapNum){
if (mBook == null) {
if (getNovel() == null) {
return;
}
preChaptPages =currentChaptPages;
@ -1313,7 +1338,11 @@ public static boolean busy(){
currentPage(true);
}
public void retryChapt(int chapNum){
fileRetryCnt.clear();
mBookUtil.fileRetryCnt.clear();
changeChapter(chapNum);
}
public void openBookmark(int chapNum,long position){
//preChaptPages =currentChaptPages;
@ -1426,12 +1455,13 @@ public static boolean busy(){
public void clear(){
Log.d(TAG, String .format("prepare Book: clearing book info %s" , getNovle().getName()));
fileRetryCnt.clear();
lastPageTime=0;
chaptMap.clear();
//mBookUtil=null;
currentChapter = 0;
bookPath = "";
bookName = "";
mBook = null;
//getNovel() = null;
mBookPageWidget = null;
mPageEvent = null;
cancelPage = null;
@ -1534,5 +1564,11 @@ public static boolean busy(){
public interface PageEvent{
void changeProgress(float progress);
}
public Novel getNovel(){
if(mBookUtil!=null){
return mBookUtil.getNovel();
}
return new Novel();
}
}

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="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.28,2.54 0.72,-1.21 -3.5,-2.08L13.5,8L12,8z"/>
</vector>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
@ -36,4 +36,15 @@
android:layout_height="match_parent"
android:divider="@color/list_item_divider"
android:dividerHeight="1dp" />
</LinearLayout>
<Button
android:id="@+id/btnRefresh"
android:layout_width="100dp"
android:layout_height="wrap_content"
style="@style/buttonRound"
android:layout_gravity="center"
android:text="@string/refresh"
android:visibility="gone"
/>
</FrameLayout>

View File

@ -13,7 +13,11 @@
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/id_recyclerview"
android:layout_width="match_parent"
@ -25,7 +29,7 @@
android:paddingBottom="40dp"
/>
</android.support.v4.widget.SwipeRefreshLayout>
<LinearLayout
android:id="@+id/llShelfBottom"
android:layout_width="match_parent"

View File

@ -0,0 +1,119 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="0dp"
android:layout_weight="1"
android:background="@drawable/item_selector"
android:clickable="true"
android:gravity="center"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/imageView"
style="@style/NovelImage.horizon"
android:src="@drawable/googleg_standard_color_18" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="top"
android:orientation="vertical"
>
<TextView
android:id="@+id/title"
style="@style/TextViewNovelTitle.horizon"
android:text="ddd " />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="0dp"
android:orientation="horizontal">
<TextView
android:id="@+id/category"
style="@style/TextViewNovelType"
android:text=" " />
<TextView
android:id="@+id/tvNovelStatus"
style="@style/TextViewNovelType.Status"
android:layout_marginLeft="10dp"
android:text=" "
/>
<TextView
android:id="@+id/author"
style="@style/TextViewNovelAuthor"
android:text=" " />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="0dp"
android:layout_marginTop="2dp"
android:orientation="horizontal">
<TextView
android:id="@+id/tvLastRead"
style="@style/TextViewNovelType"
android:layout_marginStart="10dp"
android:text=" "
android:textColor="@color/common_google_signin_btn_text_light" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="0dp"
android:layout_marginTop="4dp"
android:orientation="horizontal">
<TextView
android:id="@+id/tvProgress"
style="@style/TextViewNovelType"
android:text=" "
android:textColor="@color/common_google_signin_btn_text_light" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="0dp"
android:layout_marginTop="2dp"
android:orientation="horizontal">
<TextView
android:id="@+id/tvReadtime"
style="@style/TextViewNovelType"
android:layout_marginLeft="10dp"
android:text=" "
android:textColor="@color/common_google_signin_btn_text_light" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout style="@style/llGraySplit.2dp.gray" />
</LinearLayout>

View File

@ -7,8 +7,8 @@
android:background="#000000"
android:orientation="vertical">
<!--android:clipToPadding="false"
android:fitsSystemWindows="true"
<!--
android:clipToPadding="false" android:fitsSystemWindows="true"
-->
<FrameLayout
android:layout_width="match_parent"
@ -43,7 +43,16 @@
android:layout_height="match_parent"
/>
<Button
android:id="@+id/btnRefresh"
android:layout_width="100dp"
android:layout_height="wrap_content"
style="@style/buttonRound"
android:layout_gravity="center"
android:layout_marginTop="80dp"
android:text="@string/refresh"
android:visibility="gone"
/>
<LinearLayout
android:id="@+id/llTopAd"
android:layout_width="match_parent"

View File

@ -6,6 +6,13 @@
android:orderInCategory="100"
android:showAsAction="never"
android:title="@string/action_history"/>-->
<item
android:id="@+id/menuHistory"
android:orderInCategory="100"
android:title=""
android:icon="@drawable/ic_history_black_24dp"
app:showAsAction="ifRoom" />
<item
android:id="@+id/menuSearch"
android:orderInCategory="100"
@ -14,6 +21,8 @@
app:showAsAction="ifRoom" />
<item
android:id="@+id/menuMore"

View File

@ -190,6 +190,7 @@
<string name="cached">已缓存</string>
<string name="noRecordInshelf">书架空空如也</string>
<string name="msgLoading">正在加载...</string>
<string name="refresh">重试</string>
<string-array name="voicer_cloud_entries">
<item>小燕—女青、中英、普通话</item>

View File

@ -127,7 +127,7 @@
</style>
<style name="llGraySplit.2dp.gray">
<item name="android:background">@color/whitesmoke</item>
<item name="android:padding">2dp</item>
</style>
<style name="TextViewTitle">
<item name="android:paddingLeft">5dp</item>
@ -144,9 +144,6 @@
<item name="android:textSize">15sp</item>
</style>
<style name="TextViewDesc.small">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">@color/common_google_signin_btn_text_light</item>
<item name="android:textSize">13sp</item>
</style>
<style name="llGallaryImage">
@ -191,8 +188,8 @@
<style name="buttonRound">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:background">@drawable/item_selector</item>
<item name="android:layout_marginRight">3dp</item>
<item name="android:background">@drawable/button_bg</item>
<item name="android:textColor">@color/white</item>
</style>
@ -310,8 +307,8 @@
<item name="android:layout_width">wrap_content</item>
<item name="android:lines">1</item>
<item name="android:textSize">14dp</item>
<item name="android:ellipsize">end</item>
<!--<item name="android:ellipsize">end</item>-->
<item name="android:ellipsize">marquee</item>
</style>
<style name="TextViewNovelAuthor">