first commit

master
hai 2 years ago
parent 2032558770
commit b9fd53e068

9
.gitignore vendored

@ -0,0 +1,9 @@
0*.iml
.gradle
.idea
/local.properties
.DS_Store
/build
/captures
.externalNativeBuild
wanandroid.jks

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

@ -0,0 +1 @@
theme: jekyll-theme-leap-day

1
app/.gitignore vendored

@ -0,0 +1 @@
/build

@ -0,0 +1,48 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.kdp.wanandroidclient"
minSdkVersion 15
targetSdkVersion 28
versionCode 1
versionName "1.1"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
buildConfigField("boolean","LOG_DEBUG","false")
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
buildConfigField("boolean","LOG_DEBUG","true")
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
productFlavors {
}
}
dependencies {
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'io.reactivex.rxjava2:rxjava:2.1.16'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'com.squareup.retrofit2:retrofit:2.2.0'
implementation 'com.squareup.retrofit2:converter-gson:2.2.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:cardview-v7:28.0.0'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.github.bumptech.glide:glide:4.8.0'
implementation 'com.just.agentweb:agentweb:4.0.1'
implementation 'com.hyman:flowlayout-lib:1.1.2'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4'
//debug
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
}

@ -0,0 +1,25 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in F:\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.kdp.wanandroidclient">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:name=".application.WApp"
android:networkSecurityConfig="@xml/network_security_config"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="UnusedAttribute">
<activity
android:name=".ui.LauncherActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.Start">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.logon.LogonActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.Logon"
/>
<activity
android:name=".ui.main.MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="portrait" />
<activity
android:name=".ui.tree.TreeActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="portrait" />
<activity
android:name=".ui.main.SearchActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.Search"/>
<activity
android:name=".ui.web.WebViewActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="portrait" />
<activity
android:name=".ui.user.CollectArticleActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:screenOrientation="portrait" />
<activity
android:name=".ui.user.AboutUsActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:screenOrientation="portrait" />
</application>
</manifest>

@ -0,0 +1,194 @@
package com.kdp.wanandroidclient.api;
import com.kdp.wanandroidclient.bean.Article;
import com.kdp.wanandroidclient.bean.Banner;
import com.kdp.wanandroidclient.bean.BaseBean;
import com.kdp.wanandroidclient.bean.Chapter;
import com.kdp.wanandroidclient.bean.Friend;
import com.kdp.wanandroidclient.bean.Hotword;
import com.kdp.wanandroidclient.bean.PageListData;
import com.kdp.wanandroidclient.bean.ProjectCate;
import com.kdp.wanandroidclient.bean.Tree;
import com.kdp.wanandroidclient.bean.User;
import com.kdp.wanandroidclient.common.UrlConstainer;
import java.util.List;
import io.reactivex.Observable;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Path;
import retrofit2.http.Query;
/**
*
*/
public interface ApiServer {
/**
*
*
* @param username
* @param password
* @return
*/
@FormUrlEncoded
@POST(UrlConstainer.LOGIN)
Observable<BaseBean<User>> login(@Field("username") String username, @Field("password") String password);
/**
*
*
* @param username
* @param password
* @param repassword
* @return
*/
@FormUrlEncoded
@POST(UrlConstainer.REGISTER)
Observable<BaseBean<String>> register(@Field("username") String username, @Field("password") String password, @Field("repassword") String repassword);
/**
* 广
*
* @return
*/
@GET(UrlConstainer.MAIN_BANNER)
Observable<BaseBean<List<Banner>>> getBanner();
/**
*
* @return
*/
@GET(UrlConstainer.HOME_TOP_LIST)
Observable<BaseBean<List<Article>>> getHomeTopList();
/**
*
*
* @return
*/
@GET(UrlConstainer.HOME_LIST)
Observable<BaseBean<PageListData<Article>>> getHomeList(@Path("page") int page);
/**
*
*
* @param id
* @return
*/
@POST(UrlConstainer.COLLECT_ARTICLE)
Observable<BaseBean<String>> collectArticle(@Path("id") int id);
/**
*
*
* @param id
* @return
*/
@POST(UrlConstainer.UNCOLLECT_ARTICLE)
Observable<BaseBean<String>> unCollectArticle(@Path("id") int id);
/**
*
*
* @return
*/
@GET(UrlConstainer.TREE)
Observable<BaseBean<List<Tree>>> getTree();
/**
*
*
* @param cid
* @param page
* @return
*/
@GET(UrlConstainer.TREE_LIST)
Observable<BaseBean<PageListData<Article>>> getTreeList(@Path("page") int page, @Query("cid") int cid);
/**
*
*
* @param page
* @return
*/
@GET(UrlConstainer.COLLECT_ARTICLE_LIST)
Observable<BaseBean<PageListData<Article>>> getCollectArticleList(@Path("page") int page);
/**
*
*
* @param id
* @return
*/
@FormUrlEncoded
@POST(UrlConstainer.DELETE_COLLECT_ARTICLE)
Observable<BaseBean<String>> deleteCollectArticle(@Path("id") int id, @Field("originId") int originId);
/**
*
*
* @param page
* @param keyword
* @return
*/
@FormUrlEncoded
@POST(UrlConstainer.SEARCH)
Observable<BaseBean<PageListData<Article>>> search(@Path("page") int page, @Field("k") String keyword);
/**
*
*
* @return
*/
@GET(UrlConstainer.HOT_KEYWORD)
Observable<BaseBean<List<Hotword>>> getHotKeyword();
/**
*
*
* @return
*/
@GET(UrlConstainer.FRIEND)
Observable<BaseBean<List<Friend>>> getFriend();
/**
*
* @return
*/
@GET(UrlConstainer.PROJECT_CATE)
Observable<BaseBean<List<ProjectCate>>> getProjectCate();
/**
*
* @param page
* @param cid
* @return
*/
@GET(UrlConstainer.PROJECT)
Observable<BaseBean<PageListData<Article>>> getProjectList(@Path("page") int page,@Query("cid") int cid);
/**
*
* @return
*/
@GET(UrlConstainer.CHAPTERS)
Observable<BaseBean<List<Chapter>>> getChapters();
/**
*
* @param page
* @param id
* @return
*/
@GET(UrlConstainer.CHAPTER_LIST)
Observable<BaseBean<PageListData<Article>>> getChapterList(@Path("page") int page,@Path("id") int id);
}

@ -0,0 +1,23 @@
package com.kdp.wanandroidclient.application;
import android.content.Context;
import com.kdp.wanandroidclient.common.UrlConstainer;
import com.kdp.wanandroidclient.net.RxRetrofit;
import com.kdp.wanandroidclient.utils.PreUtils;
/**
* author:
* date: 2023/5/31
*/
public class AppConfig {
static void init(Context context){
//初始化网络框架
RxRetrofit.getInstance().initRxRetrofit(context, UrlConstainer.baseUrl);
//初始化缓存
PreUtils.init(context);
}
}

@ -0,0 +1,38 @@
package com.kdp.wanandroidclient.application;
import android.content.Context;
/**
* Context
* author:
* date: 2023/5/31
*/
public class AppContext {
private static Context mContext;
private static AppContext mInstance;
private AppContext(Context mCon) {
mContext = mCon;
}
public static Context getContext() {
return mContext;
}
public static AppContext getInstance() {
return mInstance;
}
static void initialize(Context context) {
if (mInstance == null) {
synchronized (AppContext.class) {
if (mInstance == null) {
mInstance = new AppContext(context.getApplicationContext());
AppConfig.init(mContext);
}
}
}
}
}

@ -0,0 +1,29 @@
package com.kdp.wanandroidclient.application;
import android.app.Application;
import com.kdp.wanandroidclient.BuildConfig;
import com.kdp.wanandroidclient.utils.LogUtils;
import com.squareup.leakcanary.LeakCanary;
/**
* Android
* Created by on 2023/5/31
*/
public class WApp extends Application{
@Override
public void onCreate() {
super.onCreate();
//初始化内存泄漏检测工具
if (LeakCanary.isInAnalyzerProcess(this)){
return;
}
LeakCanary.install(this);
//开启debug模式
LogUtils.isDebug = BuildConfig.LOG_DEBUG;
//初始化App配置
AppContext.initialize(this);
}
}

@ -0,0 +1,305 @@
package com.kdp.wanandroidclient.bean;
import java.io.Serializable;
import java.util.List;
/**
*
* author:
* date: 2023/5/31
*/
public class Article implements Serializable {
/**
* apkLink :
* author :
* chapterId : 411
* chapterName :
* collect : false
* courseId : 13
* desc :
* envelopePic :
* fresh : false
* top: false
* id : 8109
* link : https://mp.weixin.qq.com/s/Qo7R9NGo7sQYnlUeaDeDYw
* niceDate : 2019-03-20
* origin :
* projectLink :
* publishTime : 1553011200000
* superChapterId : 408
* superChapterName :
* tags : [{"name":"公众号","url":"/wxarticle/list/411/1"}]
* title : DNS TCP UDP UDP
* type : 0
* userId : -1
* visible : 1
* zan : 0
*/
private String apkLink;
private String author;
private int chapterId;
private String chapterName;
private boolean collect;
private int courseId;
private String desc;
private String envelopePic;
private boolean fresh;
private boolean top;
private int id;
private String link;
private String niceDate;
private String origin;
private String projectLink;
private long publishTime;
private int superChapterId;
private String superChapterName;
private String title;
private int type;
private int userId;
private int visible;
private int zan;
private List<TagsBean> tags;
private int originId;
public int getOriginId() {
return originId;
}
public void setOriginId(int originId) {
this.originId = originId;
}
public String getApkLink() {
return apkLink;
}
public void setApkLink(String apkLink) {
this.apkLink = apkLink;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getChapterId() {
return chapterId;
}
public void setChapterId(int chapterId) {
this.chapterId = chapterId;
}
public String getChapterName() {
return chapterName;
}
public void setChapterName(String chapterName) {
this.chapterName = chapterName;
}
public boolean isCollect() {
return collect;
}
public void setCollect(boolean collect) {
this.collect = collect;
}
public int getCourseId() {
return courseId;
}
public void setCourseId(int courseId) {
this.courseId = courseId;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getEnvelopePic() {
return envelopePic;
}
public void setEnvelopePic(String envelopePic) {
this.envelopePic = envelopePic;
}
public boolean isFresh() {
return fresh;
}
public void setFresh(boolean fresh) {
this.fresh = fresh;
}
public boolean isTop() {
return top;
}
public void setTop(boolean top) {
this.top = top;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getNiceDate() {
return niceDate;
}
public void setNiceDate(String niceDate) {
this.niceDate = niceDate;
}
public String getOrigin() {
return origin;
}
public void setOrigin(String origin) {
this.origin = origin;
}
public String getProjectLink() {
return projectLink;
}
public void setProjectLink(String projectLink) {
this.projectLink = projectLink;
}
public long getPublishTime() {
return publishTime;
}
public void setPublishTime(long publishTime) {
this.publishTime = publishTime;
}
public int getSuperChapterId() {
return superChapterId;
}
public void setSuperChapterId(int superChapterId) {
this.superChapterId = superChapterId;
}
public String getSuperChapterName() {
return superChapterName;
}
public void setSuperChapterName(String superChapterName) {
this.superChapterName = superChapterName;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public int getVisible() {
return visible;
}
public void setVisible(int visible) {
this.visible = visible;
}
public int getZan() {
return zan;
}
public void setZan(int zan) {
this.zan = zan;
}
public List<TagsBean> getTags() {
return tags;
}
public void setTags(List<TagsBean> tags) {
this.tags = tags;
}
public static class TagsBean implements Serializable{
/**
* name :
* url : /wxarticle/list/411/1
*/
private String name;
private String url;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
@Override
public boolean equals(Object obj) {
if (obj == null) return false;
if (obj instanceof Article) {
return this.id == ((Article) obj).id;
}
return false;
}
}

@ -0,0 +1,95 @@
package com.kdp.wanandroidclient.bean;
/**
* 广
* author:
* date: 2023/5/31
*/
public class Banner {
/**
* desc : App
* id : 10
* imagePath : http://www.wanandroid.com/blogimgs/50c115c2-cf6c-4802-aa7b-a4334de444cd.png
* isVisible : 1
* order : 0
* title : App
* type : 0
* url : http://www.wanandroid.com/blog/show/2
*/
private String desc;
private int id;
private String imagePath;
private int isVisible;
private int order;
private String title;
private int type;
private String url;
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getImagePath() {
return imagePath;
}
public void setImagePath(String imagePath) {
this.imagePath = imagePath;
}
public int getIsVisible() {
return isVisible;
}
public void setIsVisible(int isVisible) {
this.isVisible = isVisible;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}

@ -0,0 +1,36 @@
package com.kdp.wanandroidclient.bean;
/**
*
* Created by on 2023/5/31
*/
public class BaseBean<T> {
/**
*
*/
public int errorCode;
/**
*
*/
public String errorMsg;
/**
*
*/
public T data;
public BaseBean(int errorCode, String errorMsg, T data) {
this.errorCode = errorCode;
this.errorMsg = errorMsg;
this.data = data;
}
@Override
public String toString() {
return "BaseBean{" +
"errorCode=" + errorCode +
", errorMsg='" + errorMsg + '\'' +
", data=" + data +
'}';
}
}

@ -0,0 +1,91 @@
package com.kdp.wanandroidclient.bean;
import java.util.List;
public class Chapter {
/**
* children : []
* courseId : 13
* id : 408
* name : 鸿
* order : 190000
* parentChapterId : 407
* userControlSetTop : false
* visible : 1
*/
private int courseId;
private int id;
private String name;
private int order;
private int parentChapterId;
private boolean userControlSetTop;
private int visible;
private List<?> children;
public int getCourseId() {
return courseId;
}
public void setCourseId(int courseId) {
this.courseId = courseId;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public int getParentChapterId() {
return parentChapterId;
}
public void setParentChapterId(int parentChapterId) {
this.parentChapterId = parentChapterId;
}
public boolean isUserControlSetTop() {
return userControlSetTop;
}
public void setUserControlSetTop(boolean userControlSetTop) {
this.userControlSetTop = userControlSetTop;
}
public int getVisible() {
return visible;
}
public void setVisible(int visible) {
this.visible = visible;
}
public List<?> getChildren() {
return children;
}
public void setChildren(List<?> children) {
this.children = children;
}
}

@ -0,0 +1,74 @@
package com.kdp.wanandroidclient.bean;
/**
*
* author:
* date: 2023/5/31
*/
public class Friend {
/**
* icon :
* id : 17
* link : http://www.wanandroid.com/article/list/0?cid=176
* name :
* order : 1
* visible : 1
*/
private String icon;
private int id;
private String link;
private String name;
private int order;
private int visible;
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public int getVisible() {
return visible;
}
public void setVisible(int visible) {
this.visible = visible;
}
}

@ -0,0 +1,33 @@
package com.kdp.wanandroidclient.bean;
import java.util.List;
public class HomeData {
private BaseBean<List<Banner>> banner;
private BaseBean<List<Article>> homeTop;
private BaseBean<PageListData<Article>> home;
public BaseBean<List<Banner>> getBanner() {
return banner;
}
public void setBanner(BaseBean<List<Banner>> banner) {
this.banner = banner;
}
public BaseBean<List<Article>> getHomeTop() {
return homeTop;
}
public void setHomeTop(BaseBean<List<Article>> homeTop) {
this.homeTop = homeTop;
}
public BaseBean<PageListData<Article>> getHome() {
return home;
}
public void setHome(BaseBean<PageListData<Article>> home) {
this.home = home;
}
}

@ -0,0 +1,65 @@
package com.kdp.wanandroidclient.bean;
/**
*
* author:
* date: 2023/5/31
*/
public class Hotword {
/**
* id : 6
* link :
* name :
* order : 1
* visible : 1
*/
private int id;
private String link;
private String name;
private int order;
private int visible;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public int getVisible() {
return visible;
}
public void setVisible(int visible) {
this.visible = visible;
}
}

@ -0,0 +1,81 @@
package com.kdp.wanandroidclient.bean;
import java.util.ArrayList;
import java.util.List;
/**
*
* author:
* date: 2023/5/31
*/
public class PageListData<T>{
private int curPage;
private int offset;
private boolean over;
private int pageCount;
private int size;
private int total;
private List<T> datas = new ArrayList<>();
public List<T> getDatas() {
return datas;
}
public void setDatas(List<T> datas) {
this.datas = datas;
}
public int getCurPage() {
return curPage;
}
public void setCurPage(int curPage) {
this.curPage = curPage;
}
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
public boolean isOver() {
return over;
}
public void setOver(boolean over) {
this.over = over;
}
public int getPageCount() {
return pageCount;
}
public void setPageCount(int pageCount) {
this.pageCount = pageCount;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
}

@ -0,0 +1,91 @@
package com.kdp.wanandroidclient.bean;
import java.util.List;
public class ProjectCate {
/**
* children : []
* courseId : 13
* id : 294
* name :
* order : 145000
* parentChapterId : 293
* userControlSetTop : false
* visible : 0
*/
private int courseId;
private int id;
private String name;
private int order;
private int parentChapterId;
private boolean userControlSetTop;
private int visible;
private List<?> children;
public int getCourseId() {
return courseId;
}
public void setCourseId(int courseId) {
this.courseId = courseId;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public int getParentChapterId() {
return parentChapterId;
}
public void setParentChapterId(int parentChapterId) {
this.parentChapterId = parentChapterId;
}
public boolean isUserControlSetTop() {
return userControlSetTop;
}
public void setUserControlSetTop(boolean userControlSetTop) {
this.userControlSetTop = userControlSetTop;
}
public int getVisible() {
return visible;
}
public void setVisible(int visible) {
this.visible = visible;
}
public List<?> getChildren() {
return children;
}
public void setChildren(List<?> children) {
this.children = children;
}
}

@ -0,0 +1,164 @@
package com.kdp.wanandroidclient.bean;
import java.io.Serializable;
import java.util.List;
/**
*
* author:
* date: 2023/5/31
*/
public class Tree implements Serializable{
/**
* children : [{"children":[],"courseId":13,"id":60,"name":"Android Studio相关","order":1000,"parentChapterId":150,"visible":1},{"children":[],"courseId":13,"id":169,"name":"gradle","order":1001,"parentChapterId":150,"visible":1},{"children":[],"courseId":13,"id":269,"name":"官方发布","order":1002,"parentChapterId":150,"visible":1}]
* courseId : 13
* id : 150
* name :
* order : 1
* parentChapterId : 0
* visible : 1
*/
private int courseId;
private int id;
private String name;
private int order;
private int parentChapterId;
private int visible;
private List<ChildrenBean> children;
public int getCourseId() {
return courseId;
}
public void setCourseId(int courseId) {
this.courseId = courseId;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public int getParentChapterId() {
return parentChapterId;
}
public void setParentChapterId(int parentChapterId) {
this.parentChapterId = parentChapterId;
}
public int getVisible() {
return visible;
}
public void setVisible(int visible) {
this.visible = visible;
}
public List<ChildrenBean> getChildren() {
return children;
}
public void setChildren(List<ChildrenBean> children) {
this.children = children;
}
public static class ChildrenBean implements Serializable{
/**
* children : []
* courseId : 13
* id : 60
* name : Android Studio
* order : 1000
* parentChapterId : 150
* visible : 1
*/
private int courseId;
private int id;
private String name;
private int order;
private int parentChapterId;
private int visible;
private List<?> children;
public int getCourseId() {
return courseId;
}
public void setCourseId(int courseId) {
this.courseId = courseId;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public int getParentChapterId() {
return parentChapterId;
}
public void setParentChapterId(int parentChapterId) {
this.parentChapterId = parentChapterId;
}
public int getVisible() {
return visible;
}
public void setVisible(int visible) {
this.visible = visible;
}
public List<?> getChildren() {
return children;
}
public void setChildren(List<?> children) {
this.children = children;
}
}
}

@ -0,0 +1,106 @@
package com.kdp.wanandroidclient.bean;
import java.io.Serializable;
import java.util.List;
/**
*
*/
public class User implements Serializable {
private static final long serialVersionUID = 1L;
/**
* chapterTops : []
* collectIds : [3373,7656,7650,7652,7643,7647,7645,7638,7637,7636,7640,7639,7658,7655,7653,7663,7659]
* email :
* icon :
* id : 2633
* password :
* token :
* type : 0
* username : kangdongpu
*/
private String email;
private String icon;
private int id;
private String password;
private String token;
private int type;
private String username;
private List<?> chapterTops;
private List<Integer> collectIds;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public List<?> getChapterTops() {
return chapterTops;
}
public void setChapterTops(List<?> chapterTops) {
this.chapterTops = chapterTops;
}
public List<Integer> getCollectIds() {
return collectIds;
}
public void setCollectIds(List<Integer> collectIds) {
this.collectIds = collectIds;
}
}

@ -0,0 +1,62 @@
package com.kdp.wanandroidclient.common;
public class Const {
//用户相关
public static class USERINFO_KEY {
public static final String USER_INFO = "mUserInfo"; //用户信息
public static final String IS_LOGIN = "mIsLogin"; //登录状态
public static final String AES = "mAES";//用户信息密钥
}
//事件Action
public static class EVENT_ACTION {
public static final String MAIN = "main";
public static final String HOME = "home";
public static final String SYSTEM = "system";
public static final String SYSTEM_LIST = "system_list";
public static final String CHAPTER = "chapter";
public static final String CHAPTER_LIST = "chapter_list";
public static final String PROJECT = "project";
public static final String PROJECT_LIST = "project_list";
public static final String SEARCH = "search";
// public static final String
}
//Intent传值
public static class BUNDLE_KEY {
public static final String ID = "_id";
public static final String TITLE = "title";
public static final String URL = "url";
public static final String OBJ = "obj";
public static final String TYPE = "type";
public static final String CHAPTER_ID = "chapter_id";
public static final String CHAPTER_NAME = "chapter_name";
public static final String COLLECT_TYPE = "collect_type";//1收藏列表文章 2收藏站内文章
}
//图片加载
public static class IMAGE_LOADER {
public static final int HEAD_IMG = 0;
public static final int NOMAL_IMG = 1;
}
//当前页面状态
public static class PAGE_STATE {
public static final int STATE_REFRESH = 0; //刷新
public static final int STATE_LOAD_MORE = 1;//加载更多
}
//列表Type
public static class LIST_TYPE {
public static final int HOME = 0; //首页文章列表
public static final int CHAPTER = 0; //公众号文章列表
public static final int TREE = 1; //知识体系文章列表
public static final int COLLECT = 2; //我的收藏
public static final int SEARCH = 3; //搜索
}
}

@ -0,0 +1,46 @@
package com.kdp.wanandroidclient.common;
import android.support.v7.widget.RecyclerView;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* Holder
* author:
* date: 2023/5/31
*/
public class ListDataHolder extends RecyclerView.ViewHolder {
private SparseArray<View> mHolderView;
private View mItemView;
public ListDataHolder(View itemView) {
super(itemView);
this.mItemView = itemView;
if (mHolderView == null)
mHolderView = new SparseArray<>();
}
public static ListDataHolder createViewHolder(ViewGroup parent, int layoutId) {
View view = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
return new ListDataHolder(view);
}
public static ListDataHolder createViewHolder(View view) {
return new ListDataHolder(view);
}
public <T extends View> T getView(int id) {
View view = mHolderView.get(id);
if (view == null) {
view = mItemView.findViewById(id);
mHolderView.put(id, view);
}
return (T) view;
}
}

@ -0,0 +1,99 @@
package com.kdp.wanandroidclient.common;
/**
* Api
*/
public class UrlConstainer {
public static final String baseUrl = "https://www.wanandroid.com/";
/**
*
*/
public static final String LOGIN = "user/login";
/**
*
*/
public static final String REGISTER = "user/register";
/**
*
*/
public static final String HOME_TOP_LIST = "article/top/json";
/**
*
*/
public static final String HOME_LIST = "article/list/{page}/json";
/**
* 广
*/
public static final String MAIN_BANNER = "banner/json";
/**
*
*/
public static final String COLLECT_ARTICLE = "lg/collect/{id}/json";
/**
*
*/
public static final String UNCOLLECT_ARTICLE = "lg/uncollect_originId/{id}/json";
/**
*
*/
public static final String DELETE_COLLECT_ARTICLE = "lg/uncollect/{id}/json";
/**
*
*/
public static final String TREE = "tree/json";
/**
*
*/
public static final String TREE_LIST = "article/list/{page}/json";
/**
*
*/
public static final String COLLECT_ARTICLE_LIST = "lg/collect/list/{page}/json";
/**
*
*/
public static final String SEARCH = "article/query/{page}/json";
/**
*
*/
public static final String HOT_KEYWORD = "/hotkey/json";
/**
*
*/
public static final String FRIEND = "friend/json";
/**
*
*/
public static final String CHAPTERS = "wxarticle/chapters/json";
/**
*
*/
public static final String CHAPTER_LIST = "wxarticle/list/{id}/{page}/json";
/**
*
*/
public static final String PROJECT_CATE = "project/tree/json";
/**
*
*/
public static final String PROJECT = "project/list/{page}/json";
}

@ -0,0 +1,24 @@
package com.kdp.wanandroidclient.event;
/**
*
* author:
* date: 2023/5/31
*/
public class Event {
public enum Type {
REFRESH_ITEM, REFRESH_LIST, SCROLL_TOP,SCALE
}
public Type type;
public Object object;
public Event(Type type) {
this(type,null);
}
public Event(Type type, Object object) {
this.type = type;
this.object = object;
}
}

@ -0,0 +1,86 @@
package com.kdp.wanandroidclient.event;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.reactivex.observers.DisposableObserver;
import io.reactivex.subjects.PublishSubject;
/**
* 线
* author:
* date: 2023/5/31
*/
public class RxEvent {
private static RxEvent mInstance;
private Map<String, List<PublishSubject>> mSubjectMaps = new HashMap<>();
public static RxEvent getInstance() {
if (mInstance == null) {
synchronized (RxEvent.class) {
if (mInstance == null)
mInstance = new RxEvent();
}
}
return mInstance;
}
/**
*
*
* @param mAction
* @return
*/
public PublishSubject registerEvent(String mAction) {
List<PublishSubject> mSubjectList = mSubjectMaps.get(mAction);
if (mSubjectList == null) {
mSubjectList = new ArrayList<>();
}
mSubjectMaps.put(mAction, mSubjectList);
PublishSubject mSubject = PublishSubject.create();
mSubjectList.add(mSubject);
return mSubject;
}
/**
*
*
* @param mAction
* @param object
*/
public void postEvent(String mAction, Object object) {
List<PublishSubject> mSubjectList = mSubjectMaps.get(mAction);
if (mSubjectList != null && !mSubjectList.isEmpty()) {
for (PublishSubject mSubject : mSubjectList) {
mSubject.onNext(object);
}
}
}
/**
*
*
* @param mAction
* @param mSubject
*/
public void unRegisterEvent(String mAction, PublishSubject mSubject, DisposableObserver mDisposable) {
List<PublishSubject> mSubjectList = mSubjectMaps.get(mAction);
//中断事件
if (mDisposable != null && !mDisposable.isDisposed())
mDisposable.dispose();
if (mSubjectList != null){
mSubjectList.remove(mSubject);
if (mSubjectList.isEmpty()){
mSubjectMaps.remove(mAction);
}
}
}
}

@ -0,0 +1,10 @@
package com.kdp.wanandroidclient.inter;
import com.kdp.wanandroidclient.bean.Article;
public interface OnArticleListItemClickListener extends OnItemClickListener<Article>{
void onDeleteCollectClick(int position,int id,int originId);
void onCollectClick(int position,int id);
}

@ -0,0 +1,6 @@
package com.kdp.wanandroidclient.inter;
public interface OnItemClickListener<T>{
void onItemClick(int position,T bean);
}

@ -0,0 +1,8 @@
package com.kdp.wanandroidclient.inter;
import com.kdp.wanandroidclient.bean.Article;
public interface OnProjectListItemClickListener extends OnItemClickListener<Article> {
void onCollectClick(int position,int id);
}

@ -0,0 +1,11 @@
package com.kdp.wanandroidclient.inter;
import com.kdp.wanandroidclient.bean.Tree;
public interface OnTreeItemClickListener {
void onItemClick(Tree mTree);
}

@ -0,0 +1,11 @@
package com.kdp.wanandroidclient.inter;
/**
*
* author:
* date: 2023/5/31
*/
public interface VerifyAccountCallback {
void onVerifyResult(String msg);
}

@ -0,0 +1,45 @@
package com.kdp.wanandroidclient.manager;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.kdp.wanandroidclient.R;
import com.kdp.wanandroidclient.application.AppContext;
import com.kdp.wanandroidclient.common.Const;
/**
* Glide
* author:
* date: 2023/5/31
*/
public class ImageLoaderManager {
private static RequestOptions nomal_image_options = RequestOptions
.placeholderOf(R.drawable.ic_img_default)
.error(R.drawable.ic_img_default)
.centerCrop();
private static RequestOptions head_options = RequestOptions
.placeholderOf(R.mipmap.ic_launcher_round)
.centerCrop();
public static void displayImage(Object resource,ImageView imageView,int type) {
switch (type) {
case Const.IMAGE_LOADER.HEAD_IMG:
loadImg(resource,head_options,imageView);
break;
case Const.IMAGE_LOADER.NOMAL_IMG:
loadImg(resource,nomal_image_options,imageView);
break;
default:
break;
}
}
private static void loadImg(Object resource, RequestOptions options, ImageView imageView){
Glide.with(AppContext.getContext()).load(resource).apply(options).into(imageView);
}
}

@ -0,0 +1,108 @@
package com.kdp.wanandroidclient.manager;
import android.text.TextUtils;
import android.util.Base64;
import com.kdp.wanandroidclient.bean.User;
import com.kdp.wanandroidclient.common.Const;
import com.kdp.wanandroidclient.utils.AesEncryptionUtils;
import com.kdp.wanandroidclient.utils.PreUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import javax.crypto.spec.SecretKeySpec;
/**
*
* author:
* date: 2023/5/31
*/
public class UserInfoManager {
/**
*
* @return
*/
public static User getUserInfo() {
SecretKeySpec keySpec = getAesKey();
String userInfo = AesEncryptionUtils.decrypt(keySpec, (String) PreUtils.get(Const.USERINFO_KEY.USER_INFO, ""));
if (TextUtils.isEmpty(userInfo)) return null;
try {
return translateStringTOUserInfo(userInfo);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
/**
*
* @param user
*/
public static void saveUserInfo(User user){
try {
String userInfo = translateUserInfoTOString(user);
SecretKeySpec key = AesEncryptionUtils.createKey();
String aesContent = AesEncryptionUtils.encrypt(key, userInfo);
//保存用户信息
PreUtils.put(Const.USERINFO_KEY.USER_INFO, aesContent);
//保存密钥
saveAesKey(key);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void saveAesKey(SecretKeySpec keySpec){
PreUtils.put(Const.USERINFO_KEY.AES, Base64.encodeToString(keySpec.getEncoded(),Base64.DEFAULT));
}
private static SecretKeySpec getAesKey(){
String keyStr = (String) PreUtils.get(Const.USERINFO_KEY.AES, "");
return AesEncryptionUtils.getSecretKey(Base64.decode(keyStr, Base64.DEFAULT));
}
public static boolean isLogin() {
return (boolean) PreUtils.get(Const.USERINFO_KEY.IS_LOGIN, false);
}
public static void saveIsLogin(boolean isLogin){
PreUtils.put(Const.USERINFO_KEY.IS_LOGIN,isLogin);
}
/**
* User String
* @param user
* @return
* @throws IOException
*/
private static String translateUserInfoTOString(User user) throws IOException{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(user);
return Base64.encodeToString(bos.toByteArray(), Base64.DEFAULT);
}
/**
* String User
* @param userStr
* @return
* @throws IOException
* @throws ClassNotFoundException
*/
private static User translateStringTOUserInfo(String userStr) throws IOException, ClassNotFoundException {
if (userStr == null) return null;
byte[] base64Bytes = Base64.decode(userStr,Base64.DEFAULT);
ByteArrayInputStream bis = new ByteArrayInputStream(base64Bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
return (User) ois.readObject();
}
}

@ -0,0 +1,50 @@
package com.kdp.wanandroidclient.net;
/**
*
*/
public interface NetConfig {
//请求成功
int REQUEST_SUCCESS = 0;
//请求失败
int REQUEST_ERROR = -1;
/**
* ,
*/
int CONNECT_ERROR = 1001;
/**
*
*/
int UNKNOWN_HOST = 1002;
/**
*
*/
int CONNECT_TIMEOUT = 1003;
/**
*
*/
int REQUEST_TIMEOUT = 1004;
/**
*
*/
int PARSE_ERROR = 1005;
/**
*
*/
int UNKNOWN_ERROR = 1006;
/**
*
*/
int ILLEGAL_PARAMS = 1007;
}

@ -0,0 +1,85 @@
package com.kdp.wanandroidclient.net;
import android.content.Context;
import com.kdp.wanandroidclient.R;
import com.kdp.wanandroidclient.utils.NetworkUtils;
import com.kdp.wanandroidclient.utils.ToastUtils;
import org.json.JSONException;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.text.ParseException;
public class NetExceptionHandle {
/**
*
* @param context
* @param t
*/
public static void dealException(Context context, Throwable t) {
if (!NetworkUtils.isAvailable(context)){
onException(NetConfig.CONNECT_ERROR, context);
return;
}
if (t instanceof ConnectException) {
//连接错误,网络异常
onException(NetConfig.CONNECT_ERROR, context);
}else if (t instanceof UnknownHostException){
//无法连接到主机
onException(NetConfig.UNKNOWN_HOST,context);
}
else if (t instanceof InterruptedException) {
//连接超时
onException(NetConfig.CONNECT_TIMEOUT, context);
} else if (t instanceof JSONException || t instanceof ParseException) {
//解析错误
onException(NetConfig.PARSE_ERROR, context);
} else if (t instanceof SocketTimeoutException) {
//请求超时
onException(NetConfig.REQUEST_TIMEOUT, context);
} else if (t instanceof UnknownError) {
//未知错误
onException(NetConfig.UNKNOWN_ERROR, context);
} else if (t instanceof IllegalArgumentException){
//未知错误
onException(NetConfig.ILLEGAL_PARAMS, context);
}
}
/**
*
* @param errorCode
* @param context
*/
private static void onException(int errorCode, Context context) {
switch (errorCode) {
case NetConfig.CONNECT_ERROR:
ToastUtils.showToast(context, R.string.connect_error);
break;
case NetConfig.UNKNOWN_HOST:
ToastUtils.showToast(context,R.string.unknown_host);
break;
case NetConfig.CONNECT_TIMEOUT:
ToastUtils.showToast(context, R.string.connect_timeout);
break;
case NetConfig.PARSE_ERROR:
ToastUtils.showToast(context, R.string.parse_error);
break;
case NetConfig.REQUEST_TIMEOUT:
ToastUtils.showToast(context, R.string.request_timeout);
break;
case NetConfig.UNKNOWN_ERROR:
ToastUtils.showToast(context, R.string.unknown_error);
break;
case NetConfig.ILLEGAL_PARAMS:
ToastUtils.showToast(context,R.string.illegal_params);
break;
}
}
}

@ -0,0 +1,73 @@
package com.kdp.wanandroidclient.net;
import android.content.Context;
import com.kdp.wanandroidclient.api.ApiServer;
import com.kdp.wanandroidclient.net.interceptor.CacheInterceptor;
import com.kdp.wanandroidclient.net.interceptor.LoadCookieInterceptor;
import com.kdp.wanandroidclient.net.interceptor.RequestInterceptor;
import com.kdp.wanandroidclient.net.interceptor.SaveCookieInterceptor;
import java.util.concurrent.TimeUnit;
import okhttp3.Cache;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
/**
*
*/
public class RxRetrofit {
private Retrofit retrofit;
private static ApiServer apiServer;
private static final class Holder {
private static final RxRetrofit INSTANCE = new RxRetrofit();
}
public void initRxRetrofit(final Context context, String baseUrl) {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
//链接超时
.connectTimeout(10, TimeUnit.SECONDS)
//读取超时
.readTimeout(10, TimeUnit.SECONDS)
//配置缓存,okhttp会自动缓存数据到本地
.cache(new Cache(context.getExternalFilesDir("http_cache"), 10 << 20))
//添加Cookie拦截器
.addInterceptor(new SaveCookieInterceptor())
.addInterceptor(new LoadCookieInterceptor())
//添加缓存拦截器
.addInterceptor(new RequestInterceptor())
.addNetworkInterceptor(new CacheInterceptor())
.build();
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
apiServer = retrofit.create(ApiServer.class);
}
public static RxRetrofit getInstance() {
return Holder.INSTANCE;
}
/**
* ApiServer
*
* @return apiServer
*/
public static ApiServer Api() {
if (apiServer == null)
throw new IllegalStateException("You must invoke init method first in Application");
return apiServer;
}
}

@ -0,0 +1,33 @@
package com.kdp.wanandroidclient.net;
import com.kdp.wanandroidclient.bean.BaseBean;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
/**
* author:
* date: 2023/5/31
*/
public class RxSchedulers{
/**
* io线
* 线
*/
public static <T>ObservableTransformer<BaseBean<T>,BaseBean<T>> io_main() {
return new ObservableTransformer<BaseBean<T>, BaseBean<T>>() {
@Override
public ObservableSource<BaseBean<T>> apply(Observable<BaseBean<T>> upstream) {
return upstream.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}
};
}
}

@ -0,0 +1,52 @@
package com.kdp.wanandroidclient.net.callback;
import com.kdp.wanandroidclient.application.AppContext;
import com.kdp.wanandroidclient.bean.BaseBean;
import com.kdp.wanandroidclient.net.NetExceptionHandle;
import com.kdp.wanandroidclient.ui.core.presenter.BasePresenter;
import com.kdp.wanandroidclient.ui.core.view.IView;
import io.reactivex.observers.DisposableObserver;
/**
* RxRetrofit
*/
public abstract class RxBaseObserver<T> extends DisposableObserver<BaseBean<T>> {
protected IView view;
RxBaseObserver(BasePresenter mPresenter) {
this.view = mPresenter.getView();
}
@Override
protected void onStart() {
super.onStart();
//显示loading
showLoading();
}
public void showLoading() {
view.showLoading("");
}
@Override
public void onError(Throwable e) {
//隐藏loading
hideLoading();
//处理异常
NetExceptionHandle.dealException(AppContext.getContext(),e);
}
@Override
public void onComplete() {
hideLoading();
}
private void hideLoading() {
if (null != view)
this.view.hideLoading();
}
}

@ -0,0 +1,28 @@
package com.kdp.wanandroidclient.net.callback;
import com.kdp.wanandroidclient.bean.BaseBean;
import com.kdp.wanandroidclient.net.NetConfig;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Consumer;
/**
* author:
* date: 2023/5/31
*/
public abstract class RxConsumer<T> implements Consumer<BaseBean<T>> {
@Override
public void accept(@NonNull BaseBean<T> tBaseBean) throws Exception {
if (tBaseBean.errorCode == NetConfig.REQUEST_SUCCESS){
onSuccess(tBaseBean.data);
}else {
onFail(tBaseBean.errorMsg);
}
}
protected abstract void onFail(String errorMsg);
protected abstract void onSuccess(T data);
}

@ -0,0 +1,27 @@
package com.kdp.wanandroidclient.net.callback;
import com.kdp.wanandroidclient.bean.BaseBean;
import com.kdp.wanandroidclient.net.NetConfig;
import io.reactivex.Observable;
import io.reactivex.functions.Function;
/**
*
* author:
* date: 2023/5/31
*/
public abstract class RxFunction<T, R> implements Function<BaseBean<T>, Observable<BaseBean<R>>> {
@Override
public Observable<BaseBean<R>> apply(BaseBean<T> tBaseBean) throws Exception {
if (tBaseBean.errorCode == NetConfig.REQUEST_SUCCESS){
return doOnNextRequest();
}
return null;
}
protected abstract Observable<BaseBean<R>> doOnNextRequest();
}

@ -0,0 +1,32 @@
package com.kdp.wanandroidclient.net.callback;
import com.kdp.wanandroidclient.bean.BaseBean;
import com.kdp.wanandroidclient.net.NetConfig;
import com.kdp.wanandroidclient.ui.core.presenter.BasePresenter;
/**
* RxRetrofit
*/
public abstract class RxObserver<T> extends RxBaseObserver<T> {
public RxObserver(BasePresenter mPresenter) {
super(mPresenter);
}
@Override
public void onNext(BaseBean<T> mBaseBean) {
//请求成功
if (mBaseBean.errorCode == NetConfig.REQUEST_SUCCESS) {
onSuccess(mBaseBean.data);
} else {
//失败
onFail(mBaseBean.errorCode, mBaseBean.errorMsg);
}
}
protected abstract void onSuccess(T data);
protected abstract void onFail(int errorCode, String errorMsg);
}

@ -0,0 +1,55 @@
package com.kdp.wanandroidclient.net.callback;
import com.kdp.wanandroidclient.bean.BaseBean;
import com.kdp.wanandroidclient.bean.PageListData;
import com.kdp.wanandroidclient.net.NetConfig;
import com.kdp.wanandroidclient.ui.core.presenter.BasePresenter;
import com.kdp.wanandroidclient.ui.core.view.IPageLoadDataView;
import java.util.List;
/**
*
*
* author:
* date: 2023/5/31
*/
public abstract class RxPageListObserver<T> extends RxBaseObserver<PageListData<T>> {
private IPageLoadDataView mListDataView;
public RxPageListObserver(BasePresenter mPresenter) {
super(mPresenter);
this.mListDataView = (IPageLoadDataView) mPresenter.getView();
}
@Override
public void onNext(BaseBean<PageListData<T>> baseBean) {
if (baseBean.errorCode == NetConfig.REQUEST_SUCCESS) {
PageListData<T> mListData = baseBean.data;
if (mListDataView.getPage() == mListDataView.getFirstPage()) {
mListDataView.clearListData();
}
if (mListData.isOver()) {
mListDataView.showNoMore();
} else {
mListDataView.autoLoadMore();
}
onSuccess(mListData.getDatas());
} else {
onFail(baseBean.errorCode, baseBean.errorMsg);
}
}
@Override
public void onError(Throwable e) {
super.onError(e);
mListDataView.showError();
}
public abstract void onSuccess(List<T> mData);
public abstract void onFail(int errorCode, String errorMsg);
}

@ -0,0 +1,45 @@
package com.kdp.wanandroidclient.net.callback;
import com.kdp.wanandroidclient.application.AppContext;
import com.kdp.wanandroidclient.net.NetExceptionHandle;
import com.kdp.wanandroidclient.ui.core.presenter.BasePresenter;
import com.kdp.wanandroidclient.ui.core.view.IView;
import io.reactivex.observers.DisposableObserver;
public abstract class RxZipObserver<T> extends DisposableObserver<T> {
protected IView view;
protected RxZipObserver(BasePresenter mPresenter) {
this.view = mPresenter.getView();
}
@Override
protected void onStart() {
super.onStart();
//显示loading
showLoading();
}
@Override
public void onError(Throwable e) {
//隐藏loading
hideLoading();
//处理异常
NetExceptionHandle.dealException(AppContext.getContext(),e);
}
@Override
public void onComplete() {
hideLoading();
}
public void showLoading() {
view.showLoading("");
}
private void hideLoading() {
if (null != view)
this.view.hideLoading();
}
}

@ -0,0 +1,60 @@
package com.kdp.wanandroidclient.net.interceptor;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import okhttp3.CacheControl;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* ,60
* author:
* date: 2023/5/31
*/
public class CacheInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//FORCE_NETWORK 里设置了 no-cache
//no-cache,强制客户端直接向服务器发送请求,也就是说每次请求都必须向服务器发送。
//如果缓存被删除,则返回请求的数据并重新缓存数据,否则如下:
// 服务器接收到请求然后判断资源是否变更是则返回新内容刷新缓存否则返回304(Not Modified)。
// 若资源未变更,且缓存时间未过期则返回缓存的数据,若缓存时间已过期,则会请求服务器获取数据。
// 当缓存过期后,如果资源一直未变更(返回304)okhttp客户端会请求网络返回数据且刷新本地缓存。
//若不设置no-cache,那么只要缓存时间过期,就会请求网络获取数据并刷新缓存,
//若缓存时间未过期,不管资源有没有变更,则一直从缓存中取数据。
//注意:拦截器只有配置到addInterceptor中时onlyIfCached、maxStale才会生效且如果no-cache和maxStale同时存在maxStale也会失效。
//若no-cache、onlyIfCached同时存在no-cache会失效
// CacheControl requestCacheControl = new CacheControl.Builder()
// .noCache()
// .onlyIfCached()
// .maxStale(60*60,TimeUnit.SECONDS)
// .build();
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_NETWORK)
// .cacheControl(requestCacheControl)
.build();
Response response = chain.proceed(request);
//max-age:如果仅在请求头中设置它,不起作用必须要在响应头中设置如果同时设置了它且请求头中的max-age小于响应头中的max-age
//则请求头的max-age生效。因此可以这样设计:用响应头的max-age控制缓存的时间用请求头的max-age控制缓存刷新的时间
//max-age会存储到缓存文件中,告知缓存多长时间,在没有超过缓存时间的情况下,请求会返回缓存内的数据,
//在超出max-age的情况下向服务端发起新的请求请求失败的情况下返回缓存数据否则向服务端重新发起请求。
//注意:拦截器只有配置到addNetInterceptor中response中的max-age才会生效
CacheControl responseCacheControl = new CacheControl.Builder()
.maxAge(60, TimeUnit.SECONDS)
.build();
response = response.newBuilder()
.removeHeader("Pragma")//若服务器不支持缓存{pragma : [no-cache]}则需移除Pragma
.header("Cache-Control", responseCacheControl.toString())
.build();
return response;
}
}

@ -0,0 +1,29 @@
package com.kdp.wanandroidclient.net.interceptor;
import android.text.TextUtils;
import com.kdp.wanandroidclient.utils.PreUtils;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* Cookie
* author:
* date: 2023/5/31
*/
public class LoadCookieInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request.Builder builder = chain.request().newBuilder();
String mCookieStr = (String) PreUtils.get(chain.request().url().host(), "");
if (!TextUtils.isEmpty(mCookieStr)) {
builder.addHeader("Cookie", mCookieStr.substring(0, mCookieStr.length() - 1));//长度减1为了去除最后的逗号
}
return chain.proceed(builder.build());
}
}

@ -0,0 +1,41 @@
package com.kdp.wanandroidclient.net.interceptor;
import com.kdp.wanandroidclient.application.AppContext;
import com.kdp.wanandroidclient.utils.NetworkUtils;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import okhttp3.CacheControl;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* (Integer.MAX_VALUE)
* author:
* date: 2023/5/31
*/
public class RequestInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
//无网络时从缓存中获取
if (!NetworkUtils.isAvailable(AppContext.getContext())) {
//max-stale:指示客户机可以接收超出max-age时间的响应消息,若respond中没有设置max-age,相当于max-age=0
//请求的缓存过期时间: max-stale+max-age(response中)
//在请求设置中有效,在响应设置中无效
// CacheControl cacheControl = new CacheControl.Builder()
// .onlyIfCached()
// .maxStale(60*60,TimeUnit.SECONDS)
// .build();
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
// .cacheControl(cacheControl)
.build();
}
return chain.proceed(request);
}
}

@ -0,0 +1,40 @@
package com.kdp.wanandroidclient.net.interceptor;
import android.util.Log;
import com.kdp.wanandroidclient.common.UrlConstainer;
import com.kdp.wanandroidclient.utils.PreUtils;
import java.io.IOException;
import java.util.List;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* Cookie
* author:
* date: 2023/5/31
*/
public class SaveCookieInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
System.out.println("ddddddddddd"+request);
Response response = chain.proceed(request);
List<String> mCookieList = response.headers("Set-Cookie");
//保存Cookie
if (!mCookieList.isEmpty() && request.url().toString().endsWith(UrlConstainer.LOGIN)) {
StringBuilder sb = new StringBuilder();
for (String cookie : mCookieList) {
//注意Cookie请求头字段中的每个Cookie之间用逗号或分号分隔
sb.append(cookie).append(",");
}
PreUtils.put(response.request().url().host(), sb.toString());
Log.e(SaveCookieInterceptor.class.getSimpleName(), "intercept: url : " + request.url());
}
return response;
}
}

@ -0,0 +1,135 @@
package com.kdp.wanandroidclient.ui;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.KeyEvent;
import android.view.View;
import com.kdp.wanandroidclient.R;
import com.kdp.wanandroidclient.bean.User;
import com.kdp.wanandroidclient.manager.UserInfoManager;
import com.kdp.wanandroidclient.ui.base.BasePresenterActivity;
import com.kdp.wanandroidclient.ui.logon.LogonContract;
import com.kdp.wanandroidclient.ui.logon.LogonPresenter;
import com.kdp.wanandroidclient.ui.main.MainActivity;
import java.lang.ref.WeakReference;
/**
*
*/
public class LauncherActivity extends BasePresenterActivity<LogonPresenter> implements LogonContract.ILoginRegisterView {
private User user;
private Handler mHandler;
private DelayRunnable mRunnable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
hideBottomUIMenu();
//倒计时
startCountdown();
}
private void startCountdown() {
mHandler = new Handler();
mRunnable = new DelayRunnable(this);
mHandler.postDelayed(mRunnable, 2000);
}
/**
*
*/
protected void hideBottomUIMenu() {
//隐藏虚拟按键,并且全屏
if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api
View v = this.getWindow().getDecorView();
v.setSystemUiVisibility(View.GONE);
} else if (Build.VERSION.SDK_INT >= 19) {
//for new api versions.
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
}
}
//自动登录
private void autoLogin() {
if (UserInfoManager.isLogin()) {
//自动登录
user = UserInfoManager.getUserInfo();
if (user != null)
mPresenter.login();
}
startToActivity();
}
private static class DelayRunnable implements Runnable {
private WeakReference<LauncherActivity> mWeakReference;
DelayRunnable(LauncherActivity instance) {
mWeakReference = new WeakReference<>(instance);
}
@Override
public void run() {
LauncherActivity instance = mWeakReference.get();
if (instance == null) return;
instance.autoLogin();
}
}
//进入首页
private void startToActivity() {
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
}
@Override
protected int getLayoutId() {
return R.layout.activity_splash;
}
@Override
protected LogonPresenter createPresenter() {
return new LogonPresenter();
}
@Override
public String getUserName() {
return user.getUsername();
}
@Override
public String getPassWord() {
return user.getPassword();
}
@Override
public void showResult(String msg) {
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void onDestroy() {
mHandler.removeCallbacks(mRunnable);
super.onDestroy();
}
}

@ -0,0 +1,156 @@
package com.kdp.wanandroidclient.ui.adapter;
import android.graphics.Color;
import android.os.Build;
import android.support.v4.content.ContextCompat;
import android.text.Html;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.kdp.wanandroidclient.R;
import com.kdp.wanandroidclient.application.AppContext;
import com.kdp.wanandroidclient.bean.Article;
import com.kdp.wanandroidclient.common.Const;
import com.kdp.wanandroidclient.common.ListDataHolder;
import com.kdp.wanandroidclient.inter.OnArticleListItemClickListener;
import com.kdp.wanandroidclient.utils.DateUtils;
/**
*
* author:
* date: 2023/5/31
*/
public class ArticleListAdapter extends BaseListAdapter<Article> {
private int Type;
private OnArticleListItemClickListener listener;
public ArticleListAdapter(OnArticleListItemClickListener listener, int type) {
this.listener = listener;
this.Type = type;
}
@Override
protected int getLayoutId(int viewType) {
return R.layout.item_home_article_list;
}
@Override
public void bindDatas(ListDataHolder holder, final Article bean, int itemType, final int position) {
TextView tv_tag = holder.getView(R.id.tv_tag);
TextView tv_author = holder.getView(R.id.tv_author);
TextView tv_title = holder.getView(R.id.tv_title);
TextView tv_time = holder.getView(R.id.tv_time);
TextView tv_type = holder.getView(R.id.tv_type);
ImageView img_collect = holder.getView(R.id.img_collect);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
tv_title.setText(Html.fromHtml(bean.getTitle(), Html.FROM_HTML_MODE_LEGACY));
} else {
tv_title.setText(Html.fromHtml(bean.getTitle()));
}
tv_author.setText(bean.getAuthor());
tv_time.setText(DateUtils.parseTime(bean.getPublishTime()));
if (Type == Const.LIST_TYPE.HOME || Type == Const.LIST_TYPE.SEARCH){
coverToArticleList(tv_type,tv_tag,img_collect,position,bean);
}else if (Type == Const.LIST_TYPE.TREE){
coverToTreeList(tv_type,tv_tag,img_collect,position,bean);
}else if (Type == Const.LIST_TYPE.COLLECT){
coverToCollectList(tv_type,tv_tag,img_collect,position,bean);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
listener.onItemClick(position,bean);
}
}
});
}
/**
*
* @param tv_type
* @param tv_tag
* @param img_collect
* @param position
* @param bean
*/
private void coverToArticleList(TextView tv_type,TextView tv_tag, ImageView img_collect, final int position, final Article bean) {
tv_type.setText(String.format("%1$s / %2$s",bean.getSuperChapterName(), bean.getChapterName()));
tv_tag.setVisibility(View.VISIBLE);
if (bean.isTop()){
tv_tag.setActivated(true);
tv_tag.setText("置顶");
tv_tag.setTextColor(Color.RED);
}else if (bean.isFresh()){
tv_tag.setText("新");
tv_tag.setTextColor(Color.RED);
tv_tag.setActivated(true);
}else if (bean.getTags().size() > 0){
tv_tag.setActivated(false);
tv_tag.setText(bean.getTags().get(0).getName());
tv_tag.setTextColor(ContextCompat.getColor(AppContext.getContext(),R.color._009a61));
}else {
tv_tag.setVisibility(View.GONE);
}
img_collect.setImageResource(bean.isCollect() ? R.drawable.ic_favorite_light_24dp : R.drawable.ic_favorite_gray_24dp);
img_collect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
listener.onCollectClick(position, bean.getId());
}
}
});
}
/**
*
* @param tv_tag
*/
private void coverToTreeList(TextView tv_type, TextView tv_tag, ImageView img_collect, final int position, final Article bean) {
tv_type.setText(String.format("%1$s / %2$s",bean.getSuperChapterName(), bean.getChapterName()));
tv_tag.setVisibility(View.GONE);
img_collect.setImageResource(bean.isCollect() ? R.drawable.ic_favorite_light_24dp : R.drawable.ic_favorite_gray_24dp);
img_collect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
listener.onCollectClick(position, bean.getId());
}
}
});
}
/**
*
* @param tv_type
* @param img_collect
* @param position
* @param bean
*/
private void coverToCollectList(TextView tv_type,TextView tv_tag,ImageView img_collect, final int position, final Article bean) {
tv_type.setText(bean.getChapterName());
tv_tag.setVisibility(View.GONE);
img_collect.setImageResource(R.drawable.ic_favorite_light_24dp);
img_collect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
listener.onDeleteCollectClick(position, bean.getId(), bean.getOriginId());
}
}
});
}
}

@ -0,0 +1,125 @@
package com.kdp.wanandroidclient.ui.adapter;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.view.PagerAdapter;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.kdp.wanandroidclient.R;
import com.kdp.wanandroidclient.application.AppContext;
import com.kdp.wanandroidclient.bean.Article;
import com.kdp.wanandroidclient.bean.Banner;
import com.kdp.wanandroidclient.common.Const;
import com.kdp.wanandroidclient.manager.ImageLoaderManager;
import com.kdp.wanandroidclient.ui.web.WebViewActivity;
import java.util.List;
/**
* author:
* date: 2023/5/31
*/
public class BannerAdapter extends PagerAdapter {
private SparseArray<View> mViews;
private List<Banner> mBannerDatas;
public BannerAdapter(List<Banner> mBannerDatas) {
this.mBannerDatas = mBannerDatas;
mViews = new SparseArray<>();
}
public void notifyDatas(List<Banner> mBannerDatas) {
this.mBannerDatas = mBannerDatas;
notifyDataSetChanged();
}
@Override
public int getCount() {
if (mBannerDatas == null) return 0;
return mBannerDatas.size() <= 1 ? mBannerDatas.size() : Integer.MAX_VALUE;
}
@NonNull
@Override
public Object instantiateItem(@NonNull final ViewGroup container, int position) {
View view = mViews.get(position);
if (view == null) {
position %= mBannerDatas.size();
final Banner bean = mBannerDatas.get(position);
view = LayoutInflater.from(AppContext.getContext()).inflate(R.layout.item_banner, container, false);
ImageView imageView = view.findViewById(R.id.img);
TextView titleView = view.findViewById(R.id.title);
ImageLoaderManager.displayImage(bean.getImagePath(), imageView, Const.IMAGE_LOADER.NOMAL_IMG);
titleView.setText(bean.getTitle());
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(container.getContext(), WebViewActivity.class);
Article mArticle = new Article();
mArticle.setTitle(bean.getTitle());
mArticle.setLink(bean.getUrl());
Bundle bundle = new Bundle();
bundle.putSerializable(Const.BUNDLE_KEY.OBJ, mArticle);
intent.putExtras(bundle);
container.getContext().startActivity(intent);
}
});
mViews.put(position, view);
}
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public int getItemPosition(Object object) {
mViews.clear();
return POSITION_NONE;
}
// @Override
// public void startUpdate(ViewGroup container) {
// super.startUpdate(container);
//ViewPager显示的页面数据有所改变的回调(还未处理)
// }
// @Override
// public void finishUpdate(ViewGroup container) {
// super.finishUpdate(container);
//页面数据改变的处理结束后的回调
//此处的处理其实就是 回调instantiateItem和destroyItem方法
//当数据发生变化
// int position = viewPager.getCurrentItem();
// if (position == 0){
// viewPager.setCurrentItem(8,false);
// }else if (position == 9){
// viewPager.setCurrentItem(1,false);
// }
// }
}

@ -0,0 +1,62 @@
package com.kdp.wanandroidclient.ui.adapter;
import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup;
import com.kdp.wanandroidclient.common.ListDataHolder;
import com.kdp.wanandroidclient.widget.LMRecyclerView;
import java.util.List;
/**
*
* author:
* date: 2023/5/31
*/
public abstract class BaseListAdapter<T> extends RecyclerView.Adapter<ListDataHolder> {
private List<T> mList;
//刷新所有数据
public void notifyAllDatas(List<T> mList, LMRecyclerView recyclerView) {
this.mList = mList;
recyclerView.notifyDataSetChanged();
}
//刷新单条数据
public void notifyItemDataChanged(int position, LMRecyclerView recyclerView) {
recyclerView.notifyItemChanged(position);
}
//移除单条数据
public void notifyItemDataRemove(int position, LMRecyclerView recyclerView) {
recyclerView.notifyItemRemoved(position);
}
@Override
public ListDataHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return ListDataHolder.createViewHolder(parent, getLayoutId(viewType));
}
protected abstract int getLayoutId(int viewType);
@Override
public void onBindViewHolder(ListDataHolder holder, int position) {
//初始化View
T bean = mList.get(position);
//绑定数据
bindDatas(holder, bean, holder.getItemViewType(), position);
}
@Override
public int getItemCount() {
return mList != null ? mList.size() : 0;
}
public abstract void bindDatas(ListDataHolder holder, T bean, int itemType, int position);
}

@ -0,0 +1,39 @@
package com.kdp.wanandroidclient.ui.adapter;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import com.kdp.wanandroidclient.bean.Chapter;
import com.kdp.wanandroidclient.ui.chapter.ChapterListFragment;
import java.util.List;
/***
* @author kdp
* @date 2023
* @description
*/
public class ChaptersFragPagerAdapter extends FragmentPagerAdapter {
private List<Chapter> list;
public ChaptersFragPagerAdapter(FragmentManager fm,List<Chapter> list) {
super(fm);
this.list = list;
}
@Override
public Fragment getItem(int positions) {
return ChapterListFragment.instantiate(list.get(positions).getId());
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return list.get(position).getName();
}
@Override
public int getCount() {
return list!=null?list.size():0;
}
}

@ -0,0 +1,41 @@
package com.kdp.wanandroidclient.ui.adapter;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import com.kdp.wanandroidclient.bean.ProjectCate;
import com.kdp.wanandroidclient.ui.project.ProjectListFragment;
import java.util.List;
/***
* @author kdp
* @date 2023
* @description
*/
public class ProjectFragPagerAdapter extends FragmentPagerAdapter {
private List<ProjectCate> projectCateList;
public ProjectFragPagerAdapter(FragmentManager fm,List<ProjectCate> projectCateList) {
super(fm);
this.projectCateList = projectCateList;
}
@Override
public Fragment getItem(int position) {
return ProjectListFragment.instantiate(projectCateList.get(position).getId());
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return projectCateList.get(position).getName();
}
@Override
public int getCount() {
return projectCateList == null ? 0:projectCateList.size();
}
}

@ -0,0 +1,58 @@
package com.kdp.wanandroidclient.ui.adapter;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.kdp.wanandroidclient.R;
import com.kdp.wanandroidclient.bean.Article;
import com.kdp.wanandroidclient.common.Const;
import com.kdp.wanandroidclient.common.ListDataHolder;
import com.kdp.wanandroidclient.inter.OnProjectListItemClickListener;
import com.kdp.wanandroidclient.manager.ImageLoaderManager;
import com.kdp.wanandroidclient.utils.DateUtils;
public class ProjectListAdapter extends BaseListAdapter<Article> {
private OnProjectListItemClickListener listener;
public ProjectListAdapter(OnProjectListItemClickListener listener) {
this.listener = listener;
}
@Override
protected int getLayoutId(int viewType) {
return R.layout.item_project_list;
}
@Override
public void bindDatas(ListDataHolder holder, final Article bean, int itemType, final int position) {
ImageView iv_img = holder.getView(R.id.iv_img);
ImageView img_collect = holder.getView(R.id.img_collect);
TextView tv_title = holder.getView(R.id.tv_title);
TextView tv_desc = holder.getView(R.id.tv_desc);
TextView tv_time = holder.getView(R.id.tv_time);
TextView tv_name = holder.getView(R.id.tv_name);
ImageLoaderManager.displayImage(bean.getEnvelopePic(),iv_img, Const.IMAGE_LOADER.NOMAL_IMG);
tv_title.setText(bean.getTitle());
tv_desc.setText(bean.getDesc());
tv_time.setText(DateUtils.parseTime(bean.getPublishTime()));
tv_name.setText(bean.getAuthor());
img_collect.setImageResource(bean.isCollect() ? R.drawable.ic_favorite_light_24dp : R.drawable.ic_favorite_gray_24dp);
img_collect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null)
listener.onCollectClick(position,bean.getId());
}
});
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener!=null)
listener.onItemClick(position,bean);
}
});
}
}

@ -0,0 +1,49 @@
package com.kdp.wanandroidclient.ui.adapter;
import android.view.View;
import android.widget.TextView;
import com.kdp.wanandroidclient.common.ListDataHolder;
import com.kdp.wanandroidclient.R;
import com.kdp.wanandroidclient.bean.Tree;
import com.kdp.wanandroidclient.inter.OnItemClickListener;
/**
*
* author:
* date: 2023/5/31
*/
public class TreeAdapter extends BaseListAdapter<Tree> {
private OnItemClickListener<Tree> listener;
public TreeAdapter(OnItemClickListener<Tree> listener) {
this.listener = listener;
}
@Override
protected int getLayoutId(int viewType) {
return R.layout.item_tree;
}
@Override
public void bindDatas(ListDataHolder holder, final Tree bean, int itemType, final int position) {
TextView tv_title = holder.getView(R.id.tv_title);
TextView tv_content = holder.getView(R.id.tv_content);
tv_title.setText(bean.getName());
tv_content.setText("");
for (Tree.ChildrenBean child : bean.getChildren()) {
tv_content.append(child.getName() + " ");
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener!=null)
listener.onItemClick(position,bean);
}
});
}
}

@ -0,0 +1,40 @@
package com.kdp.wanandroidclient.ui.adapter;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import com.kdp.wanandroidclient.bean.Tree;
import com.kdp.wanandroidclient.ui.tree.TreeListFragment;
import java.util.List;
/**
* fragmetn
* author:
* date: 2023/5/31
*/
public class TreeFragPagerAdapter extends FragmentPagerAdapter {
private List<Tree.ChildrenBean> mTreeDatas;
public TreeFragPagerAdapter(FragmentManager fm, List<Tree.ChildrenBean> mTreeDatas) {
super(fm);
this.mTreeDatas = mTreeDatas;
}
@Override
public Fragment getItem(int position) {
return TreeListFragment.instantiate(mTreeDatas.get(position).getId());
}
@Override
public int getCount() {
return mTreeDatas != null ? mTreeDatas.size() : 0;
}
@Override
public CharSequence getPageTitle(int position) {
return mTreeDatas.get(position).getName();
}
}

@ -0,0 +1,285 @@
package com.kdp.wanandroidclient.ui.base;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import com.kdp.wanandroidclient.R;
import com.kdp.wanandroidclient.common.Const;
import com.kdp.wanandroidclient.event.Event;
import com.kdp.wanandroidclient.event.RxEvent;
import com.kdp.wanandroidclient.ui.adapter.BaseListAdapter;
import com.kdp.wanandroidclient.ui.core.presenter.BasePresenter;
import com.kdp.wanandroidclient.ui.core.view.IPageLoadDataView;
import com.kdp.wanandroidclient.utils.ViewAnimatorHelper;
import com.kdp.wanandroidclient.widget.StatusLayout;
import com.kdp.wanandroidclient.widget.LMRecyclerView;
import com.kdp.wanandroidclient.widget.NoAlphaItemAnimator;
import java.util.ArrayList;
import java.util.List;
/**
* Activity
*/
public abstract class BaseAbListActivity<P extends BasePresenter, T> extends BasePresenterActivity<P> implements LMRecyclerView.OnFooterAutoLoadMoreListener, IPageLoadDataView<T> {
protected StatusLayout mStatusLayout;
protected SwipeRefreshLayout mRefreshLayout;
protected LMRecyclerView mRecyclerView;
private FloatingActionButton btn_scroll_top;
protected BaseListAdapter<T> mListAdapter;
private ViewAnimatorHelper viewAnimatorHelper;
protected int page;
protected int state = -1;
protected boolean isAutoLoadMore = true;//是否显示自动加载
protected List<T> mListData = new ArrayList<>();
@SuppressLint("RestrictedApi")
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
btn_scroll_top.setVisibility(View.VISIBLE);
btn_scroll_top.setOnClickListener(onScrollTopListener);
viewAnimatorHelper = new ViewAnimatorHelper();
viewAnimatorHelper.bindView(btn_scroll_top);
mRefreshLayout.setOnRefreshListener(mOnRefreshListener);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setItemAnimator(new NoAlphaItemAnimator());
mRecyclerView.addOnScrollListener(onScrollListener);
setCanLoadMore(isCanLoadMore());
mRecyclerView.addFooterAutoLoadMoreListener(this);
mListAdapter = getListAdapter();
mStatusLayout.showLoding();
if (mListAdapter != null) {
mRecyclerView.addHeaderView(initHeaderView());
mRecyclerView.setAdapter(mListAdapter);
loadDatas();
}
}
/**
*
*/
@Override
protected void initViews() {
mRefreshLayout = findViewById(R.id.refreshLayout);
mStatusLayout = findViewById(R.id.containerLayout);
mRecyclerView = findViewById(R.id.recyclerView);
btn_scroll_top = findViewById(R.id.btn_scroll_top);
}
private RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
if (dy > 0 && btn_scroll_top.getVisibility() != View.INVISIBLE && !viewAnimatorHelper.isAnimating()){
viewAnimatorHelper.hideFloatActionButton();
}else if (dy < 0 && btn_scroll_top.getVisibility() != View.VISIBLE){
viewAnimatorHelper.showFloatActionButton();
}
}
};
private View.OnClickListener onScrollTopListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
mRecyclerView.smoothScrollToPosition(0);
}
};
/**
* Layout
* @return
*/
@Override
protected int getLayoutId() {
return R.layout.include_recycler_list;
}
@Override
public List<T> getData() {
return mListData;
}
/**
*
*/
@Override
public void showContent() {
mStatusLayout.showContent();
mListAdapter.notifyAllDatas(mListData, mRecyclerView);
}
/**
*
*/
private SwipeRefreshLayout.OnRefreshListener mOnRefreshListener = new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
refreshData();
}
};
/**
*
*/
public void refreshData() {
state = Const.PAGE_STATE.STATE_REFRESH;
isAutoLoadMore = true;
page = getFirstPage();
loadDatas();
}
/**
*
*/
@Override
public void loadMore() {
if (!isAutoLoadMore) return;
state = Const.PAGE_STATE.STATE_LOAD_MORE;
loadDatas();
}
/**
*
*/
@Override
public void reLoadMore() {
isAutoLoadMore = true;
loadMore();
}
/**
*
*/
@Override
public void clearListData() {
mListData.clear();
}
/**
*
*/
@Override
public void autoLoadMore() {
mRecyclerView.showLoadMore();
page++;
isAutoLoadMore = true;
}
/**
*
*/
@Override
public void showNoMore() {
mRecyclerView.showNoMoreData();
isAutoLoadMore = false;
}
/**
*
*/
@Override
public void showError() {
isAutoLoadMore = false;
//如果是加载更多出现异常,那么底部就显示点击重新加载;
// 否则,就清空数据,显示没有数据
if (state == Const.PAGE_STATE.STATE_LOAD_MORE) {
mRecyclerView.showLoadMoreError();
mListAdapter.notifyAllDatas(mListData, mRecyclerView);
} else {
mStatusLayout.showError();
}
}
/**
*
* @return
*/
public int getPage() {
return page;
}
/**
* Loading
* @param msg
*/
@Override
public void showLoading(String msg) {
if (state == Const.PAGE_STATE.STATE_REFRESH)
setRefreshing(true);
}
@Override
public void hideLoading() {
setRefreshing(false);
}
/**
*
* @param isCanLoadMore
*/
public void setCanLoadMore(boolean isCanLoadMore) {
mRecyclerView.setCanLoadMore(isCanLoadMore);
}
/**
*
* @param isEnableRefresh
*/
public void setRefreshEnable(boolean isEnableRefresh) {
mRefreshLayout.setEnabled(isEnableRefresh);
}
/**
*
*/
@Override
public void showEmpty() {
mStatusLayout.showEmpty();
}
protected void setRefreshing(final boolean isRefrshing) {
mRefreshLayout.postDelayed(new Runnable() {
@Override
public void run() {
mRefreshLayout.setRefreshing(isRefrshing);
}
}, 100);
}
@Override
public int getFirstPage() {
return 0;
}
/**
*
* @return
*/
protected boolean isCanLoadMore(){
return false;
}
protected View initHeaderView(){
return null;
}
protected abstract void loadDatas();
protected abstract BaseListAdapter<T>getListAdapter();
}

@ -0,0 +1,289 @@
package com.kdp.wanandroidclient.ui.base;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import com.kdp.wanandroidclient.R;
import com.kdp.wanandroidclient.common.Const;
import com.kdp.wanandroidclient.event.Event;
import com.kdp.wanandroidclient.event.RxEvent;
import com.kdp.wanandroidclient.ui.adapter.BaseListAdapter;
import com.kdp.wanandroidclient.ui.core.presenter.BasePresenter;
import com.kdp.wanandroidclient.ui.core.view.IPageLoadDataView;
import com.kdp.wanandroidclient.utils.ToastUtils;
import com.kdp.wanandroidclient.widget.StatusLayout;
import com.kdp.wanandroidclient.widget.LMRecyclerView;
import java.util.ArrayList;
import java.util.List;
/**
* fragment
* author:
* date: 2023/5/31
*/
public abstract class BaseAbListFragment<P extends BasePresenter, T> extends BasePresenterFragment<P> implements LMRecyclerView.OnFooterAutoLoadMoreListener, IPageLoadDataView<T> {
protected StatusLayout mStatusLayout;
protected SwipeRefreshLayout mRefreshLayout;
protected LMRecyclerView mRecyclerView;
protected BaseListAdapter<T> mListAdapter;
protected int page = getFirstPage();
protected int state = -1;
protected boolean isAutoLoadMore = true;//是否开启自动加载
private boolean isPreload; //是否已经预加载完成
private boolean isVisible; //是否可见
private boolean isFirst = true;//是否第一次加载数据
private boolean isEnableLazy = false; //是否开启懒加载
protected List<T> mListData = new ArrayList<>();
@Override
protected void initViews(View view) {
mRefreshLayout = view.findViewById(R.id.refreshLayout);
mStatusLayout = view.findViewById(R.id.containerLayout);
mRecyclerView = view.findViewById(R.id.recyclerView);
}
@Override
public List<T> getData() {
return mListData;
}
/**
*
*/
@Override
public void showContent() {
mStatusLayout.showContent();
mListAdapter.notifyAllDatas(mListData, mRecyclerView);
}
@Override
protected int getLayoutId() {
return R.layout.include_recycler_list;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mRefreshLayout.setOnRefreshListener(mOnRefreshListener);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mRecyclerView.setCanLoadMore(isCanLoadMore());
mRecyclerView.addFooterAutoLoadMoreListener(this);
mListAdapter = getListAdapter();
if (mListAdapter != null) {
mRecyclerView.addHeaderView(initHeaderView());
mRecyclerView.setAdapter(mListAdapter);
if (isEnableLazy) {
isPreload = true;
isFirst = true;
lazyLoad();
} else {
mStatusLayout.showLoding();
loadDatas();
}
}
}
private void lazyLoad() {
if (!isPreload || !isVisible || !isFirst) {
return;
}
mStatusLayout.showLoding();
loadDatas();
isFirst = false;
}
/**
*
*
* @param isVisibleToUser
*/
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
isEnableLazy = isEnableLazy();//默认不开启懒加载
if (!isEnableLazy) return;
if (isVisibleToUser) {
isVisible = true;
lazyLoad();
} else {
isVisible = false;
}
}
/**
*
*/
private SwipeRefreshLayout.OnRefreshListener mOnRefreshListener = new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
refreshData();
}
};
/**
*
*/
public void refreshData() {
state = Const.PAGE_STATE.STATE_REFRESH;
isAutoLoadMore = true;
page = getFirstPage();
loadDatas();
}
/**
*
*/
@Override
public void loadMore() {
if (!isAutoLoadMore) return;
state = Const.PAGE_STATE.STATE_LOAD_MORE;
loadDatas();
}
/**
*
*/
@Override
public void reLoadMore() {
isAutoLoadMore = true;
loadMore();
}
/**
*
*/
@Override
public void clearListData() {
mListData.clear();
}
/**
*
*/
@Override
public void autoLoadMore() {
mRecyclerView.showLoadMore();
page++;
isAutoLoadMore = true;
}
/**
*
*/
@Override
public void showNoMore() {
mRecyclerView.showNoMoreData();
isAutoLoadMore = false;
}
/**
*
*/
@Override
public void showError() {
isAutoLoadMore = false;
//如果是加载更多出现异常,那么底部就显示点击重新加载;
// 否则,就清空数据,显示没有数据
if (state == Const.PAGE_STATE.STATE_LOAD_MORE) {
mRecyclerView.showLoadMoreError();
mListAdapter.notifyAllDatas(mListData, mRecyclerView);
} else {
mStatusLayout.showError();
}
}
/**
*
*/
@Override
public void showEmpty() {
mStatusLayout.showEmpty();
}
/**
*
*
* @return
*/
public int getPage() {
return page;
}
@Override
public void showLoading(String msg) {
if (state == Const.PAGE_STATE.STATE_REFRESH)
setRefreshing(true);
}
@Override
public void hideLoading() {
setRefreshing(false);
}
@Override
public void showFail(String msg) {
ToastUtils.showToast(getActivity(), msg);
}
protected void setRefreshing(final boolean isRefrshing) {
mRefreshLayout.postDelayed(new Runnable() {
@Override
public void run() {
mRefreshLayout.setRefreshing(isRefrshing);
}
}, 100);
}
@Override
public int getFirstPage() {
return 0;
}
/**
*
* @return
*/
protected boolean isEnableLazy() {
return false;
}
/**
*
* @return
*/
protected boolean isCanLoadMore(){
return false;
}
@Override
protected void getBundle(Bundle bundle) {
}
protected View initHeaderView(){
return null;
}
protected abstract void loadDatas();
protected abstract BaseListAdapter<T> getListAdapter();
}

@ -0,0 +1,160 @@
package com.kdp.wanandroidclient.ui.base;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import com.kdp.wanandroidclient.R;
import com.kdp.wanandroidclient.event.RxEvent;
import io.reactivex.observers.DisposableObserver;
import io.reactivex.subjects.PublishSubject;
/**
* Activity
*/
public abstract class BaseActivity extends AppCompatActivity {
protected Toolbar mToolbar;
protected FrameLayout mContainerLayout;
private ProgressDialog loadingDialog = null;
private PublishSubject mSubject;
private DisposableObserver mDisposableObserver;
@Override
protected void onCreate(Bundle bundle) {
if (bundle != null) {
//如果系统回收Activity,但是系统却保留了Fragment,当Activity被重新初始化,此时,系统保存的Fragment 的getActivity为空
//所以要移除旧的Fragment,重新初始化新的Fragment
String FRAGMENTS_TAG = "android:support:fragments";
bundle.remove(FRAGMENTS_TAG);
}
super.onCreate(bundle);
setContentView(R.layout.activity_base);
Intent intent = getIntent();
if (intent != null)
getIntent(intent);
mToolbar = findViewById(R.id.toolbar);
mContainerLayout = findViewById(R.id.frameLayout);
//初始化ToolBar
boolean isToolbar = initToolbar();
if (isToolbar) {
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
//必须要在setSupportActionBar之后,不然不起作用
@Override
public void onClick(View v) {
onNavigationClick();
}
});
} else {
mToolbar.setVisibility(View.GONE);
}
//初始化Content
initContent(getLayoutId());
//注册事件线
mSubject = RxEvent.getInstance().registerEvent(registerEvent());
mDisposableObserver = new ReceiveEvent();
mSubject.subscribe(mDisposableObserver);
}
private class ReceiveEvent extends DisposableObserver{
@Override
public void onNext(Object o) {
receiveEvent(o);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//注销事件
RxEvent.getInstance().unRegisterEvent(registerEvent(), mSubject, mDisposableObserver);
}
private void initContent(int layoutId) {
if (layoutId != 0) {
View contentView = LayoutInflater.from(this).inflate(layoutId, mContainerLayout, false);
mContainerLayout.addView(contentView);
initViews();
}
}
/**
*
*
* @param title
*/
protected void showLoadingDialog(String title) {
createLoadingDialog();
loadingDialog.setMessage(title);
if (!loadingDialog.isShowing())
loadingDialog.show();
}
/**
*
*/
protected void showLoadingDialog() {
createLoadingDialog();
if (!loadingDialog.isShowing())
loadingDialog.show();
}
/**
* LodingDialog
*/
private void createLoadingDialog() {
if (loadingDialog == null) {
loadingDialog = new ProgressDialog(this);
loadingDialog.setCancelable(true);
loadingDialog.setCanceledOnTouchOutside(false);
}
}
/**
*
*/
protected void hideLoadingDialog() {
if (loadingDialog != null && loadingDialog.isShowing()) {
loadingDialog.dismiss();
}
}
protected void receiveEvent(Object object){ }
protected String registerEvent(){
return null;
}
protected void onNavigationClick() {
finish();
}
protected abstract int getLayoutId();
protected boolean initToolbar(){
return false;
}
protected void getIntent(Intent intent){ }
protected abstract void initViews();
}

@ -0,0 +1,83 @@
package com.kdp.wanandroidclient.ui.base;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.kdp.wanandroidclient.event.RxEvent;
import io.reactivex.observers.DisposableObserver;
import io.reactivex.subjects.PublishSubject;
/**
* author:
* date: 2023/5/31
*/
public abstract class BaseFragment extends Fragment {
private PublishSubject mSubject;
private DisposableObserver mDisposableObserver;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getArguments();
if (bundle != null)
getBundle(bundle);
mDisposableObserver = new ReceiveEvent();
//注册事件
mSubject = RxEvent.getInstance().registerEvent(registerEvent());
mSubject.subscribe(mDisposableObserver);
}
private class ReceiveEvent extends DisposableObserver {
@Override
public void onNext(Object o) {
receiveEvent(o);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
}
@Override
public void onDestroy() {
super.onDestroy();
//注销事件
RxEvent.getInstance().unRegisterEvent(registerEvent(), mSubject, mDisposableObserver);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = null;
int layoutId = getLayoutId();
if (layoutId != 0) {
view = inflater.inflate(getLayoutId(), container, false);
initViews(view);
}
return view;
}
protected abstract void initViews(View view);
protected abstract int getLayoutId();
protected void receiveEvent(Object object){}
protected String registerEvent(){ return null; }
protected void getBundle(Bundle bundle){}
}

@ -0,0 +1,104 @@
package com.kdp.wanandroidclient.ui.base;
import android.content.Intent;
import android.os.Bundle;
import com.kdp.wanandroidclient.ui.core.presenter.BasePresenter;
import com.kdp.wanandroidclient.ui.core.view.IView;
import com.kdp.wanandroidclient.utils.ToastUtils;
/**
* PresenterActivity
*/
public abstract class BasePresenterActivity<P extends BasePresenter> extends BaseActivity implements IView {
protected P mPresenter;
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
mPresenter = createPresenter();
attachView();
}
@Override
protected void onNavigationClick() {
finish();
}
@Override
protected void getIntent(Intent intent) {
}
protected abstract P createPresenter();
@Override
protected void onDestroy() {
//接触presenter与View关联
detachView();
//移除所有请求
removeAllDisposable();
super.onDestroy();
}
//关联View
private void attachView() {
if (mPresenter != null) {
mPresenter.attachView(this);
}
}
private void detachView() {
if (mPresenter != null) {
mPresenter.detachView();
}
}
protected void removeAllDisposable() {
if (mPresenter != null) {
mPresenter.removeAllDisposable();
}
}
@Override
protected boolean initToolbar() {
return false;
}
@Override
protected void initViews() {
}
@Override
public void showLoading(String msg) {
}
@Override
public void hideLoading() {
hideLoadingDialog();
}
@Override
public void showFail(String msg) {
ToastUtils.showToast(this, msg);
}
@Override
public void showError() {
}
@Override
public void showEmpty() {
}
@Override
protected void receiveEvent(Object object) {
}
@Override
protected String registerEvent() {
return null;
}
}

@ -0,0 +1,79 @@
package com.kdp.wanandroidclient.ui.base;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.View;
import com.kdp.wanandroidclient.ui.core.presenter.BasePresenter;
import com.kdp.wanandroidclient.ui.core.view.IView;
/**
* author:
* date: 2023/5/31
*/
public abstract class BasePresenterFragment<P extends BasePresenter> extends BaseFragment implements IView{
protected P mPresenter;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter = createPresenter();
//关联View
attachView();
}
@Override
public void onDestroy() {
super.onDestroy();
//解除关联
detachView();
}
@Override
protected void initViews(View view) {
}
@Override
protected int getLayoutId() {
return 0;
}
private void detachView() {
if (mPresenter != null) {
mPresenter.detachView();
mPresenter.removeAllDisposable();
mPresenter = null;
}
}
private void attachView() {
if (mPresenter != null) {
mPresenter.attachView(this);
}
}
protected abstract P createPresenter();
@Override
public void showLoading(String msg) {
}
@Override
public void hideLoading() {
}
@Override
public void showFail(String msg) {
}
@Override
public void showError() {
}
@Override
public void showEmpty() {
}
}

@ -0,0 +1,54 @@
package com.kdp.wanandroidclient.ui.base;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.TabLayout;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import com.kdp.wanandroidclient.R;
import com.kdp.wanandroidclient.common.Const;
import com.kdp.wanandroidclient.event.Event;
import com.kdp.wanandroidclient.event.RxEvent;
/***
* @author kdp
* @date 2023
* @description
*/
public abstract class BaseTabActivity extends BaseActivity{
private TabLayout tabLayout;
protected ViewPager viewPager;
protected FloatingActionButton btn_scroll_top;
@Override
protected int getLayoutId() {
return R.layout.base_tab_layout;
}
@Override
protected void initViews() {
tabLayout = findViewById(R.id.tabLayout);
viewPager = findViewById(R.id.viewPager);
btn_scroll_top = findViewById(R.id.btn_scroll_top);
}
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
FragmentPagerAdapter fragPagerAdapter = createFragPagerAdapter();
if (fragPagerAdapter != null){
viewPager.setAdapter(fragPagerAdapter);
tabLayout.setupWithViewPager(viewPager);
}
}
protected abstract FragmentPagerAdapter createFragPagerAdapter();
}

@ -0,0 +1,26 @@
package com.kdp.wanandroidclient.ui.base;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.view.View;
import com.kdp.wanandroidclient.R;
import com.kdp.wanandroidclient.ui.core.presenter.BasePresenter;
/***
* @author kdp
* @date 2023
* @description
*/
public abstract class BaseTabFragment<P extends BasePresenter> extends BasePresenterFragment<P>{
protected TabLayout tabLayout;
protected ViewPager viewPager;
@Override
protected int getLayoutId() {
return R.layout.base_tab_layout;
}
@Override
protected void initViews(View view) {
tabLayout = view.findViewById(R.id.tabLayout);
viewPager = view.findViewById(R.id.viewPager);
}
}

@ -0,0 +1,20 @@
package com.kdp.wanandroidclient.ui.chapter;
import com.kdp.wanandroidclient.bean.Chapter;
import com.kdp.wanandroidclient.ui.core.view.IListDataView;
/***
* @author kdp
* @date 2023
* @description
*/
public interface ChapterContract {
interface IChaptersPresenter {
void getChapters();
}
interface IChaptersView extends IListDataView<Chapter>{
}
}

@ -0,0 +1,23 @@
package com.kdp.wanandroidclient.ui.chapter;
import com.kdp.wanandroidclient.bean.Article;
import com.kdp.wanandroidclient.ui.core.view.IPageLoadDataView;
/***
* @author kdp
* @date 2023
* @description
*/
public interface ChapterListContract {
interface IChapterListPresenter{
void getChapterList();
void collectArticle();
void unCollectArticle();
}
interface IChapterListView extends IPageLoadDataView<Article>{
int getCid();
int getArticleId();
void collect(boolean isCollect,String result);
}
}

@ -0,0 +1,168 @@
package com.kdp.wanandroidclient.ui.chapter;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import com.kdp.wanandroidclient.R;
import com.kdp.wanandroidclient.bean.Article;
import com.kdp.wanandroidclient.common.Const;
import com.kdp.wanandroidclient.event.Event;
import com.kdp.wanandroidclient.event.RxEvent;
import com.kdp.wanandroidclient.inter.OnArticleListItemClickListener;
import com.kdp.wanandroidclient.manager.UserInfoManager;
import com.kdp.wanandroidclient.ui.adapter.ArticleListAdapter;
import com.kdp.wanandroidclient.ui.adapter.BaseListAdapter;
import com.kdp.wanandroidclient.ui.base.BaseAbListFragment;
import com.kdp.wanandroidclient.ui.web.WebViewActivity;
import com.kdp.wanandroidclient.utils.IntentUtils;
import com.kdp.wanandroidclient.utils.ToastUtils;
import java.util.List;
/***
* @author kdp
* @date 2023
* @description
*/
public class ChapterListFragment extends BaseAbListFragment<ChapterListPresenter,Article> implements ChapterListContract.IChapterListView,OnArticleListItemClickListener {
private int cid;//公众号id
private int id;//文章id
private int position;
public static ChapterListFragment instantiate(int cid){
ChapterListFragment instance = new ChapterListFragment();
Bundle bundle = new Bundle();
bundle.putInt(Const.BUNDLE_KEY.ID,cid);
instance.setArguments(bundle);
return instance;
}
@Override
protected boolean isCanLoadMore() {
return true;
}
@Override
protected boolean isEnableLazy() {
return true;
}
@Override
protected void getBundle(Bundle bundle) {
if (bundle !=null){
cid = bundle.getInt(Const.BUNDLE_KEY.ID,0);
}
}
@Override
protected void loadDatas() {
mPresenter.getChapterList();
}
@Override
protected BaseListAdapter<Article> getListAdapter() {
return new ArticleListAdapter(this,Const.LIST_TYPE.CHAPTER);
}
@Override
protected ChapterListPresenter createPresenter() {
return new ChapterListPresenter();
}
@Override
public void setData(List<Article> data) {
mListData.addAll(data);
}
@Override
public int getFirstPage() {
return 1;
}
@Override
public int getCid() {
return cid;
}
@Override
public int getArticleId() {
return id;
}
@Override
public void collect(boolean isCollect, String result) {
notifyItemData(isCollect,result);
}
private void notifyItemData(boolean isCollect, String result) {
mListData.get(position).setCollect(isCollect);
mListAdapter.notifyItemDataChanged(position, mRecyclerView);
ToastUtils.showToast(getActivity(), result);
}
@Override
public void onDeleteCollectClick(int position, int id, int originId) {
}
@Override
public void onCollectClick(int position, int id) {
if (!UserInfoManager.isLogin())
IntentUtils.goLogin(getActivity());
this.id = id;
this.position = position;
if (mListData.get(this.position).isCollect())
mPresenter.unCollectArticle();
else
mPresenter.collectArticle();
}
@Override
public void onItemClick(int position, Article bean) {
Intent intent = new Intent(getActivity(), WebViewActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable(Const.BUNDLE_KEY.OBJ, bean);
bundle.putString(Const.BUNDLE_KEY.TYPE, Const.EVENT_ACTION.CHAPTER_LIST);
intent.putExtras(bundle);
startActivity(intent);
}
@Override
protected void receiveEvent(Object object) {
Event mEvent = (Event) object;
if (mEvent.type == Event.Type.REFRESH_ITEM) {
Article bean = (Article) mEvent.object;
for (int i = 0; i < mListData.size(); i++) {
if (bean.equals(mListData.get(i))) {
position = i;
notifyItemData(bean.isCollect(), getString(R.string.collect_success));
}
}
}else if (mEvent.type == Event.Type.SCROLL_TOP && (int)mEvent.object == cid){
mRecyclerView.smoothScrollToPosition(0);
}
else if (mEvent.type == Event.Type.REFRESH_LIST){
refreshData();
}
}
@Override
protected String registerEvent() {
return Const.EVENT_ACTION.CHAPTER_LIST;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mRecyclerView.addOnScrollListener(onScrollListener);
}
private RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
RxEvent.getInstance().postEvent(Const.EVENT_ACTION.MAIN,new Event(Event.Type.SCALE,dy));
}
};
}

@ -0,0 +1,88 @@
package com.kdp.wanandroidclient.ui.chapter;
import com.kdp.wanandroidclient.R;
import com.kdp.wanandroidclient.application.AppContext;
import com.kdp.wanandroidclient.bean.Article;
import com.kdp.wanandroidclient.net.callback.RxObserver;
import com.kdp.wanandroidclient.net.callback.RxPageListObserver;
import com.kdp.wanandroidclient.ui.core.model.impl.ChapterListModel;
import com.kdp.wanandroidclient.ui.core.presenter.BasePresenter;
import java.util.List;
/***
* @author kdp
* @date 2023
* @description
*/
public class ChapterListPresenter extends BasePresenter<ChapterListContract.IChapterListView> implements ChapterListContract.IChapterListPresenter{
private ChapterListModel chapterArticleModel;
private ChapterListContract.IChapterListView chapterArticleView;
public ChapterListPresenter() {
this.chapterArticleModel = new ChapterListModel();
}
@Override
public void getChapterList() {
chapterArticleView = getView();
RxPageListObserver<Article> rxPageListObserver = new RxPageListObserver<Article>(this) {
@Override
public void onSuccess(List<Article> mData) {
chapterArticleView.setData(mData);
if (chapterArticleView.getData().size() == 0){
chapterArticleView.showEmpty();
}else {
chapterArticleView.showContent();
}
}
@Override
public void onFail(int errorCode, String errorMsg) {
chapterArticleView.showFail(errorMsg);
}
};
chapterArticleModel.getChapterArticleList(chapterArticleView.getPage(),chapterArticleView.getCid(),rxPageListObserver);
addDisposable(rxPageListObserver);
}
@Override
public void collectArticle() {
RxObserver<String> mCollectRxObserver = new RxObserver<String>(this) {
@Override
protected void onStart() {
}
@Override
protected void onSuccess(String data) {
chapterArticleView.collect(true, AppContext.getContext().getString(R.string.collect_success));
}
@Override
protected void onFail(int errorCode, String errorMsg) {
view.showFail(errorMsg);
}
};
chapterArticleModel.collectArticle(chapterArticleView.getArticleId(), mCollectRxObserver);
addDisposable(mCollectRxObserver);
}
@Override
public void unCollectArticle() {
RxObserver<String> unCollectRxObserver = new RxObserver<String>(this) {
@Override
protected void onStart() {
}
@Override
protected void onSuccess(String data) {
chapterArticleView.collect(false, AppContext.getContext().getString(R.string.uncollect_success));
}
@Override
protected void onFail(int errorCode, String errorMsg) {
view.showFail(errorMsg);
}
};
chapterArticleModel.unCollectArticle(chapterArticleView.getArticleId(), unCollectRxObserver);
addDisposable(unCollectRxObserver);
}
}

@ -0,0 +1,65 @@
package com.kdp.wanandroidclient.ui.chapter;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.kdp.wanandroidclient.bean.Chapter;
import com.kdp.wanandroidclient.common.Const;
import com.kdp.wanandroidclient.event.Event;
import com.kdp.wanandroidclient.event.RxEvent;
import com.kdp.wanandroidclient.ui.adapter.ChaptersFragPagerAdapter;
import com.kdp.wanandroidclient.ui.base.BaseTabFragment;
import com.kdp.wanandroidclient.ui.main.MainActivity;
import java.util.ArrayList;
import java.util.List;
/***
* @author kdp
* @date 2023
* @description
*/
public class ChaptersFragment extends BaseTabFragment<ChaptersPresenter> implements ChapterContract.IChaptersView{
private List<Chapter> chapterList = new ArrayList<>();
@Override
protected ChaptersPresenter createPresenter() {
return new ChaptersPresenter();
}
@Override
public void setData(List<Chapter> data) {
chapterList.clear();
chapterList.addAll(data);
}
@Override
public List<Chapter> getData() {
return chapterList;
}
@Override
public void showContent() {
ChaptersFragPagerAdapter adapter = new ChaptersFragPagerAdapter(getChildFragmentManager(),chapterList);
viewPager.setAdapter(adapter);
viewPager.setOffscreenPageLimit(chapterList.size());
tabLayout.setupWithViewPager(viewPager);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mPresenter.getChapters();
}
public void scrollToTop(){
int id = chapterList.get(viewPager.getCurrentItem()).getId();
RxEvent.getInstance().postEvent(Const.EVENT_ACTION.CHAPTER_LIST,new Event(Event.Type.SCROLL_TOP,id));
}
}

@ -0,0 +1,44 @@
package com.kdp.wanandroidclient.ui.chapter;
import com.kdp.wanandroidclient.bean.Chapter;
import com.kdp.wanandroidclient.net.callback.RxObserver;
import com.kdp.wanandroidclient.ui.core.model.impl.ChapterModel;
import com.kdp.wanandroidclient.ui.core.presenter.BasePresenter;
import java.util.List;
/***
* @author kdp
* @date 2023
* @description
*/
public class ChaptersPresenter extends BasePresenter<ChapterContract.IChaptersView> implements ChapterContract.IChaptersPresenter{
private ChapterModel chapterModel;
private ChapterContract.IChaptersView chaptersView;
ChaptersPresenter() {
this.chapterModel = new ChapterModel();
}
@Override
public void getChapters() {
chaptersView = getView();
RxObserver<List<Chapter>> rxObserver = new RxObserver<List<Chapter>>(this) {
@Override
protected void onSuccess(List<Chapter> data) {
chaptersView.setData(data);
if (chaptersView.getData().size() == 0) {
chaptersView.showEmpty();
}else {
chaptersView.showContent();
}
}
@Override
protected void onFail(int errorCode, String errorMsg) {
chaptersView.showFail(errorMsg);
}
};
chapterModel.getChapters(rxObserver);
addDisposable(rxObserver);
}
}

@ -0,0 +1,20 @@
package com.kdp.wanandroidclient.ui.core.model;
import com.kdp.wanandroidclient.bean.Article;
import com.kdp.wanandroidclient.net.callback.RxPageListObserver;
/***
* @author kdp
* @date 2023
* @description
*/
public interface IChapterListModel {
/**
*
* @param page
* @param cid cid
* @param rxPageListObserver
*/
void getChapterArticleList(int page, int cid, RxPageListObserver<Article> rxPageListObserver);
}

@ -0,0 +1,20 @@
package com.kdp.wanandroidclient.ui.core.model;
import com.kdp.wanandroidclient.bean.Chapter;
import com.kdp.wanandroidclient.net.callback.RxObserver;
import java.util.List;
/***
* @author kdp
* @date 2019/3/25 16:34
* @description
*/
public interface IChapterModel {
/**
*
* @param rxObserver
*/
void getChapters(RxObserver<List<Chapter>> rxObserver);
}

@ -0,0 +1,30 @@
package com.kdp.wanandroidclient.ui.core.model;
import com.kdp.wanandroidclient.net.callback.RxObserver;
/**
*
* author:
* date: 2023/5/31
*/
public interface ICommonModel {
/**
*
*
* @param id id
* @param callback
*/
void collectArticle(int id, RxObserver<String> callback);
/**
*
*
* @param id id
* @param callback
*/
void unCollectArticle(int id, RxObserver<String> callback);
}

@ -0,0 +1,41 @@
package com.kdp.wanandroidclient.ui.core.model;
import com.kdp.wanandroidclient.bean.Article;
import com.kdp.wanandroidclient.bean.Banner;
import com.kdp.wanandroidclient.bean.BaseBean;
import com.kdp.wanandroidclient.bean.HomeData;
import com.kdp.wanandroidclient.bean.PageListData;
import com.kdp.wanandroidclient.net.callback.RxPageListObserver;
import java.util.List;
import io.reactivex.Observable;
import io.reactivex.functions.Function3;
import io.reactivex.observers.DisposableObserver;
/**
*
* author:
* date: 2023/5/31
*/
public interface IHomeModel {
/**
* banner
* @param page
* @param function3
* @param rxObserver
*/
void getHomeData(int page, Function3<BaseBean<List<Banner>>, BaseBean<List<Article>>, BaseBean<PageListData<Article>>, HomeData> function3, DisposableObserver<HomeData> rxObserver);
/**
*
* @param page
* @param rxPageListObserver
*/
void getMoreArticleList(int page,RxPageListObserver<Article> rxPageListObserver);
Observable<BaseBean<List<Banner>>> getBannerObservable();
Observable<BaseBean<List<Article>>> getHomeTopObservable();
Observable<BaseBean<PageListData<Article>>> getHomeListObservable(int page);
}

@ -0,0 +1,44 @@
package com.kdp.wanandroidclient.ui.core.model;
import com.kdp.wanandroidclient.bean.User;
import com.kdp.wanandroidclient.inter.VerifyAccountCallback;
import com.kdp.wanandroidclient.net.callback.RxObserver;
/**
*
*/
public interface ILogonModel {
/**
*
*
* @param username
* @param password
*/
void login(String username, String password,RxObserver<User> callback);
/**
*
*
* @param username
* @param password
*/
void register(String username, String password,RxObserver<String> callback);
/**
*
* @param user
*/
void saveUserInfo(User user);
/**
*
* @param username
* @param password
* @return
*/
boolean verifyAccount(String username, String password, VerifyAccountCallback callback);
}

@ -0,0 +1,14 @@
package com.kdp.wanandroidclient.ui.core.model;
import com.kdp.wanandroidclient.api.ApiServer;
public interface IModel {
/**
* 使RxRetrofit
*
* @return
*/
ApiServer doRxRequest();
}

@ -0,0 +1,20 @@
package com.kdp.wanandroidclient.ui.core.model;
import com.kdp.wanandroidclient.bean.ProjectCate;
import com.kdp.wanandroidclient.net.callback.RxObserver;
import java.util.List;
/***
* @author kdp
* @date 2019/3/20 16:52
* @description
*/
public interface IProjectCateModel {
/**
*
* @param rxObserver
*/
void getProjectCate(RxObserver<List<ProjectCate>> rxObserver);
}

@ -0,0 +1,15 @@
package com.kdp.wanandroidclient.ui.core.model;
import com.kdp.wanandroidclient.bean.Article;
import com.kdp.wanandroidclient.net.callback.RxPageListObserver;
public interface IProjectModel {
/**
*
* @param page
* @param cid id
* @param rxPageListObserver
*/
void getProjectList(int page, int cid, RxPageListObserver<Article> rxPageListObserver);
}

@ -0,0 +1,41 @@
package com.kdp.wanandroidclient.ui.core.model;
import com.kdp.wanandroidclient.bean.Article;
import com.kdp.wanandroidclient.bean.Friend;
import com.kdp.wanandroidclient.bean.Hotword;
import com.kdp.wanandroidclient.net.callback.RxObserver;
import com.kdp.wanandroidclient.net.callback.RxPageListObserver;
import java.util.List;
/**
*
* author:
* date: 2023/5/31
*/
public interface ISearchModel {
/**
*
*
* @param page
* @param keyword
* @param rxPageListObserver
*/
void searchArticle(int page, String keyword, RxPageListObserver<Article> rxPageListObserver);
/**
*
*
* @param rxObserver
*/
void getHotWord(RxObserver<List<Hotword>> rxObserver);
/**
*
*
* @param rxObserver
*/
void getFriend(RxObserver<List<Friend>> rxObserver);
}

@ -0,0 +1,24 @@
package com.kdp.wanandroidclient.ui.core.model;
import com.kdp.wanandroidclient.bean.Article;
import com.kdp.wanandroidclient.net.callback.RxPageListObserver;
/**
*
* author:
* date: 2023/5/31
*/
public interface ITreeListModel {
/**
*
*
* @param page
* @param cid id
* @param rxObserver
*/
void getTreeList(int page, int cid, RxPageListObserver<Article> rxObserver);
}

@ -0,0 +1,21 @@
package com.kdp.wanandroidclient.ui.core.model;
import com.kdp.wanandroidclient.bean.Tree;
import com.kdp.wanandroidclient.net.callback.RxObserver;
import java.util.List;
/**
*
* author:
* date: 2023/5/31
*/
public interface ITreeModel {
/**
*
*
* @param callback
*/
void getTree(RxObserver<List<Tree>> callback);
}

@ -0,0 +1,30 @@
package com.kdp.wanandroidclient.ui.core.model;
import com.kdp.wanandroidclient.bean.Article;
import com.kdp.wanandroidclient.net.callback.RxObserver;
import com.kdp.wanandroidclient.net.callback.RxPageListObserver;
/**
*
* author:
* date: 2023/5/31
*/
public interface IUserModel {
/**
*
* @param page
* @param rxObserver
*/
void getCollectArticleList(int page, RxPageListObserver<Article> rxObserver);
/**
*
*
* @param id id
* @param originId id
* @param callback
*/
void deleteCollectArticle(int id, int originId, RxObserver<String> callback);
}

@ -0,0 +1,14 @@
package com.kdp.wanandroidclient.ui.core.model.impl;
import com.kdp.wanandroidclient.api.ApiServer;
import com.kdp.wanandroidclient.net.RxRetrofit;
import com.kdp.wanandroidclient.ui.core.model.IModel;
public class BaseModel implements IModel {
@Override
public ApiServer doRxRequest() {
return RxRetrofit.Api();
}
}

@ -0,0 +1,28 @@
package com.kdp.wanandroidclient.ui.core.model.impl;
import com.kdp.wanandroidclient.bean.Article;
import com.kdp.wanandroidclient.bean.PageListData;
import com.kdp.wanandroidclient.net.RxSchedulers;
import com.kdp.wanandroidclient.net.callback.RxPageListObserver;
import com.kdp.wanandroidclient.ui.core.model.IChapterListModel;
/***
* @author kdp
* @date 2019/3/27 9:28
* @description
*/
public class ChapterListModel extends CommonModel implements IChapterListModel {
/**
*
* @param page
* @param cid cid
* @param rxPageListObserver
*/
@Override
public void getChapterArticleList(int page, int cid, RxPageListObserver<Article> rxPageListObserver) {
doRxRequest()
.getChapterList(page,cid)
.compose(RxSchedulers.<PageListData<Article>>io_main())
.subscribe(rxPageListObserver);
}
}

@ -0,0 +1,26 @@
package com.kdp.wanandroidclient.ui.core.model.impl;
import com.kdp.wanandroidclient.bean.Chapter;
import com.kdp.wanandroidclient.net.RxSchedulers;
import com.kdp.wanandroidclient.net.callback.RxObserver;
import com.kdp.wanandroidclient.ui.core.model.IChapterModel;
import java.util.List;
/***
* @author kdp
* @date 2019/3/25 16:35
* @description
*/
public class ChapterModel extends BaseModel implements IChapterModel{
/**
*
* @param rxObserver
*/
@Override
public void getChapters(RxObserver<List<Chapter>> rxObserver) {
doRxRequest()
.getChapters()
.compose(RxSchedulers.<List<Chapter>>io_main())
.subscribe(rxObserver);
}
}

@ -0,0 +1,41 @@
package com.kdp.wanandroidclient.ui.core.model.impl;
import com.kdp.wanandroidclient.ui.core.model.ICommonModel;
import com.kdp.wanandroidclient.net.RxSchedulers;
import com.kdp.wanandroidclient.net.callback.RxObserver;
/**
* author:
* date: 2018/2/26
*/
public class CommonModel extends BaseModel implements ICommonModel {
/**
*
* @param id id
* @param callback
*/
@Override
public void collectArticle(int id, RxObserver<String> callback) {
doRxRequest().
collectArticle(id)
.compose(RxSchedulers.<String>io_main())
.subscribe(callback);
}
/**
*
* @param id id
* @param callback
*/
@Override
public void unCollectArticle(int id, RxObserver<String> callback) {
doRxRequest()
.unCollectArticle(id)
.compose(RxSchedulers.<String>io_main())
.subscribe(callback);
}
}

@ -0,0 +1,66 @@
package com.kdp.wanandroidclient.ui.core.model.impl;
import com.kdp.wanandroidclient.bean.Article;
import com.kdp.wanandroidclient.bean.Banner;
import com.kdp.wanandroidclient.bean.BaseBean;
import com.kdp.wanandroidclient.bean.HomeData;
import com.kdp.wanandroidclient.bean.PageListData;
import com.kdp.wanandroidclient.net.RxSchedulers;
import com.kdp.wanandroidclient.net.callback.RxPageListObserver;
import com.kdp.wanandroidclient.ui.core.model.IHomeModel;
import java.util.List;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function3;
import io.reactivex.observers.DisposableObserver;
import io.reactivex.schedulers.Schedulers;
/**
* author:
* date: 2018/2/22
*/
public class HomeModel extends CommonModel implements IHomeModel {
/**
* banner
* @param page
* @param function3
* @param rxObserver
*/
@Override
public void getHomeData(int page, Function3<BaseBean<List<Banner>>, BaseBean<List<Article>>, BaseBean<PageListData<Article>>, HomeData> function3, DisposableObserver<HomeData> rxObserver) {
Observable<BaseBean<List<Banner>>> bannerObservable = getBannerObservable();
Observable<BaseBean<List<Article>>> homeTopObservable = getHomeTopObservable();
Observable<BaseBean<PageListData<Article>>> homeObservable = getHomeListObservable(page);
Observable.zip(bannerObservable, homeTopObservable, homeObservable, function3)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(rxObserver);
}
/**
*
* @param page
* @param rxPageListObserver
*/
@Override
public void getMoreArticleList(int page, RxPageListObserver<Article> rxPageListObserver) {
doRxRequest().getHomeList(page)
.compose(RxSchedulers.<PageListData<Article>>io_main())
.subscribe(rxPageListObserver);
}
@Override
public Observable<BaseBean<List<Banner>>> getBannerObservable() {
return doRxRequest().getBanner().subscribeOn(Schedulers.newThread());
}
@Override
public Observable<BaseBean<List<Article>>> getHomeTopObservable() {
return doRxRequest().getHomeTopList().subscribeOn(Schedulers.newThread());
}
@Override
public Observable<BaseBean<PageListData<Article>>> getHomeListObservable(int page) {
return doRxRequest().getHomeList(page);
}
}

@ -0,0 +1,80 @@
package com.kdp.wanandroidclient.ui.core.model.impl;
import android.text.TextUtils;
import com.kdp.wanandroidclient.R;
import com.kdp.wanandroidclient.application.AppContext;
import com.kdp.wanandroidclient.bean.User;
import com.kdp.wanandroidclient.inter.VerifyAccountCallback;
import com.kdp.wanandroidclient.manager.UserInfoManager;
import com.kdp.wanandroidclient.net.RxSchedulers;
import com.kdp.wanandroidclient.net.callback.RxObserver;
import com.kdp.wanandroidclient.ui.core.model.ILogonModel;
/**
* Created by on 2018/2/1.
*/
public class LogonModel extends BaseModel implements ILogonModel {
/**
*
* @param username
* @param password
* @param callback
*/
@Override
public void login(String username, String password, RxObserver<User> callback) {
doRxRequest()
.login(username, password)
.compose(RxSchedulers.<User>io_main())
.subscribe(callback);
}
/**
*
* @param username
* @param password
* @param callback
*/
@Override
public void register(final String username, final String password, RxObserver<String> callback) {
doRxRequest()
.register(username, password, password)
.compose(RxSchedulers.<String>io_main())
.subscribe(callback);
}
/**
*
* @param user
*/
@Override
public void saveUserInfo(User user) {
//加密保存用户信息和密钥
UserInfoManager.saveUserInfo(user);
UserInfoManager.saveIsLogin(true);
}
/**
*
* @param username
* @param password
* @param callback
* @return
*/
@Override
public boolean verifyAccount(String username, String password, VerifyAccountCallback callback) {
if (TextUtils.isEmpty(username)) {
callback.onVerifyResult(AppContext.getContext().getString(R.string.username_not_empty));
return false;
}
if (TextUtils.isEmpty(password)) {
callback.onVerifyResult(AppContext.getContext().getString(R.string.password_not_empty));
return false;
}
return true;
}
}

@ -0,0 +1,28 @@
package com.kdp.wanandroidclient.ui.core.model.impl;
import com.kdp.wanandroidclient.bean.ProjectCate;
import com.kdp.wanandroidclient.net.RxSchedulers;
import com.kdp.wanandroidclient.net.callback.RxObserver;
import com.kdp.wanandroidclient.ui.core.model.IProjectCateModel;
import java.util.List;
/***
* @author kdp
* @date 2019/3/20 16:55
* @description
*/
public class ProjectCateModel extends BaseModel implements IProjectCateModel {
/**
*
* @param rxObserver
*/
@Override
public void getProjectCate(RxObserver<List<ProjectCate>> rxObserver) {
doRxRequest()
.getProjectCate()
.compose(RxSchedulers.<List<ProjectCate>>io_main())
.subscribe(rxObserver);
}
}

@ -0,0 +1,23 @@
package com.kdp.wanandroidclient.ui.core.model.impl;
import com.kdp.wanandroidclient.bean.Article;
import com.kdp.wanandroidclient.bean.PageListData;
import com.kdp.wanandroidclient.net.RxSchedulers;
import com.kdp.wanandroidclient.net.callback.RxPageListObserver;
import com.kdp.wanandroidclient.ui.core.model.IProjectModel;
public class ProjectModel extends CommonModel implements IProjectModel {
/**
*
* @param page
* @param cid id
* @param rxPageListObserver
*/
@Override
public void getProjectList(int page, int cid, RxPageListObserver<Article> rxPageListObserver) {
doRxRequest()
.getProjectList(page,cid)
.compose(RxSchedulers.<PageListData<Article>>io_main())
.subscribe(rxPageListObserver);
}
}

@ -0,0 +1,58 @@
package com.kdp.wanandroidclient.ui.core.model.impl;
import com.kdp.wanandroidclient.bean.Article;
import com.kdp.wanandroidclient.bean.Friend;
import com.kdp.wanandroidclient.bean.Hotword;
import com.kdp.wanandroidclient.bean.PageListData;
import com.kdp.wanandroidclient.net.RxSchedulers;
import com.kdp.wanandroidclient.net.callback.RxObserver;
import com.kdp.wanandroidclient.net.callback.RxPageListObserver;
import com.kdp.wanandroidclient.ui.core.model.ISearchModel;
import com.kdp.wanandroidclient.utils.LogUtils;
import java.util.List;
/**
* author:
* date: 2018/4/5
*/
public class SearchModel extends CommonModel implements ISearchModel {
/**
*
* @param page
* @param keyword
* @param rxObserver
*/
@Override
public void searchArticle(int page, String keyword, RxPageListObserver<Article> rxObserver) {
doRxRequest()
.search(page, keyword)
.compose(RxSchedulers.<PageListData<Article>>io_main())
.subscribe(rxObserver);
}
/**
*
* @param observable
*/
@Override
public void getHotWord(RxObserver<List<Hotword>> observable) {
doRxRequest()
.getHotKeyword()
.compose(RxSchedulers.<List<Hotword>>io_main())
.subscribe(observable);
}
/**
*
* @param rxObserver
*/
@Override
public void getFriend(RxObserver<List<Friend>> rxObserver) {
doRxRequest()
.getFriend()
.compose(RxSchedulers.<List<Friend>>io_main())
.subscribe(rxObserver);
}
}

@ -0,0 +1,30 @@
package com.kdp.wanandroidclient.ui.core.model.impl;
import com.kdp.wanandroidclient.bean.Article;
import com.kdp.wanandroidclient.bean.PageListData;
import com.kdp.wanandroidclient.net.RxSchedulers;
import com.kdp.wanandroidclient.net.callback.RxPageListObserver;
import com.kdp.wanandroidclient.ui.core.model.ITreeListModel;
/**
* author:
* date: 2018/3/20
*/
public class TreeListModel extends CommonModel implements ITreeListModel {
/**
*
* @param page
* @param cid id
* @param rxObserver
*/
@Override
public void getTreeList(int page,int cid,RxPageListObserver<Article> rxObserver) {
doRxRequest()
.getTreeList(page, cid)
.compose(RxSchedulers.<PageListData<Article>>io_main())
.subscribe(rxObserver);
}
}

@ -0,0 +1,30 @@
package com.kdp.wanandroidclient.ui.core.model.impl;
import com.kdp.wanandroidclient.bean.Tree;
import com.kdp.wanandroidclient.net.RxSchedulers;
import com.kdp.wanandroidclient.net.callback.RxObserver;
import com.kdp.wanandroidclient.ui.core.model.ITreeModel;
import java.util.List;
/**
* author:
* date: 2018/2/24
*/
public class TreeModel extends BaseModel implements ITreeModel {
/**
*
* @param callback
*/
@Override
public void getTree(RxObserver<List<Tree>> callback) {
doRxRequest()
.getTree()
.compose(RxSchedulers.<List<Tree>>io_main())
.subscribe(callback);
}
}

@ -0,0 +1,42 @@
package com.kdp.wanandroidclient.ui.core.model.impl;
import com.kdp.wanandroidclient.bean.Article;
import com.kdp.wanandroidclient.bean.PageListData;
import com.kdp.wanandroidclient.net.RxSchedulers;
import com.kdp.wanandroidclient.net.callback.RxObserver;
import com.kdp.wanandroidclient.net.callback.RxPageListObserver;
import com.kdp.wanandroidclient.ui.core.model.IUserModel;
/**
* author:
* date: 2018/3/21
*/
public class UserModel extends CommonModel implements IUserModel {
/**
*
* @param page
* @param rxObserver
*/
@Override
public void getCollectArticleList(int page, RxPageListObserver<Article> rxObserver) {
doRxRequest()
.getCollectArticleList(page)
.compose(RxSchedulers.<PageListData<Article>>io_main())
.subscribe(rxObserver);
}
/**
*
* @param id id
* @param originId id
* @param callback
*/
@Override
public void deleteCollectArticle(int id, int originId, RxObserver<String> callback) {
doRxRequest()
.deleteCollectArticle(id, originId)
.compose(RxSchedulers.<String>io_main())
.subscribe(callback);
}
}

@ -0,0 +1,66 @@
package com.kdp.wanandroidclient.ui.core.presenter;
import com.kdp.wanandroidclient.ui.core.view.IView;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
/**
* Presenter,view
*/
public class BasePresenter<V extends IView> implements IPresenter<V> {
private V view;
//用来存放Disposable的容器
private CompositeDisposable mCompositeDisposable;
//绑定View
@Override
public void attachView(V view) {
this.view = view;
}
//解除View绑定
@Override
public void detachView() {
this.view = null;
}
//获取绑定的View
@Override
public V getView() {
checkAttachView();
return view;
}
//检查View是否存在
@Override
public void checkAttachView() {
if (view == null)
throw new RuntimeException("You have no binding this view");
}
//添加指定的请求
@Override
public void addDisposable(Disposable disposable) {
if (mCompositeDisposable == null)
mCompositeDisposable = new CompositeDisposable();
mCompositeDisposable.add(disposable);
}
//移除指定的请求
@Override
public void removeDisposable(Disposable disposable) {
if (mCompositeDisposable != null)
mCompositeDisposable.remove(disposable);
}
//取消所有的请求Tag
@Override
public void removeAllDisposable() {
if (mCompositeDisposable != null)
mCompositeDisposable.clear();
}
}

@ -0,0 +1,31 @@
package com.kdp.wanandroidclient.ui.core.presenter;
import com.kdp.wanandroidclient.ui.core.view.IView;
import io.reactivex.disposables.Disposable;
/**
* Presenter
*/
public interface IPresenter<V extends IView> {
//绑定View
void attachView(V view);
//解除View绑定
void detachView();
//检查View是否存在
void checkAttachView();
V getView();
//添加指定的请求
void addDisposable(Disposable disposable);
//移除指定的请求
void removeDisposable(Disposable disposable);
//取消所有请求
void removeAllDisposable();
}

@ -0,0 +1,17 @@
package com.kdp.wanandroidclient.ui.core.view;
import java.util.List;
/***
* @author kdp
* @date 2019/3/20 13:03
* @description
*/
public interface IListDataView<T> extends IView{
void setData(List<T> data);
List<T> getData();
void showContent(); //显示内容
}

@ -0,0 +1,17 @@
package com.kdp.wanandroidclient.ui.core.view;
/**
* View
* author:
* date: 2023/5/31
*/
public interface IPageLoadDataView<T> extends IListDataView<T>{
int getFirstPage();
int getPage();
void autoLoadMore();//自动加载
void clearListData();//清空所有数据
void showNoMore();//没有更多数据
}

@ -0,0 +1,41 @@
package com.kdp.wanandroidclient.ui.core.view;
/**
* view
*/
public interface IView{
/**
*
*
*/
void showLoading(String msg);
/**
*
*/
void hideLoading();
/**
*
*
* @param msg
*/
void showFail(String msg);
/**
*
*/
void showError();
/**
*
*/
void showEmpty();//没有数据
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save