diff --git a/app/build.gradle b/app/build.gradle index 1b2cead..86c14da 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -62,7 +62,7 @@ android { } defaultConfig { - applicationId "com.gedoor.monkeybook.super" + applicationId "com.nick.monkeybook.super" minSdkVersion min_sdk_version targetSdkVersion target_sdk_version versionCode currentVersionCode @@ -113,6 +113,11 @@ configurations.all { } } } +repositories { + flatDir { + dirs 'libs' + } +} dependencies { implementation project(':basemvplib') diff --git a/app/src/main/java/com/monke/monkeybook/bean/BookShelfBean.java b/app/src/main/java/com/monke/monkeybook/bean/BookShelfBean.java index 360ee17..8009b59 100644 --- a/app/src/main/java/com/monke/monkeybook/bean/BookShelfBean.java +++ b/app/src/main/java/com/monke/monkeybook/bean/BookShelfBean.java @@ -531,4 +531,10 @@ public String getVariable(String key) { } return variableStore.getVariable(key); } + + + public int getUnreadChapterNum() { + int num = getChapterListSize() - getDurChapter() - 1; + return num < 0 ? 0 : num; + } } \ No newline at end of file diff --git a/app/src/main/java/com/monke/monkeybook/bean/SearchBookBean.java b/app/src/main/java/com/monke/monkeybook/bean/SearchBookBean.java index c80a468..439d15b 100644 --- a/app/src/main/java/com/monke/monkeybook/bean/SearchBookBean.java +++ b/app/src/main/java/com/monke/monkeybook/bean/SearchBookBean.java @@ -150,7 +150,7 @@ public void setNoteUrl(String noteUrl) { public String getRealNoteUrl() { if (!StringUtils.isBlank(noteUrl) - && noteUrl.startsWith("@716:")) { + && noteUrl.startsWith("@SQi:")) { return noteUrl.substring(5); } return noteUrl; diff --git a/app/src/main/java/com/monke/monkeybook/model/SearchBookModel.java b/app/src/main/java/com/monke/monkeybook/model/SearchBookModel.java index 111badf..1e748c4 100644 --- a/app/src/main/java/com/monke/monkeybook/model/SearchBookModel.java +++ b/app/src/main/java/com/monke/monkeybook/model/SearchBookModel.java @@ -13,7 +13,6 @@ import com.monke.monkeybook.bean.SearchEngine; import com.monke.monkeybook.help.AppConfigHelper; import com.monke.monkeybook.model.annotation.BookType; -import com.monke.monkeybook.model.content.Default716; import com.monke.monkeybook.model.content.DefaultShuqi; import com.monke.monkeybook.model.impl.ISearchTask; import com.monke.monkeybook.model.task.SearchTaskImpl; @@ -36,7 +35,6 @@ public class SearchBookModel implements ISearchTask.OnSearchingListener { private String group; private SearchListener searchListener; private boolean searchEngineChanged = false; - private boolean useMy716; private boolean useShuqi; private final List searchEngineS = new ArrayList<>(); private final List searchTasks = new ArrayList<>(); @@ -91,14 +89,10 @@ public SearchBookModel(Context context) { /** * 搜索引擎初始化 */ - private void initSearchEngineS() { + public void initSearchEngineS() { if (!searchEngineS.isEmpty()) { searchEngineS.clear(); } - - if (useMy716) { - searchEngineS.add(new SearchEngine(Default716.TAG)); - } if (useShuqi) { searchEngineS.add(new SearchEngine(DefaultShuqi.TAG)); } @@ -108,7 +102,7 @@ private void initSearchEngineS() { if (searchBookType != null && !TextUtils.equals(bookSourceBean.getBookSourceType(), searchBookType)) { continue; } - searchEngineS.add(new SearchEngine(bookSourceBean.getBookSourceUrl())); + searchEngineS.add(new SearchEngine(bookSourceBean.getBookSourceUrl())); } } searchEngineChanged = false; @@ -123,6 +117,7 @@ public void startSearch(String query) { if (searchEngineChanged || searchEngineS.isEmpty()) { initSearchEngineS(); + //searchHandler.obtainMessage(SearchHandler.MSG_EMPTY).sendToTarget(); } else { for (SearchEngine searchEngine : searchEngineS) { searchEngine.searchReset(); @@ -192,11 +187,6 @@ public SearchBookModel listener(SearchListener listener) { return this; } - public SearchBookModel useMy716(boolean useMy716) { - this.useMy716 = useMy716; - return this; - } - public SearchBookModel useShuqi(boolean useShuqi) { this.useShuqi = useShuqi; return this; diff --git a/app/src/main/java/com/monke/monkeybook/model/WebBookModel.java b/app/src/main/java/com/monke/monkeybook/model/WebBookModel.java index d5c4ac1..095cb66 100644 --- a/app/src/main/java/com/monke/monkeybook/model/WebBookModel.java +++ b/app/src/main/java/com/monke/monkeybook/model/WebBookModel.java @@ -10,7 +10,6 @@ import com.monke.monkeybook.bean.SearchBookBean; import com.monke.monkeybook.help.BookshelfHelp; import com.monke.monkeybook.help.ChapterContentHelp; -import com.monke.monkeybook.model.content.Default716; import com.monke.monkeybook.model.content.DefaultModel; import com.monke.monkeybook.model.content.DefaultShuqi; import com.monke.monkeybook.model.impl.IAudioBookChapterModel; @@ -22,7 +21,6 @@ import java.util.Objects; import io.reactivex.Observable; -import io.reactivex.schedulers.Schedulers; public class WebBookModel implements IWebBookModel { @@ -132,8 +130,6 @@ public Observable> findBook(String tag, String url, int pag private IStationBookModel getBookSourceModel(String tag) { if (BookShelfBean.LOCAL_TAG.equals(tag)) { return null; - } else if (TextUtils.equals(tag, Default716.TAG)) { - return Default716.getInstance(); } else if (TextUtils.equals(tag, DefaultShuqi.TAG)) { return DefaultShuqi.getInstance(); } else { diff --git a/app/src/main/java/com/monke/monkeybook/model/content/Default716.java b/app/src/main/java/com/monke/monkeybook/model/content/Default716.java deleted file mode 100644 index 3cfc0fc..0000000 --- a/app/src/main/java/com/monke/monkeybook/model/content/Default716.java +++ /dev/null @@ -1,260 +0,0 @@ -package com.monke.monkeybook.model.content; - -import android.text.TextUtils; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.monke.basemvplib.BaseModelImpl; -import com.monke.basemvplib.OkHttpHelper; -import com.monke.monkeybook.bean.BookContentBean; -import com.monke.monkeybook.bean.BookInfoBean; -import com.monke.monkeybook.bean.BookShelfBean; -import com.monke.monkeybook.bean.ChapterBean; -import com.monke.monkeybook.bean.SearchBookBean; -import com.monke.monkeybook.model.analyzeRule.AnalyzeHeaders; -import com.monke.monkeybook.model.annotation.BookType; -import com.monke.monkeybook.model.impl.IHttpGetApi; -import com.monke.monkeybook.model.impl.IStationBookModel; -import com.monke.monkeybook.utils.StringUtils; - -import org.jsoup.nodes.Element; -import org.seimicrawler.xpath.JXDocument; - -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import io.reactivex.Observable; -import retrofit2.Response; - -public class Default716 extends BaseModelImpl implements IStationBookModel { - public static final String TAG = "My716"; - - private volatile static Default716 sInstance; - - private Default716() { - } - - public static Default716 getInstance() { - if (sInstance == null) { - synchronized (Default716.class) { - if (sInstance == null) { - sInstance = new Default716(); - } - } - } - return sInstance; - } - - /** - * 发现书籍 - */ - @Override - public Observable> findBook(String url, int page) { - return null; - } - - /** - * 搜索书籍 - */ - @Override - public Observable> searchBook(String content, int page) { - Map queryMap = new HashMap<>(); - queryMap.put("query", content); - return OkHttpHelper.getInstance().createService("http://api.zhuishushenqi.com", IHttpGetApi.class) - .searchBook("http://api.zhuishushenqi.com/book/fuzzy-search", - queryMap, - AnalyzeHeaders.getMap(null)) - .flatMap(this::analyzeSearchBook); - } - - private Observable> analyzeSearchBook(final Response response) { - return Observable.create(e -> { - List searchBookList = new ArrayList<>(); - JsonObject root = new JsonParser().parse(Objects.requireNonNull(response.body())).getAsJsonObject(); - if (root.get("ok").getAsBoolean()) { - JsonArray bookArray = root.get("books").getAsJsonArray(); - for (int i = 0, size = bookArray.size(); i < size; i++) { - JsonObject book = bookArray.get(i).getAsJsonObject(); - SearchBookBean searchBookBean = new SearchBookBean(); - searchBookBean.setTag(TAG); - searchBookBean.setOrigin(TAG); - searchBookBean.setBookType(BookType.TEXT); - searchBookBean.setWeight(Integer.MAX_VALUE); - searchBookBean.setKind(book.get("cat").getAsString()); - searchBookBean.setName(book.get("title").getAsString()); - searchBookBean.setAuthor(book.get("author").getAsString()); - searchBookBean.setNoteUrl("@716:http://api.zhuishushenqi.com/atoc?view=summary&book=" + book.get("_id").getAsString()); - String lastChapter = book.get("lastChapter").getAsString().replaceAll("^\\s*正文[卷:\\s]+", ""); - searchBookBean.setLastChapter(lastChapter); - searchBookBean.setCoverUrl("http://statics.zhuishushenqi.com" + book.get("cover").getAsString()); - searchBookBean.setIntroduce(book.get("shortIntro").getAsString()); - searchBookList.add(searchBookBean); - } - } - e.onNext(searchBookList); - e.onComplete(); - }); - } - - /** - * 网络请求并解析书籍信息 - */ - @Override - public Observable getBookInfo(BookShelfBean bookShelfBean) { - return OkHttpHelper.getInstance().createService("http://api.zhuishushenqi.com", IHttpGetApi.class) - .getWebContent(bookShelfBean.getNoteUrl(), AnalyzeHeaders.getMap(null)) - .flatMap(response -> analyzeBookInfo(response.body(), bookShelfBean)); - } - - private Observable analyzeBookInfo(String s, final BookShelfBean bookShelfBean) { - return Observable.create(e -> { - if (TextUtils.isEmpty(s)) { - e.onError(new Throwable("书籍信息获取失败")); - e.onComplete(); - return; - } - - JsonArray sourceArray = new JsonParser().parse(s).getAsJsonArray(); - HashMap sourceMap = new HashMap<>(); - for (int i = 0, size = sourceArray.size(); i < size; i++) { - JsonObject source = sourceArray.get(i).getAsJsonObject(); - String name = source.get("source").getAsString(); - sourceMap.put(name, source); - } - - JsonObject targetSource = null; - if (sourceMap.containsKey("xbiquge")) { - targetSource = sourceMap.get("xbiquge"); - } else if (sourceMap.containsKey("my176")) { - targetSource = sourceMap.get("my176"); - } else if (sourceMap.containsKey("hunhun")) { - targetSource = sourceMap.get("hunhun"); - } else if (sourceMap.containsKey("sanjiangge")) { - targetSource = sourceMap.get("sanjiangge"); - } else if (sourceMap.containsKey("xiaoxiaoshuwu")) { - targetSource = sourceMap.get("xiaoxiaoshuwu"); - } else if (sourceMap.containsKey("luoqiu")) { - targetSource = sourceMap.get("luoqiu"); - } else if (sourceMap.containsKey("snwx")) { - targetSource = sourceMap.get("snwx"); - } else if (sourceMap.containsKey("tianyibook")) { - targetSource = sourceMap.get("tianyibook"); - } else if (sourceMap.containsKey("shuhaha")) { - targetSource = sourceMap.get("shuhaha"); - } else if (sourceMap.containsKey("lewenwu")) { - targetSource = sourceMap.get("lewenwu"); - } else if (sourceMap.containsKey("zhuishuvip")) { - targetSource = sourceMap.get("zhuishuvip"); - } else if (sourceMap.size() > 0) { - Iterator it = sourceMap.keySet().iterator(); - targetSource = sourceMap.get(it.next()); - } - - if (targetSource != null) { - bookShelfBean.setLastChapterName(targetSource.get("lastChapter").getAsString()); - BookInfoBean bookInfoBean = bookShelfBean.getBookInfoBean(); - bookInfoBean.setBookType(BookType.TEXT); - bookInfoBean.setTag(TAG); - bookInfoBean.setOrigin(TAG); - bookInfoBean.setNoteUrl(bookShelfBean.getNoteUrl()); - bookInfoBean.setChapterListUrl("http://api.zhuishushenqi.com/atoc/" + targetSource.get("_id").getAsString() + "?view=chapters"); - e.onNext(bookShelfBean); - } else { - e.onError(new Throwable("书籍信息获取失败")); - } - e.onComplete(); - }); - } - - /** - * 网络解析图书目录 - */ - @Override - public Observable> getChapterList(BookShelfBean bookShelfBean) { - return OkHttpHelper.getInstance().createService("http://api.zhuishushenqi.com", IHttpGetApi.class) - .getWebContent(bookShelfBean.getBookInfoBean().getChapterListUrl(), AnalyzeHeaders.getMap(null)) - .flatMap(response -> analyzeChapterList(response.body(), bookShelfBean.getNoteUrl())); - } - - private Observable> analyzeChapterList(String s, String noteUrl) { - return Observable.create(e -> { - List chapterList = new ArrayList<>(); - JsonObject root = new JsonParser().parse(s).getAsJsonObject(); - JsonArray chapterArray = root.get("chapters").getAsJsonArray(); - for (JsonElement element : chapterArray) { - JsonObject chapter = element.getAsJsonObject(); - ChapterBean chapterBean = new ChapterBean(); - chapterBean.setDurChapterName(chapter.get("title").getAsString()); - final String link = chapter.get("link").getAsString(); - if (link.contains("vip.zhuishushenqi") - || link.contains("xbiquge")) { - chapterBean.setDurChapterUrl("http://chapterup.zhuishushenqi.com/chapter/" + URLEncoder.encode(link, "UTF-8")); - } else { - chapterBean.setDurChapterUrl(link); - } - chapterBean.setNoteUrl(noteUrl); - chapterList.add(chapterBean); - } - e.onNext(chapterList); - e.onComplete(); - }); - } - - /** - * 章节缓存 - */ - @Override - public Observable getBookContent(String chapterUrl, ChapterBean chapterBean) { - return OkHttpHelper.getInstance().createService(StringUtils.getBaseUrl(chapterBean.getDurChapterUrl()), IHttpGetApi.class) - .getWebContent(chapterBean.getDurChapterUrl(), AnalyzeHeaders.getMap(null)) - .flatMap(response -> analyzeBookContent(response.body(), chapterBean)); - } - - private Observable analyzeBookContent(String s, ChapterBean chapterBean) { - return Observable.create(e -> { - final BookContentBean bookContentBean = new BookContentBean(); - bookContentBean.setDurChapterUrl(chapterBean.getDurChapterUrl()); - bookContentBean.setDurChapterIndex(chapterBean.getDurChapterIndex()); - bookContentBean.setDurChapterName(chapterBean.getDurChapterName()); - bookContentBean.setNoteUrl(chapterBean.getNoteUrl()); - - if (chapterBean.getDurChapterUrl().contains("zhuishushenqi")) { - JsonObject root = new JsonParser().parse(s).getAsJsonObject(); - if (root.get("ok").getAsBoolean()) { - JsonObject chapterJson = root.get("chapter").getAsJsonObject(); - final String result; - if (chapterJson.has("isVip")) { - if (chapterJson.get("isVip").getAsBoolean()) { - result = "当前章节为VIP章节,无法阅读,请换源。"; - } else { - result = chapterJson.get("cpContent").getAsString(); - } - } else { - result = chapterJson.get("body").getAsString(); - } - bookContentBean.appendDurChapterContent(result.replaceAll("\\\\r\\\\n", "")); - } - } else { - JXDocument document = JXDocument.create(s); - Object object = document.selOne("//div[@name=\"content\"] or @id=\"content\" or @class=\"txt_tcontent\" or @id=\"htmlContent\""); - final String result; - if (object instanceof Element) { - result = ((Element) object).html(); - } else { - result = StringUtils.valueOf(object); - } - bookContentBean.appendDurChapterContent(result.replaceAll("\\\\r\\\\n", "")); - } - e.onNext(bookContentBean); - e.onComplete(); - }); - } - -} diff --git a/app/src/main/java/com/monke/monkeybook/model/content/DefaultShuqi.java b/app/src/main/java/com/monke/monkeybook/model/content/DefaultShuqi.java index 880a5c6..4b2527a 100644 --- a/app/src/main/java/com/monke/monkeybook/model/content/DefaultShuqi.java +++ b/app/src/main/java/com/monke/monkeybook/model/content/DefaultShuqi.java @@ -31,7 +31,7 @@ import io.reactivex.Observable; public class DefaultShuqi extends BaseModelImpl implements IStationBookModel { - public static final String TAG = "ShuQi"; + public static final String TAG = "书旗"; private volatile static DefaultShuqi sInstance; @@ -70,13 +70,34 @@ public Observable> searchBook(String content, int page) { private Observable> analyzeSearchBook(final String response) { return Observable.create(e -> { List searchBooks = new ArrayList<>(); + SearchBookBean item; JsonObject root = new JsonParser().parse(response).getAsJsonObject(); + JsonObject info = root.getAsJsonObject("info"); + int pageI = info.get("page").getAsInt(); + if (pageI == 1) { + if (root.has("aladdin")) { + JsonObject aladdin = root.getAsJsonObject("aladdin"); + item = new SearchBookBean(); + item.setTag(TAG); + item.setOrigin(TAG); + item.setBookType(BookType.TEXT); + item.setWeight(Integer.MAX_VALUE); + item.setAuthor(aladdin.get("author").getAsString()); + item.setKind(aladdin.get("category").getAsString()); + item.setLastChapter(aladdin.get("latest_chapter").getAsJsonObject().get("cname").getAsString()); + item.setName(aladdin.get("title").getAsString()); + item.setNoteUrl("@SQi:"+aladdin.get("bid").getAsString()); + item.setCoverUrl(aladdin.get("cover").getAsString().replace("\\/", "/")); + item.setIntroduce(aladdin.get("desc").getAsString()); + searchBooks.add(item); + } + } + if (root.has("data")) { JsonArray booksArray = root.getAsJsonArray("data"); for (JsonElement element : booksArray) { JsonObject book = element.getAsJsonObject(); - String bookId = book.get("bid").getAsString(); - SearchBookBean item = new SearchBookBean(); + item = new SearchBookBean(); item.setTag(TAG); item.setOrigin(TAG); item.setBookType(BookType.TEXT); @@ -85,10 +106,9 @@ private Observable> analyzeSearchBook(final String response item.setKind(book.get("category").getAsString()); item.setLastChapter(book.get("first_chapter").getAsString()); item.setName(book.get("title").getAsString()); - item.setNoteUrl("http://c1.shuqireader.com/httpserver/filecache/get_book_content_" + bookId); + item.setNoteUrl("@SQi:"+book.get("bid").getAsString()); item.setCoverUrl(book.get("cover").getAsString().replace("\\/", "/")); item.setIntroduce(book.get("desc").getAsString()); - item.putVariable("bookId", bookId); searchBooks.add(item); } } @@ -102,12 +122,11 @@ private Observable> analyzeSearchBook(final String response */ @Override public Observable getBookInfo(BookShelfBean bookShelfBean) { - String bid = bookShelfBean.getVariable("bookId"); - String timestamp = String.valueOf(System.currentTimeMillis()); - String data = bid + timestamp + "800000037e81a9d8f02596e1b895d07c171d5c9"; - String Sign = MD5Utils.strToMd5By32(data); + String bid = bookShelfBean.getNoteUrl(); + String Data = bid + "1514984538213800000037e81a9d8f02596e1b895d07c171d5c9"; + String Sign = MD5Utils.strToMd5By32(Data); HashMap fieldMap = new HashMap<>(); - fieldMap.put("timestamp", timestamp); + fieldMap.put("timestamp", "1514984538213"); fieldMap.put("user_id", "8000000"); fieldMap.put("bookId", bid); fieldMap.put("sign", Sign); @@ -148,12 +167,11 @@ private Observable analyzeBookInfo(String s, final BookShelfBean */ @Override public Observable> getChapterList(BookShelfBean bookShelfBean) { - String bid = bookShelfBean.getVariable("bookId"); - String timestamp = String.valueOf(System.currentTimeMillis()); - String data = bid + timestamp + "800000037e81a9d8f02596e1b895d07c171d5c9"; - String Sign = MD5Utils.strToMd5By32(data); + String bid = bookShelfBean.getNoteUrl(); + String Data = bid + "1514984538213800000037e81a9d8f02596e1b895d07c171d5c9"; + String Sign = MD5Utils.strToMd5By32(Data); HashMap fieldMap = new HashMap<>(); - fieldMap.put("timestamp", timestamp); + fieldMap.put("timestamp", "1514984538213"); fieldMap.put("user_id", "8000000"); fieldMap.put("bookId", bid); fieldMap.put("sign", Sign); @@ -174,7 +192,7 @@ private Observable> analyzeChapterList(String s, String noteUr String chapterId = ele.getAsJsonObject().get("chapterId").getAsString(); String chapterName = ele.getAsJsonObject().get("chapterName").getAsString(); ChapterBean temp = new ChapterBean(); - temp.setDurChapterUrl(noteUrl + "_" + chapterId + ".xml"); //id + temp.setDurChapterUrl("http://c1.shuqireader.com/httpserver/filecache/get_book_content_" + noteUrl + "_" + chapterId + ".xml"); //id temp.setDurChapterName(chapterName); temp.setNoteUrl(noteUrl); chapterBeans.add(temp); diff --git a/app/src/main/java/com/monke/monkeybook/model/task/SearchTaskImpl.java b/app/src/main/java/com/monke/monkeybook/model/task/SearchTaskImpl.java index 81aaeca..d0f722b 100644 --- a/app/src/main/java/com/monke/monkeybook/model/task/SearchTaskImpl.java +++ b/app/src/main/java/com/monke/monkeybook/model/task/SearchTaskImpl.java @@ -9,14 +9,11 @@ import com.monke.monkeybook.dao.DbHelper; import com.monke.monkeybook.model.BookSourceManager; import com.monke.monkeybook.model.WebBookModel; -import com.monke.monkeybook.model.content.Default716; import com.monke.monkeybook.model.content.DefaultShuqi; import com.monke.monkeybook.model.impl.ISearchTask; - import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; - import io.reactivex.Observable; import io.reactivex.Scheduler; import io.reactivex.disposables.CompositeDisposable; @@ -95,9 +92,6 @@ private void toSearch(String query, Scheduler scheduler) { if (!isDisposed() && !searchBookBeans.isEmpty()) { listener.onSearchResult(searchBookBeans); - if (TextUtils.equals(searchBookBeans.get(0).getTag(), Default716.TAG)) { - hasMore = false; - } if (TextUtils.equals(searchBookBeans.get(0).getTag(), DefaultShuqi.TAG)) { hasMore = false; } diff --git a/app/src/main/java/com/monke/monkeybook/presenter/ReadBookPresenterImpl.java b/app/src/main/java/com/monke/monkeybook/presenter/ReadBookPresenterImpl.java index 9e59c8a..09c2d22 100644 --- a/app/src/main/java/com/monke/monkeybook/presenter/ReadBookPresenterImpl.java +++ b/app/src/main/java/com/monke/monkeybook/presenter/ReadBookPresenterImpl.java @@ -29,7 +29,6 @@ import com.monke.monkeybook.help.RxBusTag; import com.monke.monkeybook.model.BookSourceManager; import com.monke.monkeybook.model.WebBookModel; -import com.monke.monkeybook.model.content.Default716; import com.monke.monkeybook.model.content.DefaultShuqi; import com.monke.monkeybook.presenter.contract.ReadBookContract; import com.monke.monkeybook.service.DownloadService; @@ -96,8 +95,6 @@ public void disableDurBookSource() { try { switch (bookShelf.getTag()) { case BookShelfBean.LOCAL_TAG: - case Default716.TAG: - break; case DefaultShuqi.TAG: break; default: @@ -309,10 +306,7 @@ public void onError(Throwable e) { } private void prepareSync() { - if (TextUtils.equals(bookShelf.getTag(), Default716.TAG) - || bookShelf.isLocalBook()) { - mView.upMenu(); - } else if (TextUtils.equals(bookShelf.getTag(), DefaultShuqi.TAG) + if (TextUtils.equals(bookShelf.getTag(), DefaultShuqi.TAG) || bookShelf.isLocalBook()) { mView.upMenu(); } else { diff --git a/app/src/main/java/com/monke/monkeybook/presenter/SearchBookPresenterImpl.java b/app/src/main/java/com/monke/monkeybook/presenter/SearchBookPresenterImpl.java index df8c243..e21e304 100644 --- a/app/src/main/java/com/monke/monkeybook/presenter/SearchBookPresenterImpl.java +++ b/app/src/main/java/com/monke/monkeybook/presenter/SearchBookPresenterImpl.java @@ -43,7 +43,6 @@ public SearchBookPresenterImpl(Context context) { //搜索引擎初始化 searchBookModel = new SearchBookModel(context) .listener(this) - .useMy716(AppConfigHelper.get().getBoolean("useMy716", true)) .useShuqi(AppConfigHelper.get().getBoolean("useShuqi", true)) .setup(); } @@ -220,12 +219,6 @@ public void stopSearch() { searchBookModel.stopSearch(); } - @Override - public void useMy716(Boolean bool) { - searchBookModel.useMy716(bool); - searchBookModel.notifySearchEngineChanged(); - } - @Override public void useShuqi(Boolean bool) { searchBookModel.useShuqi(bool); diff --git a/app/src/main/java/com/monke/monkeybook/presenter/contract/SearchBookContract.java b/app/src/main/java/com/monke/monkeybook/presenter/contract/SearchBookContract.java index e4f1732..2cfd61b 100644 --- a/app/src/main/java/com/monke/monkeybook/presenter/contract/SearchBookContract.java +++ b/app/src/main/java/com/monke/monkeybook/presenter/contract/SearchBookContract.java @@ -28,8 +28,6 @@ interface Presenter extends IPresenter { void stopSearch(); - void useMy716(Boolean bool); - void useShuqi(Boolean bool); } diff --git a/app/src/main/java/com/monke/monkeybook/service/WebService.java b/app/src/main/java/com/monke/monkeybook/service/WebService.java index adb2810..09e3333 100644 --- a/app/src/main/java/com/monke/monkeybook/service/WebService.java +++ b/app/src/main/java/com/monke/monkeybook/service/WebService.java @@ -8,9 +8,6 @@ import android.content.Intent; import android.os.IBinder; -import androidx.annotation.Nullable; -import androidx.core.app.NotificationCompat; - import com.monke.monkeybook.MApplication; import com.monke.monkeybook.R; import com.monke.basemvplib.NetworkUtil; @@ -21,6 +18,9 @@ import java.io.IOException; import java.net.InetAddress; +import androidx.annotation.Nullable; +import androidx.core.app.NotificationCompat; + public class WebService extends Service { private static boolean isRunning = false; private HttpServer httpServer; @@ -111,7 +111,7 @@ private PendingIntent getThisServicePendingIntent() { } private int getPort() { - return 1223; + return 1222; } /** diff --git a/app/src/main/java/com/monke/monkeybook/view/activity/ReadBookActivity.java b/app/src/main/java/com/monke/monkeybook/view/activity/ReadBookActivity.java index cca7cc7..2005c0c 100644 --- a/app/src/main/java/com/monke/monkeybook/view/activity/ReadBookActivity.java +++ b/app/src/main/java/com/monke/monkeybook/view/activity/ReadBookActivity.java @@ -47,7 +47,7 @@ import com.monke.monkeybook.help.BitIntentDataManager; import com.monke.monkeybook.help.BookShelfHolder; import com.monke.monkeybook.help.ReadBookControl; -import com.monke.monkeybook.model.content.Default716; + import com.monke.monkeybook.model.content.DefaultShuqi; import com.monke.monkeybook.presenter.ReadBookPresenterImpl; import com.monke.monkeybook.presenter.contract.ReadBookContract; @@ -1042,14 +1042,11 @@ public boolean onPrepareOptionsMenu(Menu menu) { } } final boolean defaultShuqi = DefaultShuqi.TAG.equals(mPresenter.getBookShelf().getTag()); - final boolean default716 = Default716.TAG.equals(mPresenter.getBookShelf().getTag()); + MenuItem disableSourceItem = menu.findItem(R.id.disable_book_source); - if (default716 || defaultShuqi) { + if (defaultShuqi) { disableSourceItem.setVisible(false); disableSourceItem.setEnabled(false); - } else { - disableSourceItem.setVisible(true); - disableSourceItem.setEnabled(true); } } return super.onPrepareOptionsMenu(menu); diff --git a/app/src/main/java/com/monke/monkeybook/view/activity/SearchBookActivity.java b/app/src/main/java/com/monke/monkeybook/view/activity/SearchBookActivity.java index 28b1982..86db060 100644 --- a/app/src/main/java/com/monke/monkeybook/view/activity/SearchBookActivity.java +++ b/app/src/main/java/com/monke/monkeybook/view/activity/SearchBookActivity.java @@ -13,13 +13,6 @@ import android.view.View; import android.widget.TextView; -import androidx.annotation.NonNull; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.widget.SearchView; -import androidx.appcompat.widget.Toolbar; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - import com.google.android.flexbox.FlexboxLayout; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.monke.basemvplib.AppActivityManager; @@ -41,6 +34,12 @@ import java.util.List; import java.util.Objects; +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.widget.SearchView; +import androidx.appcompat.widget.Toolbar; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import butterknife.BindView; import butterknife.ButterKnife; @@ -250,10 +249,6 @@ public void upMenu() { @Override public boolean onPrepareOptionsMenu(Menu menu) { - MenuItem my716 = menu.findItem(R.id.action_book_my716); - if (my716 != null) { - my716.setChecked(AppConfigHelper.get().getBoolean("useMy716", true)); - } MenuItem shuqi = menu.findItem(R.id.action_book_shuqi); if (shuqi != null) { shuqi.setChecked(AppConfigHelper.get().getBoolean("useShuqi", true)); @@ -270,11 +265,6 @@ public boolean onOptionsItemSelected(MenuItem item) { case R.id.action_book_source_manage: BookSourceActivity.startThis(this); break; - case R.id.action_book_my716: - item.setChecked(!item.isChecked()); - AppConfigHelper.get().edit().putBoolean("useMy716", item.isChecked()).apply(); - mPresenter.useMy716(item.isChecked()); - break; case R.id.action_book_shuqi: item.setChecked(!item.isChecked()); AppConfigHelper.get().edit().putBoolean("useShuqi", item.isChecked()).apply(); @@ -493,6 +483,4 @@ public void showBookSourceEmptyTip() { .setPositiveButton(R.string.goto_select, (dialog, which) -> BookSourceActivity.startThis(SearchBookActivity.this)) .show(); } - - } diff --git a/app/src/main/java/com/monke/monkeybook/view/adapter/BookShelfGridAdapter.java b/app/src/main/java/com/monke/monkeybook/view/adapter/BookShelfGridAdapter.java index 7f78507..b0e1aac 100644 --- a/app/src/main/java/com/monke/monkeybook/view/adapter/BookShelfGridAdapter.java +++ b/app/src/main/java/com/monke/monkeybook/view/adapter/BookShelfGridAdapter.java @@ -17,6 +17,7 @@ import com.monke.monkeybook.R; import com.monke.monkeybook.bean.BookShelfBean; import com.monke.monkeybook.view.adapter.base.BaseBookListAdapter; +import com.monke.monkeybook.widget.BadgeView; import com.monke.monkeybook.widget.RotateLoading; import java.util.List; @@ -63,22 +64,22 @@ public void onBindViewHolder(@NonNull MyViewHolder holder, int position, @NonNul } if (item.isFlag()) { + holder.tvHasNew.setVisibility(View.INVISIBLE); holder.rotateLoading.setVisibility(View.VISIBLE); } else { + if (item.getHasUpdate() && !item.isLocalBook()) { + holder.tvHasNew.setBadgeCount(item.getNewChapters()); + } else { + holder.tvHasNew.setBadgeCount(item.getUnreadChapterNum()); + } + holder.tvHasNew.setHighlight(item.getHasUpdate()); holder.rotateLoading.setVisibility(View.INVISIBLE); } - - if (item.getHasUpdate() && !item.isLocalBook()) { - holder.tvHasNew.setVisibility(View.VISIBLE); - } else { - holder.tvHasNew.setVisibility(View.INVISIBLE); - } - } public static class MyViewHolder extends RecyclerView.ViewHolder { ImageView ivCover; - TextView tvHasNew; + BadgeView tvHasNew; TextView tvName; RotateLoading rotateLoading; public View content; diff --git a/app/src/main/java/com/monke/monkeybook/view/adapter/BookShelfListAdapter.java b/app/src/main/java/com/monke/monkeybook/view/adapter/BookShelfListAdapter.java index 5bb3a78..696f813 100644 --- a/app/src/main/java/com/monke/monkeybook/view/adapter/BookShelfListAdapter.java +++ b/app/src/main/java/com/monke/monkeybook/view/adapter/BookShelfListAdapter.java @@ -23,6 +23,7 @@ import com.monke.monkeybook.bean.BookShelfBean; import com.monke.monkeybook.model.annotation.BookType; import com.monke.monkeybook.view.adapter.base.BaseBookListAdapter; +import com.monke.monkeybook.widget.BadgeView; import com.monke.monkeybook.widget.RotateLoading; import java.util.List; @@ -92,17 +93,17 @@ public void onBindViewHolder(@NonNull MyViewHolder holder, int position, @NonNul } if (item.isFlag()) { + holder.tvHasNew.setVisibility(View.INVISIBLE); holder.rotateLoading.setVisibility(View.VISIBLE); } else { + if (item.getHasUpdate() && !item.isLocalBook()) { + holder.tvHasNew.setBadgeCount(item.getNewChapters()); + } else { + holder.tvHasNew.setBadgeCount(item.getUnreadChapterNum()); + } + holder.tvHasNew.setHighlight(item.getHasUpdate()); holder.rotateLoading.setVisibility(View.INVISIBLE); } - - if (item.getHasUpdate() && !item.isLocalBook()) { - holder.tvHasNew.setVisibility(View.VISIBLE); - } else { - holder.tvHasNew.setVisibility(View.INVISIBLE); - } - } private SpannableStringBuilder getBookName(String name, int newChapters) { @@ -113,13 +114,13 @@ private SpannableStringBuilder getBookName(String name, int newChapters) { SpannableString chaptersSpan = new SpannableString(String.format(Locale.getDefault(), "(新增%d章)", newChapters)); chaptersSpan.setSpan(new RelativeSizeSpan(0.75f), 0, chaptersSpan.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); chaptersSpan.setSpan(new ForegroundColorSpan(getContext().getResources().getColor(R.color.colorTextSecondary)), 0, chaptersSpan.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - sbs.append(chaptersSpan); + //sbs.append(chaptersSpan); return sbs; } public static class MyViewHolder extends RecyclerView.ViewHolder { ImageView ivCover; - TextView tvHasNew; + BadgeView tvHasNew; TextView tvName; TextView tvAuthor; TextView tvRead; diff --git a/app/src/main/java/com/monke/monkeybook/view/fragment/dialog/ChangeSourceDialog.java b/app/src/main/java/com/monke/monkeybook/view/fragment/dialog/ChangeSourceDialog.java index 0d15a9f..d0616e8 100644 --- a/app/src/main/java/com/monke/monkeybook/view/fragment/dialog/ChangeSourceDialog.java +++ b/app/src/main/java/com/monke/monkeybook/view/fragment/dialog/ChangeSourceDialog.java @@ -87,7 +87,6 @@ public void onCreate(@Nullable Bundle savedInstanceState) { searchBookModel = new SearchBookModel(requireContext()) .onlyOnePage() - .useMy716(true) .useShuqi(true) .setSearchBookType(selectCover ? null : bookInfo.getBookType()) .listener(this) diff --git a/app/src/main/java/com/monke/monkeybook/widget/BadgeView.java b/app/src/main/java/com/monke/monkeybook/widget/BadgeView.java new file mode 100644 index 0000000..34c5ae8 --- /dev/null +++ b/app/src/main/java/com/monke/monkeybook/widget/BadgeView.java @@ -0,0 +1,233 @@ +package com.monke.monkeybook.widget; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ShapeDrawable; +import android.graphics.drawable.shapes.RoundRectShape; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.FrameLayout.LayoutParams; +import android.widget.TabWidget; + +import androidx.appcompat.widget.AppCompatTextView; + +import com.monke.monkeybook.R; + + +/** + * Created by milad heydari on 5/6/2016. + */ +public class BadgeView extends AppCompatTextView { + + private boolean mHideOnNull = true; + private float radius; + + public BadgeView(Context context) { + this(context, null); + } + + public BadgeView(Context context, AttributeSet attrs) { + this(context, attrs, android.R.attr.textViewStyle); + } + + public BadgeView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + init(); + } + + private void init() { + if (!(getLayoutParams() instanceof LayoutParams)) { + LayoutParams layoutParams = + new LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT, + Gravity.CENTER); + setLayoutParams(layoutParams); + } + + // set default font + setTextColor(Color.WHITE); + //setTypeface(Typeface.DEFAULT_BOLD); + setTextSize(TypedValue.COMPLEX_UNIT_SP, 11); + setPadding(dip2Px(5), dip2Px(1), dip2Px(5), dip2Px(1)); + radius = 8; + + // set default background + setBackground(radius, Color.parseColor("#d3321b")); + + setGravity(Gravity.CENTER); + + // default values + setHideOnNull(true); + setBadgeCount(0); + setMinWidth(dip2Px(16)); + setMinHeight(dip2Px(16)); + } + + public void setBackground(float dipRadius, int badgeColor) { + int radius = dip2Px(dipRadius); + float[] radiusArray = new float[]{radius, radius, radius, radius, radius, radius, radius, radius}; + + RoundRectShape roundRect = new RoundRectShape(radiusArray, null, null); + ShapeDrawable bgDrawable = new ShapeDrawable(roundRect); + bgDrawable.getPaint().setColor(badgeColor); + setBackground(bgDrawable); + } + + public void setBackground(int badgeColor) { + setBackground(radius, badgeColor); + } + + /** + * @return Returns true if view is hidden on badge value 0 or null; + */ + public boolean isHideOnNull() { + return mHideOnNull; + } + + /** + * @param hideOnNull the hideOnNull to set + */ + public void setHideOnNull(boolean hideOnNull) { + mHideOnNull = hideOnNull; + setText(getText()); + } + + /** + * @see android.widget.TextView#setText(java.lang.CharSequence, android.widget.TextView.BufferType) + */ + @Override + public void setText(CharSequence text, BufferType type) { + if (isHideOnNull() && TextUtils.isEmpty(text)) { + setVisibility(GONE); + } else { + setVisibility(VISIBLE); + } + super.setText(text, type); + } + + public void setBadgeCount(int count) { + setText(String.valueOf(count)); + if (count == 0) { + setVisibility(GONE); + } + } + + public void setHighlight(boolean highlight) { + setBackground(getResources().getColor(highlight ? R.color.light_green : R.color.darker_gray)); + } + + public Integer getBadgeCount() { + if (getText() == null) { + return null; + } + String text = getText().toString(); + try { + return Integer.parseInt(text); + } catch (NumberFormatException e) { + return null; + } + } + + public void setBadgeGravity(int gravity) { + LayoutParams params = (LayoutParams) getLayoutParams(); + params.gravity = gravity; + setLayoutParams(params); + } + + public int getBadgeGravity() { + LayoutParams params = (LayoutParams) getLayoutParams(); + return params.gravity; + } + + public void setBadgeMargin(int dipMargin) { + setBadgeMargin(dipMargin, dipMargin, dipMargin, dipMargin); + } + + public void setBadgeMargin(int leftDipMargin, int topDipMargin, int rightDipMargin, int bottomDipMargin) { + LayoutParams params = (LayoutParams) getLayoutParams(); + params.leftMargin = dip2Px(leftDipMargin); + params.topMargin = dip2Px(topDipMargin); + params.rightMargin = dip2Px(rightDipMargin); + params.bottomMargin = dip2Px(bottomDipMargin); + setLayoutParams(params); + } + + public int[] getBadgeMargin() { + LayoutParams params = (LayoutParams) getLayoutParams(); + return new int[]{params.leftMargin, params.topMargin, params.rightMargin, params.bottomMargin}; + } + + public void incrementBadgeCount(int increment) { + Integer count = getBadgeCount(); + if (count == null) { + setBadgeCount(increment); + } else { + setBadgeCount(increment + count); + } + } + + public void decrementBadgeCount(int decrement) { + incrementBadgeCount(-decrement); + } + + /** + * Attach the BadgeView to the TabWidget + * @param target the TabWidget to attach the BadgeView + * @param tabIndex index of the tab + */ + public void setTargetView(TabWidget target, int tabIndex) { + View tabView = target.getChildTabViewAt(tabIndex); + setTargetView(tabView); + } + + /** + * Attach the BadgeView to the target view + * @param target the view to attach the BadgeView + */ + public void setTargetView(View target) { + if (getParent() != null) { + ((ViewGroup) getParent()).removeView(this); + } + + if (target == null) { + return; + } + + if (target.getParent() instanceof FrameLayout) { + ((FrameLayout) target.getParent()).addView(this); + + } else if (target.getParent() instanceof ViewGroup) { + // use a new Framelayout container for adding badge + ViewGroup parentContainer = (ViewGroup) target.getParent(); + int groupIndex = parentContainer.indexOfChild(target); + parentContainer.removeView(target); + + FrameLayout badgeContainer = new FrameLayout(getContext()); + ViewGroup.LayoutParams parentLayoutParams = target.getLayoutParams(); + + badgeContainer.setLayoutParams(parentLayoutParams); + target.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + + parentContainer.addView(badgeContainer, groupIndex, parentLayoutParams); + badgeContainer.addView(target); + + badgeContainer.addView(this); + } + + } + + /** + * converts dip to px + */ + private int dip2Px(float dip) { + return (int) (dip * getContext().getResources().getDisplayMetrics().density + 0.5f); + } +} diff --git a/app/src/main/res/layout/item_bookshelf_grid.xml b/app/src/main/res/layout/item_bookshelf_grid.xml index 2680345..f44a64c 100644 --- a/app/src/main/res/layout/item_bookshelf_grid.xml +++ b/app/src/main/res/layout/item_bookshelf_grid.xml @@ -25,22 +25,14 @@ android:transitionName="img_cover" tools:ignore="UnusedAttribute" /> - + tools:ignore="RtlHardcoded" /> - - - - + android:layout_marginEnd="2dp"> + + + diff --git a/app/src/main/res/menu/menu_search_activity.xml b/app/src/main/res/menu/menu_search_activity.xml index 9d4be9f..ad3c65d 100644 --- a/app/src/main/res/menu/menu_search_activity.xml +++ b/app/src/main/res/menu/menu_search_activity.xml @@ -14,12 +14,6 @@ android:title="@string/book_inner_source"> - - - - diff --git a/app/src/main/res/values/common_colors.xml b/app/src/main/res/values/common_colors.xml index 1e403ec..09b6c76 100644 --- a/app/src/main/res/values/common_colors.xml +++ b/app/src/main/res/values/common_colors.xml @@ -29,5 +29,5 @@ #66ffffff #66000000 #66dddddd - + #aaaaaaaa \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8e1eb19..7e1fa6f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -16,8 +16,7 @@ 全部 内置书源 外置书源 - My716 - ShuQi + 书旗 设置 关于 捐赠 diff --git a/basemvplib/build.gradle b/basemvplib/build.gradle index df0a08f..0d4f9bb 100644 --- a/basemvplib/build.gradle +++ b/basemvplib/build.gradle @@ -24,6 +24,7 @@ android { } dependencies { + //api fileTree(dir: 'libs', include: ['*.jar']) //support api 'androidx.core:core:1.2.0-alpha02' api 'androidx.appcompat:appcompat:1.1.0-beta01' diff --git a/build.gradle b/build.gradle index 94263fc..34c36b2 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,16 @@ ext { compile_sdk_version = 28 min_sdk_version = 21 - target_sdk_version = 27 + target_sdk_version = 28 support_library_version = '28.0.0' } buildscript { repositories { + maven { url "https://maven.aliyun.com/nexus/content/groups/public/" } + maven { url "https://maven.aliyun.com/nexus/content/repositories/google" } + maven { url "https://maven.aliyun.com/nexus/content/repositories/jcenter" } + maven { url "https://maven.aliyun.com/nexus/content/repositories/gradle-plugin" } google() jcenter() mavenCentral() @@ -22,7 +26,10 @@ allprojects { flatDir { dirs 'libs' } - + maven { url "https://maven.aliyun.com/nexus/content/groups/public/" } + maven { url "https://maven.aliyun.com/nexus/content/repositories/google" } + maven { url "https://maven.aliyun.com/nexus/content/repositories/jcenter" } + maven { url "https://maven.aliyun.com/nexus/content/repositories/gradle-plugin" } google() jcenter() mavenCentral() diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3572901..222fc13 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip