詹子聪 пре 5 година
комит
cc9d51d826
100 измењених фајлова са 7251 додато и 0 уклоњено
  1. 19 0
      ShiBei.iml
  2. 111 0
      adapter/adapter.iml
  3. 33 0
      adapter/build.gradle
  4. 9 0
      adapter/src/main/AndroidManifest.xml
  5. 8 0
      adapter/src/main/java/com/itant/library/Placeholder.java
  6. 41 0
      adapter/src/main/java/com/itant/library/abslistview/CommonAdapter.java
  7. 98 0
      adapter/src/main/java/com/itant/library/abslistview/MultiItemTypeAdapter.java
  8. 290 0
      adapter/src/main/java/com/itant/library/abslistview/ViewHolder.java
  9. 20 0
      adapter/src/main/java/com/itant/library/abslistview/base/ItemViewDelegate.java
  10. 134 0
      adapter/src/main/java/com/itant/library/abslistview/base/ItemViewDelegateManager.java
  11. 54 0
      adapter/src/main/java/com/itant/library/recyclerview/CommonAdapter.java
  12. 132 0
      adapter/src/main/java/com/itant/library/recyclerview/MultiItemTypeAdapter.java
  13. 16 0
      adapter/src/main/java/com/itant/library/recyclerview/base/ItemViewDelegate.java
  14. 116 0
      adapter/src/main/java/com/itant/library/recyclerview/base/ItemViewDelegateManager.java
  15. 311 0
      adapter/src/main/java/com/itant/library/recyclerview/base/ViewHolder.java
  16. 55 0
      adapter/src/main/java/com/itant/library/recyclerview/utils/WrapperUtils.java
  17. 128 0
      adapter/src/main/java/com/itant/library/recyclerview/wrapper/EmptyWrapper.java
  18. 152 0
      adapter/src/main/java/com/itant/library/recyclerview/wrapper/HeaderAndFooterWrapper.java
  19. 161 0
      adapter/src/main/java/com/itant/library/recyclerview/wrapper/LoadMoreWrapper.java
  20. 13 0
      adapter/src/main/res/anim/anim_bottom_in.xml
  21. 4 0
      adapter/src/main/res/values-v21/dimen.xml
  22. 11 0
      adapter/src/main/res/values/color.xml
  23. 5 0
      adapter/src/main/res/values/dimen.xml
  24. 3 0
      adapter/src/main/res/values/strings.xml
  25. 22 0
      adapter/src/main/res/values/styles.xml
  26. 195 0
      app/app.iml
  27. 125 0
      app/build.gradle
  28. BIN
      app/commonkey
  29. BIN
      app/libs/jiaozivideoplayer-7.4.2.aar
  30. 21 0
      app/proguard-rules.pro
  31. 27 0
      app/src/androidTest/java/com/itant/shibei/ExampleInstrumentedTest.java
  32. 96 0
      app/src/main/AndroidManifest.xml
  33. 32 0
      app/src/main/java/com/itant/shibei/adapter/FragmentPagerItemAdapter.java
  34. 104 0
      app/src/main/java/com/itant/shibei/base/ApiService.java
  35. 58 0
      app/src/main/java/com/itant/shibei/base/BaseBeiActivity.java
  36. 11 0
      app/src/main/java/com/itant/shibei/base/ITopActionListener.java
  37. 5 0
      app/src/main/java/com/itant/shibei/base/ItemLongClickListener.java
  38. 33 0
      app/src/main/java/com/itant/shibei/bean/BeiUser.java
  39. 17 0
      app/src/main/java/com/itant/shibei/bean/SystemBean.java
  40. 17 0
      app/src/main/java/com/itant/shibei/bean/UpgradeBean.java
  41. 16 0
      app/src/main/java/com/itant/shibei/common/ICommonView.java
  42. 16 0
      app/src/main/java/com/itant/shibei/constant/ConstantString.java
  43. 42 0
      app/src/main/java/com/itant/shibei/constant/ConstantUrl.java
  44. 66 0
      app/src/main/java/com/itant/shibei/manager/PreferenceManager.java
  45. 55 0
      app/src/main/java/com/itant/shibei/manager/UserInfoManager.java
  46. 173 0
      app/src/main/java/com/itant/shibei/net/RetrofitHelper.java
  47. 82 0
      app/src/main/java/com/itant/shibei/tool/Base64Tool.java
  48. 95 0
      app/src/main/java/com/itant/shibei/tool/DataTool.java
  49. 42 0
      app/src/main/java/com/itant/shibei/tool/MD5Tool.java
  50. 74 0
      app/src/main/java/com/itant/shibei/tool/StringTool.java
  51. 93 0
      app/src/main/java/com/itant/shibei/tool/SystemTool.java
  52. 51 0
      app/src/main/java/com/itant/shibei/tool/TimeTool.java
  53. 28 0
      app/src/main/java/com/itant/shibei/ui/BeiApplication.java
  54. 52 0
      app/src/main/java/com/itant/shibei/ui/HomeFragment.java
  55. 89 0
      app/src/main/java/com/itant/shibei/ui/MainActivity.java
  56. 68 0
      app/src/main/java/com/itant/shibei/ui/MainViewModel.java
  57. 165 0
      app/src/main/java/com/itant/shibei/ui/TabActivity.java
  58. 48 0
      app/src/main/java/com/itant/shibei/ui/function/FunctionFragment.java
  59. 97 0
      app/src/main/java/com/itant/shibei/ui/home/about/AboutFragment.java
  60. 49 0
      app/src/main/java/com/itant/shibei/ui/home/about/upgrade/UpgradePresenter.java
  61. 68 0
      app/src/main/java/com/itant/shibei/ui/home/coupon/CouponBean.java
  62. 17 0
      app/src/main/java/com/itant/shibei/ui/home/coupon/ITemplateView.java
  63. 129 0
      app/src/main/java/com/itant/shibei/ui/home/coupon/TemplateAdapter.java
  64. 238 0
      app/src/main/java/com/itant/shibei/ui/home/coupon/TemplateFragment.java
  65. 71 0
      app/src/main/java/com/itant/shibei/ui/home/coupon/TemplatePresenter.java
  66. 179 0
      app/src/main/java/com/itant/shibei/ui/home/goods/GoodsAdapter.java
  67. 136 0
      app/src/main/java/com/itant/shibei/ui/home/goods/GoodsBean.java
  68. 243 0
      app/src/main/java/com/itant/shibei/ui/home/goods/GoodsFragment.java
  69. 68 0
      app/src/main/java/com/itant/shibei/ui/home/goods/GoodsPresenter.java
  70. 17 0
      app/src/main/java/com/itant/shibei/ui/home/goods/IGoodsView.java
  71. 62 0
      app/src/main/java/com/itant/shibei/ui/home/goods/play/VideoPlayActivity.java
  72. 16 0
      app/src/main/java/com/itant/shibei/ui/home/search/ISearchView.java
  73. 267 0
      app/src/main/java/com/itant/shibei/ui/home/search/SearchActivity.java
  74. 47 0
      app/src/main/java/com/itant/shibei/ui/home/search/SearchPresenter.java
  75. 15 0
      app/src/main/java/com/itant/shibei/ui/home/tool/ISystemView.java
  76. 74 0
      app/src/main/java/com/itant/shibei/ui/home/tool/SystemPresenter.java
  77. 122 0
      app/src/main/java/com/itant/shibei/ui/home/tool/ToolFragment.java
  78. 15 0
      app/src/main/java/com/itant/shibei/ui/home/tool/json/IJsonView.java
  79. 106 0
      app/src/main/java/com/itant/shibei/ui/home/tool/json/JsonActivity.java
  80. 14 0
      app/src/main/java/com/itant/shibei/ui/home/tool/json/JsonBean.java
  81. 67 0
      app/src/main/java/com/itant/shibei/ui/home/tool/json/JsonPresenter.java
  82. 69 0
      app/src/main/java/com/itant/shibei/ui/home/tool/weather/WeatherActivity.java
  83. 18 0
      app/src/main/java/com/itant/shibei/ui/home/tool/weather/WeatherBean.java
  84. 71 0
      app/src/main/java/com/itant/shibei/ui/home/tool/yiji/YijiActivity.java
  85. 18 0
      app/src/main/java/com/itant/shibei/ui/home/tool/yiji/YijiBean.java
  86. 166 0
      app/src/main/java/com/itant/shibei/ui/mine/MineActivity.java
  87. 45 0
      app/src/main/java/com/itant/shibei/ui/mine/MineFragment.java
  88. 104 0
      app/src/main/java/com/itant/shibei/ui/mine/coupon/AddCouponActivity.java
  89. 43 0
      app/src/main/java/com/itant/shibei/ui/mine/coupon/AddCouponPresenter.java
  90. 18 0
      app/src/main/java/com/itant/shibei/ui/mine/coupon/IAddCouponView.java
  91. 130 0
      app/src/main/java/com/itant/shibei/ui/mine/forget/ForgetActivity.java
  92. 50 0
      app/src/main/java/com/itant/shibei/ui/mine/forget/ForgetPresenter.java
  93. 16 0
      app/src/main/java/com/itant/shibei/ui/mine/forget/IForgetView.java
  94. 193 0
      app/src/main/java/com/itant/shibei/ui/mine/goods/AddGoodsActivity.java
  95. 43 0
      app/src/main/java/com/itant/shibei/ui/mine/goods/AddGoodsPresenter.java
  96. 15 0
      app/src/main/java/com/itant/shibei/ui/mine/goods/IAddGoodsView.java
  97. 16 0
      app/src/main/java/com/itant/shibei/ui/mine/login/ILoginView.java
  98. 134 0
      app/src/main/java/com/itant/shibei/ui/mine/login/LoginActivity.java
  99. 43 0
      app/src/main/java/com/itant/shibei/ui/mine/login/LoginPresenter.java
  100. 0 0
      app/src/main/java/com/itant/shibei/ui/mine/register/CodePresenter.java

+ 19 - 0
ShiBei.iml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.id="ShiBei" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4">
+  <component name="FacetManager">
+    <facet type="java-gradle" name="Java-Gradle">
+      <configuration>
+        <option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
+        <option name="BUILDABLE" value="false" />
+      </configuration>
+    </facet>
+  </component>
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/.gradle" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 111 - 0
adapter/adapter.iml

@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.id=":adapter" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
+  <component name="FacetManager">
+    <facet type="android-gradle" name="Android-Gradle">
+      <configuration>
+        <option name="GRADLE_PROJECT_PATH" value=":adapter" />
+        <option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="3.5.2" />
+        <option name="LAST_KNOWN_AGP_VERSION" value="3.5.2" />
+      </configuration>
+    </facet>
+    <facet type="android" name="Android">
+      <configuration>
+        <option name="SELECTED_BUILD_VARIANT" value="release" />
+        <option name="ASSEMBLE_TASK_NAME" value="assembleRelease" />
+        <option name="COMPILE_JAVA_TASK_NAME" value="compileReleaseSources" />
+        <afterSyncTasks>
+          <task>generateReleaseSources</task>
+        </afterSyncTasks>
+        <option name="ALLOW_USER_CONFIGURATION" value="false" />
+        <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
+        <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
+        <option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
+        <option name="TEST_RES_FOLDERS_RELATIVE_PATH" value="" />
+        <option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
+        <option name="PROJECT_TYPE" value="1" />
+      </configuration>
+    </facet>
+  </component>
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
+    <output url="file://$MODULE_DIR$/build/intermediates/javac/release/classes" />
+    <output-test url="file://$MODULE_DIR$/build/intermediates/javac/releaseUnitTest/classes" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/release/out" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/release/compileReleaseAidl/out" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/release" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/release/compileReleaseRenderscript/out" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/release" type="java-resource" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/release" type="java-resource" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/releaseUnitTest/out" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/release/res" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/release/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/release/assets" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/release/aidl" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/release/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/release/rs" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/release/shaders" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelease/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelease/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelease/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelease/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelease/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelease/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelease/shaders" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
+      <excludeFolder url="file://$MODULE_DIR$/build" />
+    </content>
+    <orderEntry type="jdk" jdkName="Android API 29 Platform" jdkType="Android SDK" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="Gradle: androidx.collection:collection:1.1.0@jar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-common:2.3.0-alpha03@jar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.arch.core:core-common:2.1.0@jar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.annotation:annotation:1.2.0-alpha01@jar" level="project" />
+    <orderEntry type="library" name="Gradle: com.google.android.material:material:1.1.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.appcompat:appcompat:1.3.0-alpha01@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.viewpager2:viewpager2:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.fragment:fragment:1.1.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.appcompat:appcompat-resources:1.3.0-alpha01@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.drawerlayout:drawerlayout:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.coordinatorlayout:coordinatorlayout:1.1.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.transition:transition:1.2.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable-animated:1.1.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable:1.1.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.recyclerview:recyclerview:1.1.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.viewpager:viewpager:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.loader:loader:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.activity:activity:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.customview:customview:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.core:core:1.4.0-alpha01@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.cursoradapter:cursoradapter:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.cardview:cardview:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-runtime:2.3.0-alpha03@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.versionedparcelable:versionedparcelable:1.1.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-viewmodel:2.3.0-alpha03@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata:2.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata-core:2.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.arch.core:core-runtime:2.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.savedstate:savedstate:1.1.0-alpha01@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.interpolator:interpolator:1.0.0@aar" level="project" />
+  </component>
+</module>

+ 33 - 0
adapter/build.gradle

@@ -0,0 +1,33 @@
+apply plugin: 'com.android.library'
+
+android {
+    compileSdkVersion versions.compileSdk
+    buildToolsVersion versions.buildTools
+
+    defaultConfig {
+        minSdkVersion versions.minSdk
+        targetSdkVersion versions.targetSdk
+        versionCode 1
+        versionName "1.0"
+
+        //testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+
+    }
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+        }
+    }
+}
+
+dependencies {
+    compile fileTree(dir: 'libs', include: ['*.jar'])
+    /*androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
+        exclude group: 'com.android.support', module: 'support-annotations'
+    })
+    testCompile 'junit:junit:4.12'*/
+
+    api 'androidx.appcompat:appcompat:1.3.0-alpha01'
+    api 'com.google.android.material:material:1.1.0'
+}

+ 9 - 0
adapter/src/main/AndroidManifest.xml

@@ -0,0 +1,9 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.itant.library">
+
+    <application  android:label="@string/app_name">
+        <!--android:allowBackup="true"
+        android:supportsRtl="true"-->
+
+    </application>
+
+</manifest>

+ 8 - 0
adapter/src/main/java/com/itant/library/Placeholder.java

@@ -0,0 +1,8 @@
+package com.itant.library;
+
+/**
+ * Created by iTant on 2017/3/27.
+ */
+
+public class Placeholder {
+}

+ 41 - 0
adapter/src/main/java/com/itant/library/abslistview/CommonAdapter.java

@@ -0,0 +1,41 @@
+package com.itant.library.abslistview;
+
+import android.content.Context;
+
+
+import com.itant.library.abslistview.base.ItemViewDelegate;
+
+import java.util.List;
+
+public abstract class CommonAdapter<T> extends MultiItemTypeAdapter<T>
+{
+
+    public CommonAdapter(Context context, final int layoutId, List<T> datas)
+    {
+        super(context, datas);
+
+        addItemViewDelegate(new ItemViewDelegate<T>()
+        {
+            @Override
+            public int getItemViewLayoutId()
+            {
+                return layoutId;
+            }
+
+            @Override
+            public boolean isForViewType(T item, int position)
+            {
+                return true;
+            }
+
+            @Override
+            public void convert(ViewHolder holder, T t, int position)
+            {
+                CommonAdapter.this.convert(holder, t, position);
+            }
+        });
+    }
+
+    protected abstract void convert(ViewHolder viewHolder, T item, int position);
+
+}

+ 98 - 0
adapter/src/main/java/com/itant/library/abslistview/MultiItemTypeAdapter.java

@@ -0,0 +1,98 @@
+package com.itant.library.abslistview;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+
+import com.itant.library.abslistview.base.ItemViewDelegate;
+import com.itant.library.abslistview.base.ItemViewDelegateManager;
+
+import java.util.List;
+
+public class MultiItemTypeAdapter<T> extends BaseAdapter {
+    protected Context mContext;
+    protected List<T> mDatas;
+
+    private ItemViewDelegateManager mItemViewDelegateManager;
+
+
+    public MultiItemTypeAdapter(Context context, List<T> datas) {
+        this.mContext = context;
+        this.mDatas = datas;
+        mItemViewDelegateManager = new ItemViewDelegateManager();
+    }
+
+    public MultiItemTypeAdapter addItemViewDelegate(ItemViewDelegate<T> itemViewDelegate) {
+        mItemViewDelegateManager.addDelegate(itemViewDelegate);
+        return this;
+    }
+
+    private boolean useItemViewDelegateManager() {
+        return mItemViewDelegateManager.getItemViewDelegateCount() > 0;
+    }
+
+    @Override
+    public int getViewTypeCount() {
+        if (useItemViewDelegateManager())
+            return mItemViewDelegateManager.getItemViewDelegateCount();
+        return super.getViewTypeCount();
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        if (useItemViewDelegateManager()) {
+            int viewType = mItemViewDelegateManager.getItemViewType(mDatas.get(position), position);
+            return viewType;
+        }
+        return super.getItemViewType(position);
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        ItemViewDelegate itemViewDelegate = mItemViewDelegateManager.getItemViewDelegate(mDatas.get(position), position);
+        int layoutId = itemViewDelegate.getItemViewLayoutId();
+        ViewHolder viewHolder = null ;
+        if (convertView == null)
+        {
+            View itemView = LayoutInflater.from(mContext).inflate(layoutId, parent,
+                    false);
+            viewHolder = new ViewHolder(mContext, itemView, parent, position);
+            viewHolder.mLayoutId = layoutId;
+            onViewHolderCreated(viewHolder,viewHolder.getConvertView());
+        } else
+        {
+            viewHolder = (ViewHolder) convertView.getTag();
+            viewHolder.mPosition = position;
+        }
+
+
+        convert(viewHolder, getItem(position), position);
+        return viewHolder.getConvertView();
+    }
+
+    protected void convert(ViewHolder viewHolder, T item, int position) {
+        mItemViewDelegateManager.convert(viewHolder, item, position);
+    }
+
+    public void onViewHolderCreated(ViewHolder holder , View itemView )
+    {}
+
+    @Override
+    public int getCount() {
+        return mDatas.size();
+    }
+
+    @Override
+    public T getItem(int position) {
+        return mDatas.get(position);
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return position;
+    }
+
+
+}

+ 290 - 0
adapter/src/main/java/com/itant/library/abslistview/ViewHolder.java

@@ -0,0 +1,290 @@
+package com.itant.library.abslistview;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.text.util.Linkify;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AlphaAnimation;
+import android.widget.Checkable;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.RatingBar;
+import android.widget.TextView;
+
+public class ViewHolder
+{
+    private SparseArray<View> mViews;
+    protected int mPosition;
+    private View mConvertView;
+    private Context mContext;
+    protected int mLayoutId;
+
+    public ViewHolder(Context context, View itemView, ViewGroup parent, int position)
+    {
+        mContext = context;
+        mConvertView = itemView;
+        mPosition = position;
+        mViews = new SparseArray<View>();
+        mConvertView.setTag(this);
+    }
+
+
+    public static ViewHolder get(Context context, View convertView,
+                                 ViewGroup parent, int layoutId, int position)
+    {
+        if (convertView == null)
+        {
+            View itemView = LayoutInflater.from(context).inflate(layoutId, parent,
+                    false);
+            ViewHolder holder = new ViewHolder(context, itemView, parent, position);
+            holder.mLayoutId = layoutId;
+            return holder;
+        } else
+        {
+            ViewHolder holder = (ViewHolder) convertView.getTag();
+            holder.mPosition = position;
+            return holder;
+        }
+    }
+
+
+    /**
+     * 通过viewId获取控件
+     *
+     * @param viewId
+     * @return
+     */
+    public <T extends View> T getView(int viewId)
+    {
+        View view = mViews.get(viewId);
+        if (view == null)
+        {
+            view = mConvertView.findViewById(viewId);
+            mViews.put(viewId, view);
+        }
+        return (T) view;
+    }
+
+    public View getConvertView()
+    {
+        return mConvertView;
+    }
+
+    public int getLayoutId()
+    {
+        return mLayoutId;
+    }
+
+    public void updatePosition(int position)
+    {
+        mPosition = position;
+    }
+
+    public int getItemPosition()
+    {
+        return mPosition;
+    }
+
+
+    /****以下为辅助方法*****/
+
+    /**
+     * 设置TextView的值
+     *
+     * @param viewId
+     * @param text
+     * @return
+     */
+    public ViewHolder setText(int viewId, String text)
+    {
+        TextView tv = getView(viewId);
+        tv.setText(text);
+        return this;
+    }
+
+    public ViewHolder setImageResource(int viewId, int resId)
+    {
+        ImageView view = getView(viewId);
+        view.setImageResource(resId);
+        return this;
+    }
+
+    public ViewHolder setImageBitmap(int viewId, Bitmap bitmap)
+    {
+        ImageView view = getView(viewId);
+        view.setImageBitmap(bitmap);
+        return this;
+    }
+
+    public ViewHolder setImageDrawable(int viewId, Drawable drawable)
+    {
+        ImageView view = getView(viewId);
+        view.setImageDrawable(drawable);
+        return this;
+    }
+
+    public ViewHolder setBackgroundColor(int viewId, int color)
+    {
+        View view = getView(viewId);
+        view.setBackgroundColor(color);
+        return this;
+    }
+
+    public ViewHolder setBackgroundRes(int viewId, int backgroundRes)
+    {
+        View view = getView(viewId);
+        view.setBackgroundResource(backgroundRes);
+        return this;
+    }
+
+    public ViewHolder setTextColor(int viewId, int textColor)
+    {
+        TextView view = getView(viewId);
+        view.setTextColor(textColor);
+        return this;
+    }
+
+    public ViewHolder setTextColorRes(int viewId, int textColorRes)
+    {
+        TextView view = getView(viewId);
+        view.setTextColor(mContext.getResources().getColor(textColorRes));
+        return this;
+    }
+
+    @SuppressLint("NewApi")
+    public ViewHolder setAlpha(int viewId, float value)
+    {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
+        {
+            getView(viewId).setAlpha(value);
+        } else
+        {
+            // Pre-honeycomb hack to set Alpha value
+            AlphaAnimation alpha = new AlphaAnimation(value, value);
+            alpha.setDuration(0);
+            alpha.setFillAfter(true);
+            getView(viewId).startAnimation(alpha);
+        }
+        return this;
+    }
+
+    public ViewHolder setVisible(int viewId, boolean visible)
+    {
+        View view = getView(viewId);
+        view.setVisibility(visible ? View.VISIBLE : View.GONE);
+        return this;
+    }
+
+    public ViewHolder linkify(int viewId)
+    {
+        TextView view = getView(viewId);
+        Linkify.addLinks(view, Linkify.ALL);
+        return this;
+    }
+
+    public ViewHolder setTypeface(Typeface typeface, int... viewIds)
+    {
+        for (int viewId : viewIds)
+        {
+            TextView view = getView(viewId);
+            view.setTypeface(typeface);
+            view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG);
+        }
+        return this;
+    }
+
+    public ViewHolder setProgress(int viewId, int progress)
+    {
+        ProgressBar view = getView(viewId);
+        view.setProgress(progress);
+        return this;
+    }
+
+    public ViewHolder setProgress(int viewId, int progress, int max)
+    {
+        ProgressBar view = getView(viewId);
+        view.setMax(max);
+        view.setProgress(progress);
+        return this;
+    }
+
+    public ViewHolder setMax(int viewId, int max)
+    {
+        ProgressBar view = getView(viewId);
+        view.setMax(max);
+        return this;
+    }
+
+    public ViewHolder setRating(int viewId, float rating)
+    {
+        RatingBar view = getView(viewId);
+        view.setRating(rating);
+        return this;
+    }
+
+    public ViewHolder setRating(int viewId, float rating, int max)
+    {
+        RatingBar view = getView(viewId);
+        view.setMax(max);
+        view.setRating(rating);
+        return this;
+    }
+
+    public ViewHolder setTag(int viewId, Object tag)
+    {
+        View view = getView(viewId);
+        view.setTag(tag);
+        return this;
+    }
+
+    public ViewHolder setTag(int viewId, int key, Object tag)
+    {
+        View view = getView(viewId);
+        view.setTag(key, tag);
+        return this;
+    }
+
+    public ViewHolder setChecked(int viewId, boolean checked)
+    {
+        Checkable view = (Checkable) getView(viewId);
+        view.setChecked(checked);
+        return this;
+    }
+
+    /**
+     * 关于事件的
+     */
+    public ViewHolder setOnClickListener(int viewId,
+                                         View.OnClickListener listener)
+    {
+        View view = getView(viewId);
+        view.setOnClickListener(listener);
+        return this;
+    }
+
+    public ViewHolder setOnTouchListener(int viewId,
+                                         View.OnTouchListener listener)
+    {
+        View view = getView(viewId);
+        view.setOnTouchListener(listener);
+        return this;
+    }
+
+    public ViewHolder setOnLongClickListener(int viewId,
+                                             View.OnLongClickListener listener)
+    {
+        View view = getView(viewId);
+        view.setOnLongClickListener(listener);
+        return this;
+    }
+
+
+}

+ 20 - 0
adapter/src/main/java/com/itant/library/abslistview/base/ItemViewDelegate.java

@@ -0,0 +1,20 @@
+package com.itant.library.abslistview.base;
+
+
+import com.itant.library.abslistview.ViewHolder;
+
+/**
+ * Created by iTant on 2017/1/15.
+ */
+public interface ItemViewDelegate<T>
+{
+
+    public abstract int getItemViewLayoutId();
+
+    public abstract boolean isForViewType(T item, int position);
+
+    public abstract void convert(ViewHolder holder, T t, int position);
+
+
+
+}

+ 134 - 0
adapter/src/main/java/com/itant/library/abslistview/base/ItemViewDelegateManager.java

@@ -0,0 +1,134 @@
+package com.itant.library.abslistview.base;
+
+
+import androidx.collection.SparseArrayCompat;
+
+import com.itant.library.abslistview.ViewHolder;
+
+
+/**
+ * Created by iTant on 2017/1/15.
+ */
+public class ItemViewDelegateManager<T>
+{
+    SparseArrayCompat<ItemViewDelegate<T>> delegates = new SparseArrayCompat();
+
+    public int getItemViewDelegateCount()
+    {
+        return delegates.size();
+    }
+
+    public ItemViewDelegateManager<T> addDelegate(ItemViewDelegate<T> delegate)
+    {
+        int viewType = delegates.size();
+        if (delegate != null)
+        {
+            delegates.put(viewType, delegate);
+            viewType++;
+        }
+        return this;
+    }
+
+    public ItemViewDelegateManager<T> addDelegate(int viewType, ItemViewDelegate<T> delegate)
+    {
+        if (delegates.get(viewType) != null)
+        {
+            throw new IllegalArgumentException(
+                    "An ItemViewDelegate is already registered for the viewType = "
+                            + viewType
+                            + ". Already registered ItemViewDelegate is "
+                            + delegates.get(viewType));
+        }
+        delegates.put(viewType, delegate);
+        return this;
+    }
+
+    public ItemViewDelegateManager<T> removeDelegate(ItemViewDelegate<T> delegate)
+    {
+        if (delegate == null)
+        {
+            throw new NullPointerException("ItemViewDelegate is null");
+        }
+        int indexToRemove = delegates.indexOfValue(delegate);
+
+        if (indexToRemove >= 0)
+        {
+            delegates.removeAt(indexToRemove);
+        }
+        return this;
+    }
+
+    public ItemViewDelegateManager<T> removeDelegate(int itemType)
+    {
+        int indexToRemove = delegates.indexOfKey(itemType);
+
+        if (indexToRemove >= 0)
+        {
+            delegates.removeAt(indexToRemove);
+        }
+        return this;
+    }
+
+    public int getItemViewType(T item, int position)
+    {
+        int delegatesCount = delegates.size();
+        for (int i = delegatesCount - 1; i >= 0; i--)
+        {
+            ItemViewDelegate<T> delegate = delegates.valueAt(i);
+            if (delegate.isForViewType(item, position))
+            {
+                return delegates.keyAt(i);
+            }
+        }
+        throw new IllegalArgumentException(
+                "No ItemViewDelegate added that matches position=" + position + " in data source");
+    }
+
+    public void convert(ViewHolder holder, T item, int position)
+    {
+        int delegatesCount = delegates.size();
+        for (int i = 0; i < delegatesCount; i++)
+        {
+            ItemViewDelegate<T> delegate = delegates.valueAt(i);
+
+            if (delegate.isForViewType(item, position))
+            {
+                delegate.convert(holder, item, position);
+                return;
+            }
+        }
+        throw new IllegalArgumentException(
+                "No ItemViewDelegateManager added that matches position=" + position + " in data source");
+    }
+
+
+    public int getItemViewLayoutId(int viewType)
+    {
+        return delegates.get(viewType).getItemViewLayoutId();
+    }
+
+    public int getItemViewType(ItemViewDelegate itemViewDelegate)
+    {
+        return delegates.indexOfValue(itemViewDelegate);
+    }
+
+    public ItemViewDelegate getItemViewDelegate(T item, int position)
+    {
+        int delegatesCount = delegates.size();
+        for (int i = delegatesCount - 1; i >= 0; i--)
+        {
+            ItemViewDelegate<T> delegate = delegates.valueAt(i);
+            if (delegate.isForViewType(item, position))
+            {
+                return delegate;
+            }
+        }
+        throw new IllegalArgumentException(
+                "No ItemViewDelegate added that matches position=" + position + " in data source");
+    }
+
+    public int getItemViewLayoutId(T item, int position)
+    {
+        return getItemViewDelegate(item,position).getItemViewLayoutId();
+    }
+}

+ 54 - 0
adapter/src/main/java/com/itant/library/recyclerview/CommonAdapter.java

@@ -0,0 +1,54 @@
+package com.itant.library.recyclerview;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+
+import com.itant.library.recyclerview.base.ItemViewDelegate;
+import com.itant.library.recyclerview.base.ViewHolder;
+
+import java.util.List;
+
+/**
+ * Created by iTant on 2017/1/15.
+ */
+public abstract class CommonAdapter<T> extends MultiItemTypeAdapter<T>
+{
+    protected Context mContext;
+    protected int mLayoutId;
+    protected List<T> mDatas;
+    protected LayoutInflater mInflater;
+
+    public CommonAdapter(final Context context, final int layoutId, List<T> datas)
+    {
+        super(context, datas);
+        mContext = context;
+        mInflater = LayoutInflater.from(context);
+        mLayoutId = layoutId;
+        mDatas = datas;
+
+        addItemViewDelegate(new ItemViewDelegate<T>()
+        {
+            @Override
+            public int getItemViewLayoutId()
+            {
+                return layoutId;
+            }
+
+            @Override
+            public boolean isForViewType( T item, int position)
+            {
+                return true;
+            }
+
+            @Override
+            public void convert(ViewHolder holder, T t, int position)
+            {
+                CommonAdapter.this.convert(holder, t, position);
+            }
+        });
+    }
+
+    protected abstract void convert(ViewHolder holder, T t, int position);
+
+
+}

+ 132 - 0
adapter/src/main/java/com/itant/library/recyclerview/MultiItemTypeAdapter.java

@@ -0,0 +1,132 @@
+package com.itant.library.recyclerview;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.itant.library.recyclerview.base.ItemViewDelegate;
+import com.itant.library.recyclerview.base.ItemViewDelegateManager;
+import com.itant.library.recyclerview.base.ViewHolder;
+
+import java.util.List;
+
+/**
+ * Created by iTant on 2017/1/15.
+ */
+public class MultiItemTypeAdapter<T> extends RecyclerView.Adapter<ViewHolder> {
+    protected Context mContext;
+    protected List<T> mDatas;
+
+    protected ItemViewDelegateManager mItemViewDelegateManager;
+    protected OnItemClickListener mOnItemClickListener;
+
+
+    public MultiItemTypeAdapter(Context context, List<T> datas) {
+        mContext = context;
+        mDatas = datas;
+        mItemViewDelegateManager = new ItemViewDelegateManager();
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        if (!useItemViewDelegateManager()) return super.getItemViewType(position);
+        return mItemViewDelegateManager.getItemViewType(mDatas.get(position), position);
+    }
+
+
+    @Override
+    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        ItemViewDelegate itemViewDelegate = mItemViewDelegateManager.getItemViewDelegate(viewType);
+        int layoutId = itemViewDelegate.getItemViewLayoutId();
+        ViewHolder holder = ViewHolder.createViewHolder(mContext, parent, layoutId);
+        onViewHolderCreated(holder,holder.getConvertView());
+        setListener(parent, holder, viewType);
+        return holder;
+    }
+
+    public void onViewHolderCreated(ViewHolder holder,View itemView){
+
+    }
+
+    public void convert(ViewHolder holder, T t) {
+        mItemViewDelegateManager.convert(holder, t, holder.getAdapterPosition());
+    }
+
+    protected boolean isEnabled(int viewType) {
+        return true;
+    }
+
+
+    protected void setListener(final ViewGroup parent, final ViewHolder viewHolder, int viewType) {
+        if (!isEnabled(viewType)) return;
+        viewHolder.getConvertView().setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mOnItemClickListener != null) {
+                    int position = viewHolder.getAdapterPosition();
+                    mOnItemClickListener.onItemClick(v, viewHolder , position);
+                }
+            }
+        });
+
+        viewHolder.getConvertView().setOnLongClickListener(new View.OnLongClickListener() {
+            @Override
+            public boolean onLongClick(View v) {
+                if (mOnItemClickListener != null) {
+                    int position = viewHolder.getAdapterPosition();
+                    return mOnItemClickListener.onItemLongClick(v, viewHolder, position);
+                }
+                return false;
+            }
+        });
+    }
+
+    private int mLastPosition=-1;// 设为-1是为了让动画从第0个item出现
+    @Override
+    public void onBindViewHolder(ViewHolder holder, int position) {
+        convert(holder, mDatas.get(position));
+        /*if (position > mLastPosition && !isFooterPosition(position)) {
+            // 一个一个出现的动画
+            Animation animation = AnimationUtils.loadAnimation(holder.itemView.getContext(), R.anim.anim_bottom_in);
+            holder.itemView.startAnimation(animation);
+            mLastPosition = position;
+        }*/
+    }
+
+    @Override
+    public int getItemCount() {
+        int itemCount = mDatas.size();
+        return itemCount;
+    }
+
+
+    public List<T> getDatas() {
+        return mDatas;
+    }
+
+    public MultiItemTypeAdapter addItemViewDelegate(ItemViewDelegate<T> itemViewDelegate) {
+        mItemViewDelegateManager.addDelegate(itemViewDelegate);
+        return this;
+    }
+
+    public MultiItemTypeAdapter addItemViewDelegate(int viewType, ItemViewDelegate<T> itemViewDelegate) {
+        mItemViewDelegateManager.addDelegate(viewType, itemViewDelegate);
+        return this;
+    }
+
+    protected boolean useItemViewDelegateManager() {
+        return mItemViewDelegateManager.getItemViewDelegateCount() > 0;
+    }
+
+    public interface OnItemClickListener {
+        void onItemClick(View view, RecyclerView.ViewHolder holder, int position);
+
+        boolean onItemLongClick(View view, RecyclerView.ViewHolder holder, int position);
+    }
+
+    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
+        this.mOnItemClickListener = onItemClickListener;
+    }
+}

+ 16 - 0
adapter/src/main/java/com/itant/library/recyclerview/base/ItemViewDelegate.java

@@ -0,0 +1,16 @@
+package com.itant.library.recyclerview.base;
+
+
+/**
+ * Created by iTant on 2017/1/15.
+ */
+public interface ItemViewDelegate<T>
+{
+
+    int getItemViewLayoutId();
+
+    boolean isForViewType(T item, int position);
+
+    void convert(ViewHolder holder, T t, int position);
+
+}

+ 116 - 0
adapter/src/main/java/com/itant/library/recyclerview/base/ItemViewDelegateManager.java

@@ -0,0 +1,116 @@
+package com.itant.library.recyclerview.base;
+
+
+import androidx.collection.SparseArrayCompat;
+
+/**
+ * Created by iTant on 2017/1/15.
+ */
+public class ItemViewDelegateManager<T>
+{
+    SparseArrayCompat<ItemViewDelegate<T>> delegates = new SparseArrayCompat();
+
+    public int getItemViewDelegateCount()
+    {
+        return delegates.size();
+    }
+
+    public ItemViewDelegateManager<T> addDelegate(ItemViewDelegate<T> delegate)
+    {
+        int viewType = delegates.size();
+        if (delegate != null)
+        {
+            delegates.put(viewType, delegate);
+            viewType++;
+        }
+        return this;
+    }
+
+    public ItemViewDelegateManager<T> addDelegate(int viewType, ItemViewDelegate<T> delegate)
+    {
+        if (delegates.get(viewType) != null)
+        {
+            throw new IllegalArgumentException(
+                    "An ItemViewDelegate is already registered for the viewType = "
+                            + viewType
+                            + ". Already registered ItemViewDelegate is "
+                            + delegates.get(viewType));
+        }
+        delegates.put(viewType, delegate);
+        return this;
+    }
+
+    public ItemViewDelegateManager<T> removeDelegate(ItemViewDelegate<T> delegate)
+    {
+        if (delegate == null)
+        {
+            throw new NullPointerException("ItemViewDelegate is null");
+        }
+        int indexToRemove = delegates.indexOfValue(delegate);
+
+        if (indexToRemove >= 0)
+        {
+            delegates.removeAt(indexToRemove);
+        }
+        return this;
+    }
+
+    public ItemViewDelegateManager<T> removeDelegate(int itemType)
+    {
+        int indexToRemove = delegates.indexOfKey(itemType);
+
+        if (indexToRemove >= 0)
+        {
+            delegates.removeAt(indexToRemove);
+        }
+        return this;
+    }
+
+    public int getItemViewType(T item, int position)
+    {
+        int delegatesCount = delegates.size();
+        for (int i = delegatesCount - 1; i >= 0; i--)
+        {
+            ItemViewDelegate<T> delegate = delegates.valueAt(i);
+            if (delegate.isForViewType( item, position))
+            {
+                return delegates.keyAt(i);
+            }
+        }
+        throw new IllegalArgumentException(
+                "No ItemViewDelegate added that matches position=" + position + " in data source");
+    }
+
+    public void convert(ViewHolder holder, T item, int position)
+    {
+        int delegatesCount = delegates.size();
+        for (int i = 0; i < delegatesCount; i++)
+        {
+            ItemViewDelegate<T> delegate = delegates.valueAt(i);
+
+            if (delegate.isForViewType( item, position))
+            {
+                delegate.convert(holder, item, position);
+                return;
+            }
+        }
+        throw new IllegalArgumentException(
+                "No ItemViewDelegateManager added that matches position=" + position + " in data source");
+    }
+
+
+    public ItemViewDelegate getItemViewDelegate(int viewType)
+    {
+        return delegates.get(viewType);
+    }
+
+    public int getItemViewLayoutId(int viewType)
+    {
+        return getItemViewDelegate(viewType).getItemViewLayoutId();
+    }
+
+    public int getItemViewType(ItemViewDelegate itemViewDelegate)
+    {
+        return delegates.indexOfValue(itemViewDelegate);
+    }
+}

+ 311 - 0
adapter/src/main/java/com/itant/library/recyclerview/base/ViewHolder.java

@@ -0,0 +1,311 @@
+package com.itant.library.recyclerview.base;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.os.Build;
+import android.text.util.Linkify;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AlphaAnimation;
+import android.widget.Checkable;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.RatingBar;
+import android.widget.TextView;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+public class ViewHolder extends RecyclerView.ViewHolder/* implements AnimateViewHolder*/
+{
+    private SparseArray<View> mViews;
+    private View mConvertView;
+    private Context mContext;
+
+    public ViewHolder(Context context, View itemView)
+    {
+        super(itemView);
+        mContext = context;
+        mConvertView = itemView;
+        mViews = new SparseArray<View>();
+    }
+
+
+    public static ViewHolder createViewHolder(Context context, View itemView)
+    {
+        ViewHolder holder = new ViewHolder(context, itemView);
+        return holder;
+    }
+
+    public static ViewHolder createViewHolder(Context context,
+                                              ViewGroup parent, int layoutId)
+    {
+        View itemView = LayoutInflater.from(context).inflate(layoutId, parent,
+                false);
+        ViewHolder holder = new ViewHolder(context, itemView);
+        return holder;
+    }
+
+    /**
+     * 通过viewId获取控件
+     *
+     * @param viewId
+     * @return
+     */
+    public <T extends View> T getView(int viewId)
+    {
+        View view = mViews.get(viewId);
+        if (view == null)
+        {
+            view = mConvertView.findViewById(viewId);
+            mViews.put(viewId, view);
+        }
+        return (T) view;
+    }
+
+    public View getConvertView()
+    {
+        return mConvertView;
+    }
+
+
+
+
+    /****以下为辅助方法*****/
+
+    /**
+     * 设置TextView的值
+     *
+     * @param viewId
+     * @param text
+     * @return
+     */
+    public ViewHolder setText(int viewId, String text)
+    {
+        TextView tv = getView(viewId);
+        tv.setText(text);
+        return this;
+    }
+
+    public ViewHolder setImageResource(int viewId, int resId)
+    {
+        ImageView view = getView(viewId);
+        view.setImageResource(resId);
+        return this;
+    }
+
+    public ViewHolder setImageBitmap(int viewId, Bitmap bitmap)
+    {
+        ImageView view = getView(viewId);
+        view.setImageBitmap(bitmap);
+        return this;
+    }
+
+    public ViewHolder setImageDrawable(int viewId, Drawable drawable)
+    {
+        ImageView view = getView(viewId);
+        view.setImageDrawable(drawable);
+        return this;
+    }
+
+    public ViewHolder setBackgroundColor(int viewId, int color)
+    {
+        View view = getView(viewId);
+        view.setBackgroundColor(color);
+        return this;
+    }
+
+    public ViewHolder setBackgroundRes(int viewId, int backgroundRes)
+    {
+        View view = getView(viewId);
+        view.setBackgroundResource(backgroundRes);
+        return this;
+    }
+
+    public ViewHolder setTextColor(int viewId, int textColor)
+    {
+        TextView view = getView(viewId);
+        view.setTextColor(textColor);
+        return this;
+    }
+
+    public ViewHolder setTextColorRes(int viewId, int textColorRes)
+    {
+        TextView view = getView(viewId);
+        view.setTextColor(mContext.getResources().getColor(textColorRes));
+        return this;
+    }
+
+    @SuppressLint("NewApi")
+    public ViewHolder setAlpha(int viewId, float value)
+    {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
+        {
+            getView(viewId).setAlpha(value);
+        } else
+        {
+            // Pre-honeycomb hack to set Alpha value
+            AlphaAnimation alpha = new AlphaAnimation(value, value);
+            alpha.setDuration(0);
+            alpha.setFillAfter(true);
+            getView(viewId).startAnimation(alpha);
+        }
+        return this;
+    }
+
+    public ViewHolder setVisible(int viewId, boolean visible)
+    {
+        View view = getView(viewId);
+        view.setVisibility(visible ? View.VISIBLE : View.GONE);
+        return this;
+    }
+
+    public ViewHolder linkify(int viewId)
+    {
+        TextView view = getView(viewId);
+        Linkify.addLinks(view, Linkify.ALL);
+        return this;
+    }
+
+    public ViewHolder setTypeface(Typeface typeface, int... viewIds)
+    {
+        for (int viewId : viewIds)
+        {
+            TextView view = getView(viewId);
+            view.setTypeface(typeface);
+            view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG);
+        }
+        return this;
+    }
+
+    public ViewHolder setProgress(int viewId, int progress)
+    {
+        ProgressBar view = getView(viewId);
+        view.setProgress(progress);
+        return this;
+    }
+
+    public ViewHolder setProgress(int viewId, int progress, int max)
+    {
+        ProgressBar view = getView(viewId);
+        view.setMax(max);
+        view.setProgress(progress);
+        return this;
+    }
+
+    public ViewHolder setMax(int viewId, int max)
+    {
+        ProgressBar view = getView(viewId);
+        view.setMax(max);
+        return this;
+    }
+
+    public ViewHolder setRating(int viewId, float rating)
+    {
+        RatingBar view = getView(viewId);
+        LayerDrawable stars = (LayerDrawable) view.getProgressDrawable();
+        stars.getDrawable(2).setColorFilter(Color.parseColor("#eb002f"), PorterDuff.Mode.SRC_ATOP);
+        view.setRating(rating);
+        return this;
+    }
+
+    public ViewHolder setRating(int viewId, float rating, int max)
+    {
+        RatingBar view = getView(viewId);
+        view.setMax(max);
+        view.setRating(rating);
+        return this;
+    }
+
+    public ViewHolder setTag(int viewId, Object tag)
+    {
+        View view = getView(viewId);
+        view.setTag(tag);
+        return this;
+    }
+
+    public ViewHolder setTag(int viewId, int key, Object tag)
+    {
+        View view = getView(viewId);
+        view.setTag(key, tag);
+        return this;
+    }
+
+    public ViewHolder setChecked(int viewId, boolean checked)
+    {
+        Checkable view = (Checkable) getView(viewId);
+        view.setChecked(checked);
+        return this;
+    }
+
+    /**
+     * 关于事件的
+     */
+    public ViewHolder setOnClickListener(int viewId,
+                                         View.OnClickListener listener)
+    {
+        View view = getView(viewId);
+        view.setOnClickListener(listener);
+        return this;
+    }
+
+    public ViewHolder setOnTouchListener(int viewId,
+                                         View.OnTouchListener listener)
+    {
+        View view = getView(viewId);
+        view.setOnTouchListener(listener);
+        return this;
+    }
+
+    public ViewHolder setOnLongClickListener(int viewId,
+                                             View.OnLongClickListener listener)
+    {
+        View view = getView(viewId);
+        view.setOnLongClickListener(listener);
+        return this;
+    }
+
+
+    /*----------------------------------动画----------------------------------*/
+    /*@Override
+    public void preAnimateAddImpl(RecyclerView.ViewHolder holder) {
+        ViewCompat.setTranslationY(itemView, -itemView.getHeight() * 0.3f);
+        ViewCompat.setAlpha(itemView, 0);
+    }
+
+    @Override
+    public void preAnimateRemoveImpl(RecyclerView.ViewHolder holder) {
+
+    }
+
+    @Override
+    public void animateAddImpl(RecyclerView.ViewHolder holder, ViewPropertyAnimatorListener listener) {
+        // 添加的动画
+        ViewCompat.animate(itemView)
+                .translationY(0)
+                .alpha(1)
+                .setDuration(300)
+                .setListener(listener)
+                .start();
+    }
+
+    @Override
+    public void animateRemoveImpl(RecyclerView.ViewHolder holder, ViewPropertyAnimatorListener listener) {
+        // 移除的动画
+        ViewCompat.animate(itemView)
+                .translationY(-itemView.getHeight() * 0.3f)
+                .alpha(0)
+                .setDuration(300)
+                .setListener(listener)
+                .start();
+    }*/
+    /*----------------------------------动画----------------------------------*/
+}

+ 55 - 0
adapter/src/main/java/com/itant/library/recyclerview/utils/WrapperUtils.java

@@ -0,0 +1,55 @@
+package com.itant.library.recyclerview.utils;
+
+
+import android.view.ViewGroup;
+
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.StaggeredGridLayoutManager;
+
+/**
+ * Created by iTant on 2017/1/15.
+ */
+public class WrapperUtils
+{
+    public interface SpanSizeCallback
+    {
+        int getSpanSize(GridLayoutManager layoutManager, GridLayoutManager.SpanSizeLookup oldLookup, int position);
+    }
+
+    public static void onAttachedToRecyclerView(RecyclerView.Adapter innerAdapter, RecyclerView recyclerView, final SpanSizeCallback callback)
+    {
+        innerAdapter.onAttachedToRecyclerView(recyclerView);
+
+        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+        if (layoutManager instanceof GridLayoutManager)
+        {
+            final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
+            final GridLayoutManager.SpanSizeLookup spanSizeLookup = gridLayoutManager.getSpanSizeLookup();
+
+            gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup()
+            {
+                @Override
+                public int getSpanSize(int position)
+                {
+                    return callback.getSpanSize(gridLayoutManager, spanSizeLookup, position);
+                }
+            });
+            gridLayoutManager.setSpanCount(gridLayoutManager.getSpanCount());
+        }
+    }
+
+    public static void setFullSpan(RecyclerView.ViewHolder holder)
+    {
+        ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
+
+        if (lp != null
+                && lp instanceof StaggeredGridLayoutManager.LayoutParams)
+        {
+
+            StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
+
+            p.setFullSpan(true);
+        }
+    }
+}

+ 128 - 0
adapter/src/main/java/com/itant/library/recyclerview/wrapper/EmptyWrapper.java

@@ -0,0 +1,128 @@
+package com.itant.library.recyclerview.wrapper;
+
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.itant.library.recyclerview.base.ViewHolder;
+import com.itant.library.recyclerview.utils.WrapperUtils;
+
+/**
+ * Created by iTant on 2017/1/15.
+ */
+public class EmptyWrapper<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder>
+{
+    public static final int ITEM_TYPE_EMPTY = Integer.MAX_VALUE - 1;
+
+    private RecyclerView.Adapter mInnerAdapter;
+    private View mEmptyView;
+    private int mEmptyLayoutId;
+
+
+    public EmptyWrapper(RecyclerView.Adapter adapter)
+    {
+        mInnerAdapter = adapter;
+    }
+
+    private boolean isEmpty()
+    {
+        return (mEmptyView != null || mEmptyLayoutId != 0) && mInnerAdapter.getItemCount() == 0;
+    }
+
+    @Override
+    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
+    {
+        if (isEmpty())
+        {
+            ViewHolder holder;
+            if (mEmptyView != null)
+            {
+                holder = ViewHolder.createViewHolder(parent.getContext(), mEmptyView);
+            } else
+            {
+                holder = ViewHolder.createViewHolder(parent.getContext(), parent, mEmptyLayoutId);
+            }
+            return holder;
+        }
+        return mInnerAdapter.onCreateViewHolder(parent, viewType);
+    }
+
+    @Override
+    public void onAttachedToRecyclerView(RecyclerView recyclerView)
+    {
+        WrapperUtils.onAttachedToRecyclerView(mInnerAdapter, recyclerView, new WrapperUtils.SpanSizeCallback()
+        {
+            @Override
+            public int getSpanSize(GridLayoutManager gridLayoutManager, GridLayoutManager.SpanSizeLookup oldLookup, int position)
+            {
+                if (isEmpty())
+                {
+                    return gridLayoutManager.getSpanCount();
+                }
+                if (oldLookup != null)
+                {
+                    return oldLookup.getSpanSize(position);
+                }
+                return 1;
+            }
+        });
+
+
+    }
+
+    @Override
+    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder)
+    {
+        mInnerAdapter.onViewAttachedToWindow(holder);
+        if (isEmpty())
+        {
+            WrapperUtils.setFullSpan(holder);
+        }
+    }
+
+
+    @Override
+    public int getItemViewType(int position)
+    {
+        if (isEmpty())
+        {
+            return ITEM_TYPE_EMPTY;
+        }
+        return mInnerAdapter.getItemViewType(position);
+    }
+
+    @Override
+    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
+    {
+        if (isEmpty())
+        {
+            return;
+        }
+        mInnerAdapter.onBindViewHolder(holder, position);
+    }
+
+    @Override
+    public int getItemCount()
+    {
+        if (isEmpty()) {
+            return 1;
+        }
+        return mInnerAdapter.getItemCount();
+    }
+
+
+
+    public void setEmptyView(View emptyView)
+    {
+        mEmptyView = emptyView;
+    }
+
+    public void setEmptyView(int layoutId)
+    {
+        mEmptyLayoutId = layoutId;
+    }
+
+}

+ 152 - 0
adapter/src/main/java/com/itant/library/recyclerview/wrapper/HeaderAndFooterWrapper.java

@@ -0,0 +1,152 @@
+package com.itant.library.recyclerview.wrapper;
+
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.collection.SparseArrayCompat;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.itant.library.recyclerview.base.ViewHolder;
+import com.itant.library.recyclerview.utils.WrapperUtils;
+
+
+public class HeaderAndFooterWrapper<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder>
+{
+    private static final int BASE_ITEM_TYPE_HEADER = 100000;
+    private static final int BASE_ITEM_TYPE_FOOTER = 200000;
+
+    private SparseArrayCompat<View> mHeaderViews = new SparseArrayCompat<>();
+    private SparseArrayCompat<View> mFootViews = new SparseArrayCompat<>();
+
+    private RecyclerView.Adapter mInnerAdapter;
+
+    public HeaderAndFooterWrapper(RecyclerView.Adapter adapter)
+    {
+        mInnerAdapter = adapter;
+    }
+
+    @Override
+    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
+    {
+        if (mHeaderViews.get(viewType) != null)
+        {
+            ViewHolder holder = ViewHolder.createViewHolder(parent.getContext(), mHeaderViews.get(viewType));
+            return holder;
+
+        } else if (mFootViews.get(viewType) != null)
+        {
+            ViewHolder holder = ViewHolder.createViewHolder(parent.getContext(), mFootViews.get(viewType));
+            return holder;
+        }
+        return mInnerAdapter.onCreateViewHolder(parent, viewType);
+    }
+
+    @Override
+    public int getItemViewType(int position)
+    {
+        if (isHeaderViewPos(position))
+        {
+            return mHeaderViews.keyAt(position);
+        } else if (isFooterViewPos(position))
+        {
+            return mFootViews.keyAt(position - getHeadersCount() - getRealItemCount());
+        }
+        return mInnerAdapter.getItemViewType(position - getHeadersCount());
+    }
+
+    private int getRealItemCount()
+    {
+        return mInnerAdapter.getItemCount();
+    }
+
+
+    @Override
+    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
+    {
+        if (isHeaderViewPos(position))
+        {
+            return;
+        }
+        if (isFooterViewPos(position))
+        {
+            return;
+        }
+        mInnerAdapter.onBindViewHolder(holder, position - getHeadersCount());
+    }
+
+    @Override
+    public int getItemCount()
+    {
+        return getHeadersCount() + getFootersCount() + getRealItemCount();
+    }
+
+    @Override
+    public void onAttachedToRecyclerView(RecyclerView recyclerView)
+    {
+        WrapperUtils.onAttachedToRecyclerView(mInnerAdapter, recyclerView, new WrapperUtils.SpanSizeCallback()
+        {
+            @Override
+            public int getSpanSize(GridLayoutManager layoutManager, GridLayoutManager.SpanSizeLookup oldLookup, int position)
+            {
+                int viewType = getItemViewType(position);
+                if (mHeaderViews.get(viewType) != null)
+                {
+                    return layoutManager.getSpanCount();
+                } else if (mFootViews.get(viewType) != null)
+                {
+                    return layoutManager.getSpanCount();
+                }
+                if (oldLookup != null) {
+                    return oldLookup.getSpanSize(position);
+                }
+                return 1;
+            }
+        });
+    }
+
+    @Override
+    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder)
+    {
+        mInnerAdapter.onViewAttachedToWindow(holder);
+        int position = holder.getLayoutPosition();
+        if (isHeaderViewPos(position) || isFooterViewPos(position))
+        {
+            WrapperUtils.setFullSpan(holder);
+        }
+    }
+
+    private boolean isHeaderViewPos(int position)
+    {
+        return position < getHeadersCount();
+    }
+
+    private boolean isFooterViewPos(int position)
+    {
+        return position >= getHeadersCount() + getRealItemCount();
+    }
+
+
+    public void addHeaderView(View view)
+    {
+        mHeaderViews.put(mHeaderViews.size() + BASE_ITEM_TYPE_HEADER, view);
+    }
+
+    public void addFootView(View view)
+    {
+        mFootViews.put(mFootViews.size() + BASE_ITEM_TYPE_FOOTER, view);
+    }
+
+    public int getHeadersCount()
+    {
+        return mHeaderViews.size();
+    }
+
+    public int getFootersCount()
+    {
+        return mFootViews.size();
+    }
+
+
+}

+ 161 - 0
adapter/src/main/java/com/itant/library/recyclerview/wrapper/LoadMoreWrapper.java

@@ -0,0 +1,161 @@
+package com.itant.library.recyclerview.wrapper;
+
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.StaggeredGridLayoutManager;
+
+import com.itant.library.recyclerview.base.ViewHolder;
+import com.itant.library.recyclerview.utils.WrapperUtils;
+
+
+public class LoadMoreWrapper<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder>
+{
+    public static final int ITEM_TYPE_LOAD_MORE = Integer.MAX_VALUE - 2;
+
+    private RecyclerView.Adapter mInnerAdapter;
+    private View mLoadMoreView;
+    private int mLoadMoreLayoutId;
+
+    public LoadMoreWrapper(RecyclerView.Adapter adapter)
+    {
+        mInnerAdapter = adapter;
+    }
+
+    private boolean hasLoadMore()
+    {
+        return mLoadMoreView != null || mLoadMoreLayoutId != 0;
+    }
+
+
+    private boolean isShowLoadMore(int position)
+    {
+        return hasLoadMore() && (position >= mInnerAdapter.getItemCount());
+    }
+
+    @Override
+    public int getItemViewType(int position)
+    {
+        if (isShowLoadMore(position))
+        {
+            return ITEM_TYPE_LOAD_MORE;
+        }
+        return mInnerAdapter.getItemViewType(position);
+    }
+
+    @Override
+    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
+    {
+        if (viewType == ITEM_TYPE_LOAD_MORE)
+        {
+            ViewHolder holder;
+            if (mLoadMoreView != null)
+            {
+                holder = ViewHolder.createViewHolder(parent.getContext(), mLoadMoreView);
+            } else
+            {
+                holder = ViewHolder.createViewHolder(parent.getContext(), parent, mLoadMoreLayoutId);
+            }
+            return holder;
+        }
+        return mInnerAdapter.onCreateViewHolder(parent, viewType);
+    }
+
+    @Override
+    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
+    {
+        if (isShowLoadMore(position))
+        {
+            if (mOnLoadMoreListener != null)
+            {
+                mOnLoadMoreListener.onLoadMoreRequested();
+            }
+            return;
+        }
+        mInnerAdapter.onBindViewHolder(holder, position);
+    }
+
+    @Override
+    public void onAttachedToRecyclerView(RecyclerView recyclerView)
+    {
+        WrapperUtils.onAttachedToRecyclerView(mInnerAdapter, recyclerView, new WrapperUtils.SpanSizeCallback()
+        {
+            @Override
+            public int getSpanSize(GridLayoutManager layoutManager, GridLayoutManager.SpanSizeLookup oldLookup, int position)
+            {
+                if (isShowLoadMore(position))
+                {
+                    return layoutManager.getSpanCount();
+                }
+                if (oldLookup != null)
+                {
+                    return oldLookup.getSpanSize(position);
+                }
+                return 1;
+            }
+        });
+    }
+
+
+    @Override
+    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder)
+    {
+        mInnerAdapter.onViewAttachedToWindow(holder);
+
+        if (isShowLoadMore(holder.getLayoutPosition()))
+        {
+            setFullSpan(holder);
+        }
+    }
+
+    private void setFullSpan(RecyclerView.ViewHolder holder)
+    {
+        ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
+
+        if (lp != null
+                && lp instanceof StaggeredGridLayoutManager.LayoutParams)
+        {
+            StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
+
+            p.setFullSpan(true);
+        }
+    }
+
+    @Override
+    public int getItemCount()
+    {
+        return mInnerAdapter.getItemCount() + (hasLoadMore() ? 1 : 0);
+    }
+
+
+    public interface OnLoadMoreListener
+    {
+        void onLoadMoreRequested();
+    }
+
+    private OnLoadMoreListener mOnLoadMoreListener;
+
+    public LoadMoreWrapper setOnLoadMoreListener(OnLoadMoreListener loadMoreListener)
+    {
+        if (loadMoreListener != null)
+        {
+            mOnLoadMoreListener = loadMoreListener;
+        }
+        return this;
+    }
+
+    public LoadMoreWrapper setLoadMoreView(View loadMoreView)
+    {
+        mLoadMoreView = loadMoreView;
+        return this;
+    }
+
+    public LoadMoreWrapper setLoadMoreView(int layoutId)
+    {
+        mLoadMoreLayoutId = layoutId;
+        return this;
+    }
+}

+ 13 - 0
adapter/src/main/res/anim/anim_bottom_in.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:duration="500">
+
+    <translate
+        android:fromYDelta="50%"
+        android:toYDelta="0%"/>
+
+    <alpha
+        android:fromAlpha="0.5"
+        android:toAlpha="1"/>
+
+</set>

+ 4 - 0
adapter/src/main/res/values-v21/dimen.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <dimen name="fab_margin">16dp</dimen>
+</resources>

+ 11 - 0
adapter/src/main/res/values/color.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="color_primary_red">#f44336</color>
+    <color name="color_primary_red_dark">#d32f2f</color>
+    <color name="color_primary_green"> #4caf50</color>
+    <color name="color_primary_green_dark">#388e3c</color>
+    <color name="color_primary_blue">#2196f3</color>
+    <color name="color_primary_blue_dark">#1976d2</color>
+    <color name="color_accent_pink">#ff4081</color>
+    <color name="color_shadow">#44000000</color>
+</resources>

+ 5 - 0
adapter/src/main/res/values/dimen.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <dimen name="tabsHeight">48dp</dimen>
+    <dimen name="fab_margin">0dp</dimen>
+</resources>

+ 3 - 0
adapter/src/main/res/values/strings.xml

@@ -0,0 +1,3 @@
+<resources>
+    <string name="app_name">Library</string>
+</resources>

+ 22 - 0
adapter/src/main/res/values/styles.xml

@@ -0,0 +1,22 @@
+<resources>
+
+    <style name="CustomTheme" parent="Theme.AppCompat.Light.NoActionBar">
+    </style>
+
+    <style name="AppThemeRed" parent="CustomTheme">
+        <item name="colorPrimary">@color/color_primary_red</item>
+        <item name="colorPrimaryDark">@color/color_primary_red_dark</item>
+    </style>
+
+    <style name="AppThemeGreen" parent="CustomTheme">
+        <item name="colorPrimary">@color/color_primary_green</item>
+        <item name="colorPrimaryDark">@color/color_primary_green_dark</item>
+    </style>
+
+    <style name="AppThemeBlue" parent="CustomTheme">
+        <item name="colorPrimary">@color/color_primary_blue</item>
+        <item name="colorPrimaryDark">@color/color_primary_blue_dark</item>
+        <item name="colorAccent">@color/color_accent_pink</item>
+    </style>
+
+</resources>

+ 195 - 0
app/app.iml

@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
+  <component name="FacetManager">
+    <facet type="android-gradle" name="Android-Gradle">
+      <configuration>
+        <option name="GRADLE_PROJECT_PATH" value=":app" />
+        <option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="3.5.2" />
+        <option name="LAST_KNOWN_AGP_VERSION" value="3.5.2" />
+      </configuration>
+    </facet>
+    <facet type="android" name="Android">
+      <configuration>
+        <option name="SELECTED_BUILD_VARIANT" value="relRelease" />
+        <option name="ASSEMBLE_TASK_NAME" value="assembleRelRelease" />
+        <option name="COMPILE_JAVA_TASK_NAME" value="compileRelReleaseSources" />
+        <afterSyncTasks>
+          <task>generateRelReleaseSources</task>
+        </afterSyncTasks>
+        <option name="ALLOW_USER_CONFIGURATION" value="false" />
+        <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
+        <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
+        <option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res;file://$MODULE_DIR$/build/generated/res/resValues/rel/release" />
+        <option name="TEST_RES_FOLDERS_RELATIVE_PATH" value="" />
+        <option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
+      </configuration>
+    </facet>
+  </component>
+  <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
+    <output url="file://$MODULE_DIR$/build/intermediates/javac/relRelease/classes" />
+    <output-test url="file://$MODULE_DIR$/build/intermediates/javac/relReleaseUnitTest/classes" />
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/relRelease/out" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/relRelease/compileRelReleaseAidl/out" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/rel/release" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/relRelease/compileRelReleaseRenderscript/out" isTestSource="false" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/rel/release" type="java-resource" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/rel/release" type="java-resource" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/relRelease/res" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/relRelease/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/relRelease/assets" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/relRelease/aidl" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/relRelease/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/relRelease/rs" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/relRelease/shaders" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/relReleaseUnitTest/out" isTestSource="true" generated="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelRelease/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelRelease/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelRelease/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelRelease/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelRelease/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelRelease/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelRelease/shaders" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/rel/res" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/rel/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/rel/assets" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/rel/aidl" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/rel/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/rel/rs" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/rel/shaders" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTestRel/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTestRel/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTestRel/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTestRel/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTestRel/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTestRel/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTestRel/shaders" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRel/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRel/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRel/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRel/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRel/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRel/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRel/shaders" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/release/res" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/release/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/release/assets" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/release/aidl" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/release/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/release/rs" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/release/shaders" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelease/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelease/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelease/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelease/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelease/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelease/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/testRelease/shaders" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
+      <sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
+      <excludeFolder url="file://$MODULE_DIR$/build" />
+    </content>
+    <orderEntry type="jdk" jdkName="Android API 29 Platform" jdkType="Android SDK" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" scope="TEST" name="Gradle: junit:junit:4.12@jar" level="project" />
+    <orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-core:1.3@jar" level="project" />
+    <orderEntry type="library" name="Gradle: com.umeng.umsdk:common:9.1.0@jar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.collection:collection:1.1.0@jar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.arch.core:core-common:2.1.0@jar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-common:2.3.0-alpha03@jar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.annotation:annotation:1.2.0-alpha01@jar" level="project" />
+    <orderEntry type="library" name="Gradle: com.trello.rxlifecycle3:rxlifecycle:3.1.0@jar" level="project" />
+    <orderEntry type="library" name="Gradle: com.squareup.retrofit2:adapter-rxjava2:2.2.0@jar" level="project" />
+    <orderEntry type="library" name="Gradle: io.reactivex.rxjava2:rxjava:2.2.17@jar" level="project" />
+    <orderEntry type="library" name="Gradle: org.reactivestreams:reactive-streams:1.0.3@jar" level="project" />
+    <orderEntry type="library" name="Gradle: com.github.bumptech.glide:disklrucache:4.11.0@jar" level="project" />
+    <orderEntry type="library" name="Gradle: com.github.bumptech.glide:annotations:4.11.0@jar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.constraintlayout:constraintlayout-solver:1.1.3@jar" level="project" />
+    <orderEntry type="library" name="Gradle: com.squareup.retrofit2:converter-gson:2.2.0@jar" level="project" />
+    <orderEntry type="library" name="Gradle: com.squareup.retrofit2:retrofit:2.7.1@jar" level="project" />
+    <orderEntry type="library" name="Gradle: com.squareup.okhttp3:logging-interceptor:3.6.0@jar" level="project" />
+    <orderEntry type="library" name="Gradle: com.squareup.okhttp3:okhttp:3.14.4@jar" level="project" />
+    <orderEntry type="library" name="Gradle: com.squareup.okio:okio:1.17.2@jar" level="project" />
+    <orderEntry type="library" name="Gradle: com.google.code.gson:gson:2.7@jar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.constraintlayout:constraintlayout:1.1.3@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.swiperefreshlayout:swiperefreshlayout:1.1.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: com.github.VictorAlbertos:RxActivityResult:0.5.0-2.x@aar" level="project" />
+    <orderEntry type="library" name="Gradle: com.umeng.umsdk:asms:1.1.3@aar" level="project" />
+    <orderEntry type="library" name="Gradle: com.umeng.umsdk:crash:0.0.4@aar" level="project" />
+    <orderEntry type="library" name="Gradle: com.makeramen:roundedimageview:2.3.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: cn.jzvd:jiaozivideoplayer:7.4.2@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.navigation:navigation-ui:2.2.2@aar" level="project" />
+    <orderEntry type="library" name="Gradle: com.google.android.material:material:1.1.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: com.trello.rxlifecycle3:rxlifecycle-components:3.1.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.appcompat:appcompat:1.3.0-alpha01@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.appcompat:appcompat-resources:1.3.0-alpha01@aar" level="project" />
+    <orderEntry type="library" name="Gradle: com.github.bumptech.glide:glide:4.11.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable-animated:1.1.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable:1.1.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.drawerlayout:drawerlayout:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.navigation:navigation-fragment:2.2.2@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-extensions:2.2.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.viewpager2:viewpager2:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.fragment:fragment:1.2.4@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.coordinatorlayout:coordinatorlayout:1.1.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.transition:transition:1.2.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.recyclerview:recyclerview:1.1.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.viewpager:viewpager:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.customview:customview:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.loader:loader:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.navigation:navigation-runtime:2.2.2@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.activity:activity:1.1.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.navigation:navigation-common:2.2.2@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.core:core:1.4.0-alpha01@aar" level="project" />
+    <orderEntry type="library" name="Gradle: com.github.zhaokaiqiang.klog:library:1.6.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: com.trello.rxlifecycle3:rxlifecycle-android:3.1.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.interpolator:interpolator:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.versionedparcelable:versionedparcelable:1.1.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-process:2.2.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-service:2.2.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-runtime:2.3.0-alpha03@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.cursoradapter:cursoradapter:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.cardview:cardview:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata:2.2.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata-core:2.2.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.arch.core:core-runtime:2.1.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-viewmodel:2.3.0-alpha03@aar" level="project" />
+    <orderEntry type="library" name="Gradle: com.github.bumptech.glide:gifdecoder:4.11.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.exifinterface:exifinterface:1.0.0@aar" level="project" />
+    <orderEntry type="library" name="Gradle: androidx.savedstate:savedstate:1.1.0-alpha01@aar" level="project" />
+    <orderEntry type="library" name="Gradle: io.reactivex.rxjava2:rxandroid:2.1.1@aar" level="project" />
+    <orderEntry type="library" name="Gradle: com.flyco.tablayout:FlycoTabLayout_Lib:2.1.2@aar" level="project" />
+    <orderEntry type="library" name="Gradle: com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.50@aar" level="project" />
+    <orderEntry type="library" name="Gradle: com.readystatesoftware.chuck:library-no-op:1.1.0@aar" level="project" />
+    <orderEntry type="module" module-name="common" />
+    <orderEntry type="module" module-name="network" />
+    <orderEntry type="module" module-name="mvp" />
+    <orderEntry type="module" module-name="common" />
+    <orderEntry type="module" module-name="network" />
+    <orderEntry type="module" module-name="mvp" />
+    <orderEntry type="module" module-name="common" />
+    <orderEntry type="module" module-name="network" />
+    <orderEntry type="module" module-name="mvp" />
+  </component>
+</module>

+ 125 - 0
app/build.gradle

@@ -0,0 +1,125 @@
+apply plugin: 'com.android.application'
+//apply plugin: 'kotlin-android-extensions'
+//apply plugin: 'kotlin-android'
+
+android {
+    compileSdkVersion versions.compileSdk
+    buildToolsVersion versions.buildTools
+
+    defaultConfig {
+        minSdkVersion versions.minSdk
+        targetSdkVersion versions.targetSdk
+        applicationId "com.itant.shibei"
+        versionCode 5
+        versionName "1.5"
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+
+        // 支持64位架构(上架谷歌市场必要条件),'x86_64','x86'
+        ndk.abiFilters 'armeabi-v7a','arm64-v8a'
+    }
+
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+
+
+    signingConfigs {
+        config {
+            storeFile file('commonkey')
+            storePassword "away6899458"
+            keyAlias "sz"
+            keyPassword "away6899458"
+        }
+    }
+
+    flavorDimensions "url"
+    productFlavors {
+        dev {
+            // 开发环境宿舍服务器
+            buildConfigField("String", "BASE_URL", '"http://192.168.0.190:8080/"')
+        }
+
+        rel {
+            // 正式上线
+            buildConfigField("String", "BASE_URL", '"http://app.jianjie.life:11111/"')
+        }
+
+        company {
+            // 开发2
+            buildConfigField("String", "BASE_URL", '"http://10.16.0.184:8080/"')
+        }
+    }
+
+    buildTypes {
+        debug {
+
+        }
+        release {
+            signingConfig signingConfigs.config
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+        }
+    }
+
+    // 定义输出的APK名字
+    android.applicationVariants.all { variant ->
+        variant.outputs.all {
+            outputFileName = "Shibei_v${defaultConfig.versionName}.apk"
+        }
+    }
+}
+
+//implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
+//增加'*.aar'就不用在android节点写下面的了:
+/* repositories {
+     flatDir {
+         dirs 'libs'
+     }
+ }*/
+dependencies {
+    implementation fileTree(dir: 'libs', include: ['*.jar'])
+    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+
+    testImplementation 'junit:junit:4.12'
+    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+
+    api project(path: ':common')
+    implementation project(path: ':network')
+    implementation project(path: ':mvp')
+    //compile "androidx.core:core-ktx:+"
+    //compile "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+    //implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+    implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
+
+    // RxActivityResult
+    implementation 'com.github.VictorAlbertos:RxActivityResult:0.5.0-2.x'
+
+    // 调试过程中可以查看详细的网络请求与相应
+    debugImplementation 'com.readystatesoftware.chuck:library:1.1.0'
+    releaseImplementation 'com.readystatesoftware.chuck:library-no-op:1.1.0'
+
+    // 友盟
+    implementation "com.umeng.umsdk:common:9.1.0" //(必选)
+    implementation "com.umeng.umsdk:asms:1.1.3" // asms包依赖(必选)
+    implementation "com.umeng.umsdk:crash:0.0.4" // native crash包依赖(必选)
+
+    // Jsoup解析网页
+    //implementation 'org.jsoup:jsoup:1.13.1'
+
+    // 圆角图片
+    //implementation 'de.hdodenhof:circleimageview:3.1.0'
+    implementation 'com.makeramen:roundedimageview:2.3.0'
+
+    // 文字对齐
+    //implementation 'me.codeboy.android:align-text-view:2.3.2'
+
+    //饺子视频播放器
+    //implementation (name: 'jiaozivideoplayer-7.4.2', ext: 'aar')
+    implementation 'cn.jzvd:jiaozivideoplayer:7.4.2'
+}
+repositories {
+    mavenCentral()
+}
+


BIN
app/libs/jiaozivideoplayer-7.4.2.aar


+ 21 - 0
app/proguard-rules.pro

@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# 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

+ 27 - 0
app/src/androidTest/java/com/itant/shibei/ExampleInstrumentedTest.java

@@ -0,0 +1,27 @@
+package com.itant.shibei;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+    @Test
+    public void useAppContext() {
+        // Context of the app under test.
+        Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+        assertEquals("com.itant.shibei", appContext.getPackageName());
+    }
+}

+ 96 - 0
app/src/main/AndroidManifest.xml

@@ -0,0 +1,96 @@
+<?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.itant.shibei">
+
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
+    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+
+    <application
+        android:allowBackup="false"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:supportsRtl="true"
+        android:theme="@style/AppTheme"
+        tools:ignore="GoogleAppIndexingWarning"
+        android:requestLegacyExternalStorage="true"
+        android:networkSecurityConfig="@xml/network"
+        android:name=".ui.BeiApplication">
+        <activity
+            android:name=".ui.TabActivity"
+            android:label="@string/app_name"
+            android:screenOrientation="portrait"
+            android:theme="@style/SplashTheme">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
+            android:name=".ui.mine.login.LoginActivity"
+            android:screenOrientation="portrait"
+            android:theme="@style/TextInputStyle"/>
+
+        <activity
+            android:name=".ui.mine.register.RegisterActivity"
+            android:screenOrientation="portrait"
+            android:theme="@style/TextInputStyle"
+            android:windowSoftInputMode="stateVisible|adjustResize"/>
+
+        <activity
+            android:name=".ui.mine.register.fill.FillDataActivity"
+            android:screenOrientation="portrait"
+            android:theme="@style/TextInputStyle" />
+
+        <activity
+            android:name=".ui.mine.forget.ForgetActivity"
+            android:screenOrientation="portrait"
+            android:theme="@style/TextInputStyle" />
+
+        <activity
+            android:name=".ui.mine.MineActivity"
+            android:screenOrientation="portrait"
+            android:theme="@style/TextInputStyle" />
+
+        <activity
+            android:name=".ui.mine.goods.AddGoodsActivity"
+            android:screenOrientation="portrait"
+            android:theme="@style/TextInputStyle" />
+
+        <activity
+            android:name=".ui.mine.coupon.AddCouponActivity"
+            android:screenOrientation="portrait"
+            android:theme="@style/TextInputStyle" />
+
+        <activity
+            android:name=".ui.home.search.SearchActivity"
+            android:screenOrientation="portrait"
+            android:theme="@style/TextInputStyle" />
+
+        <activity
+            android:name=".ui.home.tool.json.JsonActivity"
+            android:screenOrientation="portrait"
+            android:theme="@style/TextInputStyle" />
+
+        <activity
+            android:name=".ui.home.tool.weather.WeatherActivity"
+            android:screenOrientation="portrait"
+            android:theme="@style/TextInputStyle" />
+
+        <activity
+            android:name=".ui.home.tool.yiji.YijiActivity"
+            android:screenOrientation="portrait"
+            android:theme="@style/TextInputStyle" />
+
+        <activity
+            android:name=".ui.home.goods.play.VideoPlayActivity"
+            android:configChanges="orientation|screenSize|keyboardHidden"
+            android:screenOrientation="landscape"
+            android:theme="@android:style/Theme.Light.NoTitleBar.Fullscreen" />
+    </application>
+
+</manifest>

+ 32 - 0
app/src/main/java/com/itant/shibei/adapter/FragmentPagerItemAdapter.java

@@ -0,0 +1,32 @@
+package com.itant.shibei.adapter;
+
+
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentPagerAdapter;
+
+import java.util.List;
+
+/**
+ * Created by Jason on 2018/5/19.
+ */
+
+public class FragmentPagerItemAdapter extends FragmentPagerAdapter {
+
+    private List<Fragment> fragmentList;
+
+    public FragmentPagerItemAdapter(FragmentManager fm, List<Fragment> fragmentList) {
+        super(fm);
+        this.fragmentList = fragmentList;
+    }
+
+    @Override
+    public Fragment getItem(int position) {
+        return fragmentList.get(position);
+    }
+
+    @Override
+    public int getCount() {
+        return fragmentList.size();
+    }
+}

+ 104 - 0
app/src/main/java/com/itant/shibei/base/ApiService.java

@@ -0,0 +1,104 @@
+package com.itant.shibei.base;
+
+import com.itant.shibei.bean.BeiUser;
+import com.itant.shibei.bean.SystemBean;
+import com.itant.shibei.bean.UpgradeBean;
+import com.itant.shibei.ui.home.coupon.CouponBean;
+import com.itant.shibei.ui.home.goods.GoodsBean;
+import com.itant.shibei.ui.home.tool.json.JsonBean;
+import com.miekir.network.core.base.BaseResponse;
+
+import java.util.List;
+import java.util.Map;
+
+import io.reactivex.Observable;
+import retrofit2.http.Body;
+import retrofit2.http.GET;
+import retrofit2.http.POST;
+import retrofit2.http.Query;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/8/2 10:38
+ * Description: 请求接口
+ */
+public interface ApiService {
+
+    /**请求验证码*/
+    @GET("/shibei/api/code")
+    Observable<BaseResponse<Boolean>> getCode(@Query("email") String email);
+
+    /**注册*/
+    //@Headers({ "Content-Type: application/json;charset=UTF-8"})
+    @POST("/shibei/api/register")
+    Observable<BaseResponse<BeiUser>> submitRegister(@Body Map<String, Object> body);
+
+    /**邮箱+加密的密码 登录*/
+    @POST("/shibei/api/login/normal")
+    Observable<BaseResponse<BeiUser>> submitLogin(@Query("email") String email, @Query("password") String password);
+
+    /**忘记密码*/
+    @POST("/shibei/api/password")
+    Observable<BaseResponse<BeiUser>> resetPassword(@Body Map<String, Object> body);
+
+    /*----------------------------------------京东商品开始----------------------------------------*/
+    /**新增京东商品*/
+    @POST("/shibei/api/addGoods")
+    Observable<BaseResponse<String>> addGoods(@Body GoodsBean body);
+
+    /**删除京东商品*/
+    @GET("/shibei/api/deleteGoodsById")
+    Observable<BaseResponse<String>> deleteGoodsById(@Query("goodsId") long goodsId);
+
+    /**分页查询京东商品*/
+    @GET("/shibei/api/getGoodsList")
+    Observable<BaseResponse<List<GoodsBean>>> getGoodsList(@Query("pageNum") int pageNum, @Query("pageSize") int pageSize);
+
+    /**根据关键字分页查询京东商品*/
+    @GET("/shibei/api/getGoodsListByKeyword")
+    Observable<BaseResponse<List<GoodsBean>>> getGoodsListByKeyword(@Query("keywords") String keyword, @Query("pageNum") int pageNum, @Query("pageSize") int pageSize);
+
+    /**根据链接查询京东商品*/
+    //@GET("/shibei/api/getGoodsByUrl")
+    //Observable<BaseResponse<GoodsBean>> getGoodsByUrl(@Query("url") String url, @Query("pageNum") int pageNum, @Query("pageSize") int pageSize);
+
+    /*----------------------------------------优惠券开始----------------------------------------*/
+    /**新增优惠券*/
+    @POST("/shibei/api/addCoupon")
+    Observable<BaseResponse<String>> addCoupon(@Body CouponBean body);
+
+    /**删除优惠券*/
+    @GET("/shibei/api/deleteCouponById")
+    Observable<BaseResponse<String>> deleteCouponById(@Query("couponId") long goodsId);
+
+    /**分页查询优惠券*/
+    @GET("/shibei/api/getCouponList")
+    Observable<BaseResponse<List<CouponBean>>> getCouponList(@Query("pageNum") int pageNum, @Query("pageSize") int pageSize);
+
+    /*----------------------------------------JSON开始----------------------------------------*/
+    /**保存和更新JSON*/
+    @POST("/shibei/api/saveJson")
+    Observable<BaseResponse<JsonBean>> saveJson(@Body JsonBean body);
+
+    /**获取JSON bean*/
+    @GET("/shibei/api/getJsonBean")
+    Observable<BaseResponse<JsonBean>> getJsonBean();
+
+    /*----------------------------------------升级信息----------------------------------------*/
+    /**获取版本更新信息*/
+    @GET("/shibei/api/getUpgradeInfo")
+    Observable<BaseResponse<UpgradeBean>> getUpgradeInfo();
+
+    /*----------------------------------------系统配置信息----------------------------------------*/
+    /**获取系统配置信息*/
+    @GET("/shibei/api/getSystemConfig")
+    Observable<BaseResponse<SystemBean>> getSystemConfig();
+
+    /**设置是否VIP才能用API*/
+    @POST("/shibei/api/setApiConfig")
+    Observable<BaseResponse<String>> setApiConfig(@Query("isApiVipOnly") boolean isApiVipOnly);
+
+
+}

+ 58 - 0
app/src/main/java/com/itant/shibei/base/BaseBeiActivity.java

@@ -0,0 +1,58 @@
+package com.itant.shibei.base;
+
+import android.os.Build;
+import android.os.Bundle;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.widget.Toolbar;
+
+import com.itant.shibei.R;
+import com.miekir.mvp.view.BaseMVPActivity;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/6/18 16:47
+ * Description: 界面基类
+ */
+public abstract class BaseBeiActivity extends BaseMVPActivity {
+    private View iv_done;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        // 状态栏深色模式,改变状态栏文字颜色
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+        }
+    }
+
+    protected void setOnDoneListener(View.OnClickListener onDoneListener) {
+        if (iv_done == null) {
+            return;
+        }
+        iv_done.setVisibility(View.VISIBLE);
+        iv_done.setOnClickListener(onDoneListener);
+    }
+    protected void setTitle(String title) {
+        //iv_done = findViewById(R.id.iv_done);
+        Toolbar toolbar = findViewById(R.id.toolbar);
+        if (toolbar == null) {
+            return;
+        }
+        toolbar.setTitle(title);
+        //toolbar.setTitleTextColor(getResources().getColor(R.color.black_theme));
+
+        setSupportActionBar(toolbar);
+        //关键下面两句话,设置了回退按钮,及点击事件的效果
+        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                finish();
+            }
+        });
+    }
+}

+ 11 - 0
app/src/main/java/com/itant/shibei/base/ITopActionListener.java

@@ -0,0 +1,11 @@
+package com.itant.shibei.base;
+
+/**
+ *
+ * @author Miekir
+ * @date 2020/8/2 9:19
+ * Description: 监听滚动到顶部的动作
+ */
+public interface ITopActionListener {
+    void onTopAction();
+}

+ 5 - 0
app/src/main/java/com/itant/shibei/base/ItemLongClickListener.java

@@ -0,0 +1,5 @@
+package com.itant.shibei.base;
+
+public interface ItemLongClickListener {
+    void onItemLongClick(int position);
+}

+ 33 - 0
app/src/main/java/com/itant/shibei/bean/BeiUser.java

@@ -0,0 +1,33 @@
+package com.itant.shibei.bean;
+
+import java.io.Serializable;
+
+/**
+ * Created by Jason on 2018/8/26.
+ */
+
+public class BeiUser implements Serializable {
+    public String email;
+    public String nickName;
+    public String autograph;
+    public String password;
+    public String headIcon;
+    public int sex;
+    public String token;
+    public long registerTimeMillis;
+    public long lastLoginTimeMillis;
+    public boolean isVip;
+    public String deviceId;
+    public String lastIp;
+    public int themeMode;
+    /**当前余额,单位:分*/
+    public long currentMoney;
+    /**历史提现,单位:分*/
+    public long historyCash;
+
+    /**提现支付宝账号*/
+    public String cashAccount;
+    /**是否被禁用*/
+    public boolean isLimit;
+
+}

+ 17 - 0
app/src/main/java/com/itant/shibei/bean/SystemBean.java

@@ -0,0 +1,17 @@
+package com.itant.shibei.bean;
+
+
+/**
+ * 系统控制类
+ */
+public class SystemBean {
+    /**
+     * 模板Id
+     */
+    public long id;
+
+    /**
+     * 是否有VIP限制,true表示必须要VIP才能使用特殊服务,false表示免费开放中...
+     */
+    public boolean isVipLimit;
+}

+ 17 - 0
app/src/main/java/com/itant/shibei/bean/UpgradeBean.java

@@ -0,0 +1,17 @@
+package com.itant.shibei.bean;
+
+/**
+ * Created by Jason on 2019/09/29.
+ */
+public class UpgradeBean {
+    // Id自增,注意,一个表只能有一个主键,否则服务器会报500错误,启动失败
+    public int id;
+
+    public int versionCode;
+
+    public String versionName;
+
+    public String content;
+
+    public String url;
+}

+ 16 - 0
app/src/main/java/com/itant/shibei/common/ICommonView.java

@@ -0,0 +1,16 @@
+package com.itant.shibei.common;
+
+import com.miekir.mvp.view.IView;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/7/8 19:44
+ */
+public interface ICommonView<T> extends IView {
+    default void onCommonResult(boolean success, String message, T resultBean) {
+        //要在实现类显示调用ICommonView.super.onCommonResult(success, message, resultBean);才会生效
+        //dismissLoading();
+    }
+}

+ 16 - 0
app/src/main/java/com/itant/shibei/constant/ConstantString.java

@@ -0,0 +1,16 @@
+package com.itant.shibei.constant;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/7/11 16:35
+ * Description: 常量字符串
+ */
+public interface ConstantString {
+    String MONEY_RMB = "¥%s";
+    String COMMENT_NUM = "评论 %s";
+    String GOOD_COMMENT = "%s%%";
+    String MONEY_GAME = "¥%s";
+    String WELCOME_HELLO = "%s好,%s";
+}

+ 42 - 0
app/src/main/java/com/itant/shibei/constant/ConstantUrl.java

@@ -0,0 +1,42 @@
+package com.itant.shibei.constant;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/7/5 11:27
+ * Description: 常量
+ */
+public interface ConstantUrl {
+
+    /**
+     * 壁纸
+     */
+    String URL_RANDOM_PHOTO_WALLPAPER = "https://uploadbeta.com/api/pictures/random/?key=BingEverydayWallpaperPicture";
+
+    /**
+     * 京东装机模板
+     */
+    String URL_JD_TEMPLATE_COMPUTER = "https://diy.m.jd.com/?utm_user=plusmember&ad_od=share&utm_source=androidapp&utm_medium=appshare&utm_campaign=t_335139774&utm_term=CopyURL";
+
+    /**
+     * 表情包制作
+     */
+    String URL_BIAO_QING = "https://app.xuty.tk/static/app/index.html";
+
+    /**京东联盟地址*/
+    String URL_JD_UNION = "https://union.jd.com/proManager/index?pageNo=1";
+
+
+    /**
+     * 美团优惠1
+     */
+    String URL_MEITUAN_BONUS_1 = "https://tb.jiuxinban.com/6Fq9k9";
+    String URL_MEITUAN_BONUS_2 = "https://tb.jiuxinban.com/6Fq9mM";
+
+    /**
+     * 二次元
+     */
+    String URL_RANDOM_PHOTO_ECY = "https://uploadbeta.com/api/pictures/random/?key=二次元";
+    //String URL_RANDOM_PHOTO_ECY = "https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1594032996&di=6b8d48217739c2555a4b05b931cc45d7&src=http://a3.att.hudong.com/14/75/01300000164186121366756803686.jpg";
+}

+ 66 - 0
app/src/main/java/com/itant/shibei/manager/PreferenceManager.java

@@ -0,0 +1,66 @@
+package com.itant.shibei.manager;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import com.google.gson.Gson;
+
+import java.io.Serializable;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/8/2 16:44
+ * Description: 用户信息保存
+ */
+public class PreferenceManager {
+    public static final String KEY_USER = "user_info";
+
+    private static volatile PreferenceManager instance;
+    private PreferenceManager() {}
+
+    private SharedPreferences preferences;
+
+    public static PreferenceManager getInstance() {
+        if (instance == null) {
+            init();
+        }
+        return instance;
+    }
+
+    private static synchronized void init() {
+        if (instance == null) {
+            instance = new PreferenceManager();
+        }
+    }
+
+    public void initPreference(Context context) {
+        preferences = context.getSharedPreferences("current", Context.MODE_PRIVATE);
+    }
+
+    public void putSerializable(String key, Serializable value) {
+        if (value == null) {
+            preferences.edit().putString(key, "").commit();
+        } else {
+            preferences.edit().putString(key, new Gson().toJson(value)).commit();
+        }
+    }
+
+    /**
+     * 这里不能使用TypeToken<T>,因为要明确地具体到某一个类才能解析
+     * @param key
+     * @param clazz
+     * @param <T>
+     * @return
+     */
+    public <T> T getObject(String key, Class<T> clazz){
+        String jsonString = preferences.getString(key, null);
+        try {
+            return new Gson().fromJson(jsonString, clazz);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+}

+ 55 - 0
app/src/main/java/com/itant/shibei/manager/UserInfoManager.java

@@ -0,0 +1,55 @@
+package com.itant.shibei.manager;
+
+import com.itant.shibei.bean.BeiUser;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/6/27 20:40
+ * Description: 用户信息
+ */
+public class UserInfoManager {
+    private static volatile UserInfoManager userInfoManager;
+    private UserInfoManager() {}
+    private BeiUser mBeiUser;
+
+    private boolean isLogin;
+
+    public static UserInfoManager getInstance() {
+        if (userInfoManager == null) {
+            init();
+        }
+
+        return userInfoManager;
+    }
+
+    private static synchronized void init() {
+        if (userInfoManager == null) {
+            userInfoManager = new UserInfoManager();
+        }
+    }
+
+    public BeiUser getBeiUser() {
+        if (mBeiUser == null) {
+            // 从本地拿
+            mBeiUser = PreferenceManager.getInstance().getObject(PreferenceManager.KEY_USER, BeiUser.class);
+        }
+
+        return mBeiUser;
+    }
+
+    public void setBeiUser(BeiUser beiUser) {
+        this.mBeiUser = beiUser;
+        // 保存到本地
+        PreferenceManager.getInstance().putSerializable(PreferenceManager.KEY_USER, beiUser);
+    }
+
+    public boolean isLogin() {
+        return getBeiUser() != null;
+    }
+
+    public void setLogin(boolean login) {
+        isLogin = login;
+    }
+}

+ 173 - 0
app/src/main/java/com/itant/shibei/net/RetrofitHelper.java

@@ -0,0 +1,173 @@
+package com.itant.shibei.net;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.itant.shibei.manager.UserInfoManager;
+import com.miekir.network.BuildConfig;
+import com.miekir.network.core.RetrofitInstaller;
+import com.readystatesoftware.chuck.ChuckInterceptor;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManagerFactory;
+
+import okhttp3.Interceptor;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.logging.HttpLoggingInterceptor;
+import retrofit2.Retrofit;
+import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
+import retrofit2.converter.gson.GsonConverterFactory;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/1/19 10:58
+ * Description: 请求类,适用于请求链接和配置随时变动
+ */
+public class RetrofitHelper {
+    private static volatile RetrofitHelper mInstance;
+
+    private Context mContext;
+    private Retrofit mRetrofit;
+    private Retrofit mOtherRetrofit;
+    private OkHttpClient mOkHttpClient;
+    private OkHttpClient mOtherClient;
+
+    private Interceptor mHeaderInterceptor = new Interceptor() {
+        @Override
+        public Response intercept(Chain chain) throws IOException {
+            String token = "";
+            String email = "";
+            if (UserInfoManager.getInstance().isLogin()) {
+                token = UserInfoManager.getInstance().getBeiUser().token;
+                email = UserInfoManager.getInstance().getBeiUser().email;
+            }
+            Request request = chain.request()
+                    .newBuilder()
+                    .addHeader("token", token)
+                    .addHeader("email", email)
+                    .build();
+            return chain.proceed(request);
+        }
+    };
+
+    private static SSLSocketFactory getSSLContext (Context context){
+        try {
+            CertificateFactory cf = CertificateFactory.getInstance("X.509");
+            //privatekey.crt证书文件,将它放在Assets目录下
+            InputStream is =  context.getAssets().open("lomsxj.crt");
+
+            Certificate ca = cf.generateCertificate(is);
+            Log.i("getSSLContext ", "ca=" + ((X509Certificate) ca).getSubjectDN());
+
+            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+            keyStore.load(null,null);
+            keyStore.setCertificateEntry("ca",ca);
+
+            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+            tmf.init(keyStore);
+
+            SSLContext ssContext = SSLContext.getInstance("TLSv1", "AndroidOpenSSL");
+            ssContext.init(null,tmf.getTrustManagers(),null);
+
+            return ssContext.getSocketFactory();
+
+        } catch (CertificateException | KeyManagementException | NoSuchProviderException | NoSuchAlgorithmException | KeyStoreException | IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    private RetrofitHelper() {
+        mContext = RetrofitInstaller.mInstallerContext;
+
+        // 默认请求的超时等配置
+        mOkHttpClient = getDefaultOkHttpClient();
+        mOtherClient = getDefaultOkHttpClient();
+
+        // 默认请求的地址、转换规则等配置,Base URL以不能包含路径,只能是http://加上IP或域名
+        mRetrofit = new Retrofit.Builder()
+                .baseUrl(BuildConfig.BASE_URL)
+                .client(mOkHttpClient)
+                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
+                .addConverterFactory(GsonConverterFactory.create())
+                .build();
+    }
+
+    public static RetrofitHelper getInstance() {
+        if (mInstance == null) {
+            init();
+        }
+        return mInstance;
+    }
+
+    private static synchronized void init() {
+        if (mInstance == null) {
+            mInstance = new RetrofitHelper();
+        }
+    }
+
+    /**
+     *
+     * @return 默认的请求设置
+     */
+    public OkHttpClient getDefaultOkHttpClient() {
+        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
+            @Override
+            public void log(String message) {
+                //LogTool.logInfo("Retrofit:", message);
+            }
+        });
+        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
+
+        return new OkHttpClient.Builder()
+                .addInterceptor(mHeaderInterceptor)
+                //.addInterceptor(interceptor)
+                //.sslSocketFactory(getSSLContext(context))
+                .addInterceptor(new ChuckInterceptor(mContext))
+                .retryOnConnectionFailure(true)
+                .connectTimeout(20, TimeUnit.SECONDS)
+                .writeTimeout(20, TimeUnit.SECONDS)
+                .readTimeout(60, TimeUnit.SECONDS)
+                .build();
+    }
+
+    /**
+     *
+     * @return 请求接口
+     */
+    public <T> T getRequestApi(Class<T> apiClass) {
+        return mRetrofit.create(apiClass);
+    }
+
+    /**
+     *
+     * @return 请求接口
+     */
+    public <T> T getRequestApi(Class<T> apiClass, String baseUrl) {
+        mOtherRetrofit = new Retrofit.Builder()
+                .baseUrl(baseUrl)
+                .client(mOtherClient)
+                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
+                .addConverterFactory(GsonConverterFactory.create())
+                .build();
+        return mOtherRetrofit.create(apiClass);
+    }
+}

+ 82 - 0
app/src/main/java/com/itant/shibei/tool/Base64Tool.java

@@ -0,0 +1,82 @@
+package com.itant.shibei.tool;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.util.Base64;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+/**
+ * @author 詹子聪
+ * @date 2020/7/27 15:40
+ * Description: 图片转Base64字符串
+ */
+public class Base64Tool {
+    private Base64Tool() {}
+    /**
+     * 图片Uri转Base64
+     *
+     * @param context
+     * @param imageUri
+     * @return
+     */
+    public static String getBase64FromUri(Context context, Uri imageUri) {
+        String encodedString = "";
+        if (imageUri == null) {
+            return encodedString;
+        }
+
+        InputStream imageStream = null;
+        try {
+            imageStream = context.getContentResolver().openInputStream(imageUri);
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+            return encodedString;
+        }
+
+        final Bitmap selectedImage = BitmapFactory.decodeStream(imageStream);
+        encodedString = bitmap2Base64(selectedImage);
+
+        return encodedString;
+    }
+
+    private static String bitmap2Base64(Bitmap bitmap) {
+        if (bitmap == null) {
+            return "";
+        }
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
+        byte[] b = baos.toByteArray();
+
+        //return Base64.encodeToString(b, Base64.DEFAULT);
+        return Base64.encodeToString(b, Base64.NO_WRAP);
+    }
+
+    /**
+     * 根据路径,图片转Base64
+     * @param path
+     * @return
+     */
+    public static String getBase64FromFilePath(String path) {
+        File imageFile = new File(path);
+        FileInputStream fis = null;
+        try {
+            fis = new FileInputStream(imageFile);
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+            return "";
+        }
+        Bitmap bm = BitmapFactory.decodeStream(fis);
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
+        byte[] b = baos.toByteArray();
+
+        return Base64.encodeToString(b, Base64.NO_WRAP);
+    }
+}

+ 95 - 0
app/src/main/java/com/itant/shibei/tool/DataTool.java

@@ -0,0 +1,95 @@
+package com.itant.shibei.tool;
+
+import com.itant.shibei.R;
+import com.itant.shibei.constant.ConstantUrl;
+import com.itant.shibei.ui.function.FunctionFragment;
+import com.itant.shibei.ui.home.coupon.CouponBean;
+import com.itant.shibei.ui.home.goods.GoodsBean;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Miekir
+ * @date 2020/7/8 19:36
+ * Description: 模拟数据提供者
+ */
+public class DataTool {
+    private DataTool() {
+    }
+
+    public static List<CouponBean> getTemplateList(int functionTye) {
+
+        List<CouponBean> couponBeanList = new ArrayList<>();
+        switch (functionTye) {
+            case FunctionFragment.TEMPLATE_TYPE_BONUS:
+                CouponBean meituan1 = new CouponBean();
+                //meituan1.coverUrl = ConstantUrl.URL_RANDOM_PHOTO_WALLPAPER;
+                meituan1.coverUrl = String.valueOf(R.mipmap.meituan1);
+                meituan1.isCoverUrlLocal = true;
+                meituan1.couponName = "美团优惠券最多可领48元大礼包";
+                meituan1.jumpUrl = ConstantUrl.URL_MEITUAN_BONUS_1;
+                meituan1.actionEnable = true;
+                meituan1.isLocal = true;
+
+                CouponBean meituan2 = new CouponBean();
+                //meituan2.coverUrl = ConstantUrl.URL_RANDOM_PHOTO_WALLPAPER;
+                meituan2.coverUrl = String.valueOf(R.mipmap.meituan2);
+                meituan2.isCoverUrlLocal = true;
+                meituan2.couponName = "美团优惠券至少2元起(新老用户都可领)";
+                meituan2.jumpUrl = ConstantUrl.URL_MEITUAN_BONUS_2;
+                meituan2.actionEnable = true;
+                meituan2.isLocal = true;
+
+                couponBeanList.add(meituan2);
+                couponBeanList.add(meituan1);
+                break;
+            case FunctionFragment.TEMPLATE_TYPE_TEMPLATE:
+                CouponBean template = new CouponBean();
+                template.coverUrl = ConstantUrl.URL_RANDOM_PHOTO_ECY;
+                template.couponName = "DIY装机";
+                template.jumpUrl = ConstantUrl.URL_JD_TEMPLATE_COMPUTER;
+                template.actionEnable = true;
+                template.isLocal = true;
+                couponBeanList.add(template);
+                break;
+
+            case FunctionFragment.TEMPLATE_TYPE_GAME:
+//                CouponBean game = new CouponBean();
+//                game.setCoverUrl(ConstantUrl.URL_RANDOM_PHOTO_ECY);
+//                game.setTemplateName("欢乐猜猜");
+//                game.setActionEnable(false);
+                break;
+            default:
+                break;
+        }
+
+        return couponBeanList;
+    }
+
+    public static List<GoodsBean> getGoodsList() {
+        List<GoodsBean> goodsList = new ArrayList<>();
+        GoodsBean goodsBean = new GoodsBean();
+        goodsBean.coverImageUrl = "https://img14.360buyimg.com/n12/jfs/t1/97822/29/10664/255856/5e1ebf26Eea1a28ec/ac2c298127bae9a4.jpg";
+        goodsBean.title = "华硕(ASUS) PN60 商用办公家用教育 台式机电脑主机 (i3-8130U 128G SSD 4G 正版Win10 三年上门)迷你主机";
+        goodsBean.description = "远程教育,在家办公,顺畅不卡顿!";
+        goodsBean.reason = "小巧稳定的个人服务器";
+        goodsBean.oldPrice = 229900;
+        goodsBean.nowPrice = 229900;
+        goodsBean.rebate = 0;
+        goodsBean.shopName = "华硕京东自营旗舰店";
+        goodsBean.province = "广东";
+        goodsBean.isSelfBusiness = true;
+        goodsBean.hasCoupon = true;
+        goodsBean.couponInfo = "30";
+        goodsBean.goodsType = GoodsBean.TYPE_TECHNOLOGY;
+        goodsBean.goodsUrl = "https://union-click.jd.com/jdc?e=&p=AyIGZRtcEgAXA1QfWhIyEgZUGloRAxYEXRpfJUZNXwtEa0xHV0YXEEULWldTCQQHCllHGAdFBwtEQkQBBRxNVlQYBUkeTVxNCRNLGEF6RwtVGloUAxYGURhTFAYichZtC3VcTl8wREFHCkp9MRwcSkBbZ1kXaxQyEgZUGFMcBREAUitrFQUiVDtADnsGQQBWH1JHCxMCUksOJQMiB1ETXR0CEANQG10cASIAVRJrU1dTWhNNBEtnbFMSRQYlMiIEZStrFTIRNxd1CxNSEwUFHggXBRFQUB0JFlFAUFcaXhUBGwVXT14UBEU3VxpaEQs%3D";
+        goodsBean.salesPerMonth = 1022;
+        goodsBean.commentNum = 1022;
+        goodsBean.goodCommentPercent = 0.97d;
+        goodsBean.isLocal = true;
+        goodsBean.enable = true;
+        goodsList.add(goodsBean);
+        return goodsList;
+    }
+}

+ 42 - 0
app/src/main/java/com/itant/shibei/tool/MD5Tool.java

@@ -0,0 +1,42 @@
+package com.itant.shibei.tool;
+
+
+import java.nio.charset.Charset;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/8/7 18:37
+ * Description: md5工具
+ */
+public class MD5Tool {
+    private MD5Tool(){}
+
+    /**
+     * 将字符串转成MD5值
+     * @param string
+     * @return
+     */
+    public static String stringToMD5(String string) {
+        byte[] hash;
+        try {
+            hash = MessageDigest.getInstance("MD5").digest(string.getBytes(Charset.forName("UTF-8")));
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+            return null;
+        }
+
+        StringBuilder hex = new StringBuilder(hash.length * 2);
+        for (byte b : hash) {
+            if ((b & 0xFF) < 0x10) {
+                hex.append(0);
+            }
+            hex.append(Integer.toHexString(b & 0xFF));
+        }
+        return hex.toString();
+    }
+
+}

+ 74 - 0
app/src/main/java/com/itant/shibei/tool/StringTool.java

@@ -0,0 +1,74 @@
+package com.itant.shibei.tool;
+
+import android.text.TextUtils;
+import android.util.Base64;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.nio.charset.StandardCharsets;
+import java.text.DecimalFormat;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/7/11 21:59
+ * Description: 字符串相关工具
+ */
+public class StringTool {
+    private StringTool() {}
+
+    private static final DecimalFormat FORMAT_TWO = new DecimalFormat("#.00");
+    public static String getShowMoney(double number) {
+        return FORMAT_TWO.format(number);
+    }
+
+    public static String getEncodeString(String rawString) {
+        String base64String = Base64.encodeToString(rawString.getBytes(StandardCharsets.UTF_8), Base64.NO_WRAP);
+        StringBuilder stringBuffer = new StringBuilder(base64String);
+        if (base64String.length() > 0) {
+            stringBuffer.setCharAt(base64String.length()/2, 's');
+        }
+        String base64Reverse = stringBuffer.reverse().toString();
+        return MD5Tool.stringToMD5(base64Reverse);
+    }
+
+    /**
+     * 分转元,保留2位小数
+     * @return
+     */
+    public static String longCent2Yuan(long cent) {
+        BigDecimal centDecimal = BigDecimal.valueOf(cent);
+        BigDecimal exchangeNum = BigDecimal.valueOf(100);
+        BigDecimal yuanDecimal = centDecimal.divide(exchangeNum, 2, RoundingMode.UNNECESSARY);
+        return yuanDecimal.toPlainString();
+    }
+
+    public static String getNumberString(long number) {
+        if (number > 100000) {
+            return "10w+";
+        }
+
+        if (number > 10000) {
+            return "1w+";
+        }
+
+        if (number > 1000) {
+            return "1k+";
+        }
+
+        return String.valueOf(number);
+    }
+
+    public static String getMixToken(String token) {
+        if (TextUtils.isEmpty(token) || token.length() < 2) {
+            return token;
+        }
+        int len = token.length();
+        char[] tokenArray = token.toCharArray();
+        char temp = tokenArray[len-2];
+        tokenArray[len-2] = tokenArray[len-1];
+        tokenArray[len-1] = temp;
+        return new String(tokenArray);
+    }
+}

+ 93 - 0
app/src/main/java/com/itant/shibei/tool/SystemTool.java

@@ -0,0 +1,93 @@
+package com.itant.shibei.tool;
+
+import android.app.Activity;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+
+import com.miekir.common.utils.ToastTool;
+
+
+/**
+ * Created by Jason on 2018/9/11.
+ */
+
+public class SystemTool {
+    private SystemTool() {}
+    private static final String LABEL_COPY = "shi_bei";
+    public static boolean copyText(Context context, String text) {
+        ClipboardManager manager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
+        ClipData clipData = ClipData.newPlainText(LABEL_COPY, text);
+        if (manager != null) {
+            manager.setPrimaryClip(clipData);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 获取版本code
+     * @param context
+     * @return
+     */
+    public static int getVersionCode(Context context) {
+        int versionCode = -1;
+        PackageManager packageManager = context.getPackageManager();
+        try {
+            if (packageManager != null) {
+                PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
+                return packageInfo.versionCode;
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        return versionCode;
+    }
+
+    /**
+     * 获取版本名字
+     * @param context
+     * @return
+     */
+    public static String getVersionName(Context context) {
+        PackageManager manager = context.getPackageManager();
+        if (manager != null) {
+            try {
+                //获取软件版本号,对应AndroidManifest.xml下android:versionCode,0表示基本信息
+                return manager.getPackageInfo(context.getPackageName(), 0).versionName;
+            } catch (PackageManager.NameNotFoundException e) {
+                e.printStackTrace();
+            }
+        }
+        return "";
+    }
+
+    /**
+     * 发送邮件
+     * @param activity
+     */
+    public static void sendEmail(Activity activity) {
+        if (activity == null) {
+            return;
+        }
+
+        boolean copyResult = SystemTool.copyText(activity, "[email protected]");
+        if (!copyResult) {
+            ToastTool.showLong("请发送到[email protected]");
+        } else {
+            ToastTool.showShort("已复制反馈邮箱号");
+        }
+        Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
+        emailIntent.setType("application/octet-stream");
+        try {
+            activity.startActivity(emailIntent);
+        } catch (Exception e) {
+            e.printStackTrace();
+            ToastTool.showShort("未找到邮箱客户端");
+        }
+    }
+}

+ 51 - 0
app/src/main/java/com/itant/shibei/tool/TimeTool.java

@@ -0,0 +1,51 @@
+package com.itant.shibei.tool;
+
+import java.util.Calendar;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/7/24 9:15
+ * Description: 时间相关工具类
+ */
+public class TimeTool {
+    /**
+     *
+     * @return 返回当前是上午、中午、下午
+     */
+    public static String getCurrentTimePeriod() {
+        Calendar cal = Calendar.getInstance();
+        int hour = cal.get(Calendar.HOUR_OF_DAY);
+
+        if (hour >= 3 && hour < 6) {
+            return "凌晨";
+        }
+
+        if (hour >= 6 && hour < 8) {
+            return "早上";
+        }
+
+        if (hour >= 8 && hour < 11) {
+            return "上午";
+        }
+
+        if (hour >= 11 && hour < 13) {
+            return "中午";
+        }
+
+        if (hour >= 13 && hour < 17) {
+            return "下午";
+        }
+
+        if (hour >= 17 && hour < 19) {
+            return "傍晚";
+        }
+
+        if (hour >= 19 && hour < 23) {
+            return "晚上";
+        }
+
+        return "深夜";
+    }
+}

+ 28 - 0
app/src/main/java/com/itant/shibei/ui/BeiApplication.java

@@ -0,0 +1,28 @@
+package com.itant.shibei.ui;
+
+import android.app.Application;
+
+import com.itant.shibei.manager.PreferenceManager;
+import com.umeng.analytics.MobclickAgent;
+import com.umeng.commonsdk.UMConfigure;
+
+import rx_activity_result2.RxActivityResult;
+
+/**
+ *
+ * @author Miekir
+ * @date 2020/8/2 9:34
+ * Description:
+ */
+public class BeiApplication extends Application {
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+        PreferenceManager.getInstance().initPreference(this);
+        RxActivityResult.register(this);
+        UMConfigure.init(this, "5f35e7d9d3093221547834b6", "Umeng", UMConfigure.DEVICE_TYPE_PHONE, "");
+        //选择AUTO页面采集模式,统计SDK基础指标无需手动埋点可自动采集。
+        MobclickAgent.setPageCollectionMode(MobclickAgent.PageMode.AUTO);
+    }
+}

+ 52 - 0
app/src/main/java/com/itant/shibei/ui/HomeFragment.java

@@ -0,0 +1,52 @@
+package com.itant.shibei.ui;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.viewpager.widget.ViewPager;
+
+import com.flyco.tablayout.SlidingTabLayout;
+import com.itant.shibei.R;
+import com.itant.shibei.ui.home.goods.GoodsFragment;
+import com.miekir.common.adapter.TabFragmentAdapter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class HomeFragment extends Fragment implements View.OnClickListener {
+
+
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater,
+                             ViewGroup container, Bundle savedInstanceState) {
+        View root = inflater.inflate(R.layout.fragment_home, container, false);
+
+        String[] titles = {"推荐", "科技", "生活", "网络"};
+        List<Fragment> fragments = new ArrayList<>();
+        fragments.add(new GoodsFragment());
+        fragments.add(new GoodsFragment());
+        fragments.add(new GoodsFragment());
+        fragments.add(new GoodsFragment());
+
+        ViewPager vp_home = root.findViewById(R.id.vp_home);
+        TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager(), fragments);
+        vp_home.setAdapter(adapter);
+        vp_home.setOffscreenPageLimit(titles.length);
+        //vp_home.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
+
+        SlidingTabLayout stl_home = root.findViewById(R.id.stl_home);
+        stl_home.setViewPager(vp_home, titles);
+
+        root.findViewById(R.id.rl_search).setOnClickListener(this);
+        return root;
+    }
+
+    @Override
+    public void onClick(View v) {
+
+    }
+}

+ 89 - 0
app/src/main/java/com/itant/shibei/ui/MainActivity.java

@@ -0,0 +1,89 @@
+package com.itant.shibei.ui;
+
+import android.os.Bundle;
+import android.view.MenuItem;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.navigation.NavController;
+import androidx.viewpager.widget.ViewPager;
+
+import com.google.android.material.bottomnavigation.BottomNavigationView;
+import com.google.android.material.bottomnavigation.LabelVisibilityMode;
+import com.itant.shibei.R;
+import com.itant.shibei.adapter.FragmentPagerItemAdapter;
+import com.itant.shibei.base.BaseBeiActivity;
+import com.itant.shibei.ui.function.FunctionFragment;
+import com.itant.shibei.ui.mine.MineFragment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MainActivity extends BaseBeiActivity implements View.OnClickListener {
+
+    private NavController navController;
+    private ViewPager vp_main;
+    private List<Fragment> fragmentList;
+
+
+
+    @Override
+    public int getLayoutID() {
+        return R.layout.activity_main;
+    }
+
+    @Override
+    public void initViews(Bundle savedInstanceState) {
+        BottomNavigationView nav_view = findViewById(R.id.nav_view);
+        // 去除底部动画效果
+        //BottomNavigationViewHelper.disableShiftMode(navigation);
+        nav_view.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
+        // 底部导航菜单3个项以上不显示文字的问题
+        nav_view.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);
+        // 避免在当前Fragment点击当前Fragment对应的Tab时仍然被销毁
+        nav_view.setOnNavigationItemReselectedListener(item -> {
+            // do nothing here
+        });
+
+        // 采用ViewPager+BottomNavigationView防止每次切换Tab时Fragment都被销毁
+        fragmentList = new ArrayList<>();
+        fragmentList.add(new HomeFragment());
+        fragmentList.add(new FunctionFragment());
+        fragmentList.add(new MineFragment());
+        vp_main = findViewById(R.id.vp_main);
+        vp_main.setOffscreenPageLimit(fragmentList.size());
+
+        FragmentPagerItemAdapter adapter = new FragmentPagerItemAdapter(getSupportFragmentManager(), fragmentList);
+        vp_main.setAdapter(adapter);
+        vp_main.setCurrentItem(0);
+    }
+
+    private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
+            = new BottomNavigationView.OnNavigationItemSelectedListener() {
+
+        @Override
+        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
+            switch (item.getItemId()) {
+                case R.id.nav_home:
+                    vp_main.setCurrentItem(0);
+                    return true;
+                case R.id.nav_template:
+                    vp_main.setCurrentItem(1);
+                    return true;
+                case R.id.nav_mine:
+                    vp_main.setCurrentItem(2);
+                    return true;
+                default:
+                    break;
+            }
+            return false;
+        }
+    };
+
+
+    @Override
+    public void onClick(View v) {
+
+    }
+}

+ 68 - 0
app/src/main/java/com/itant/shibei/ui/MainViewModel.java

@@ -0,0 +1,68 @@
+package com.itant.shibei.ui;
+
+import android.view.View;
+
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.ViewModel;
+
+/**
+ * 使用ViewModel + LiveData保存Fragment的数据,阻止Fragment在配合BottomNavigationView切换时总被销毁的问题
+ *
+ */
+/*public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+    mainViewModel=new ViewModelProvider(getActivity()).get(MainViewModel.class);
+    root=mainViewModel.getHomeView().getValue();
+    if(root==null){
+    //正常初始化View
+    root = inflater.inflate(R.layout.fragment_home, container, false);
+    //...
+    }
+    //...
+    return root;
+}*/
+/*@Override
+public void onDestroyView() {
+    super.onDestroyView();
+    //其实以下代码不一定写在onDestroyView(),可以获取指定后root的地方都可以
+    ViewGroup parent = (ViewGroup) root.getParent();
+    if(parent!=null){
+        parent.removeView(root);
+    }
+    mainViewModel.setHomeView(root);
+}*/
+public class MainViewModel extends ViewModel {
+    private MutableLiveData<View> mTemplateView;
+    private MutableLiveData<View> mHomeView;
+    private MutableLiveData<View> mMineView;
+
+    public MainViewModel() {
+        mTemplateView = new MutableLiveData<>();
+        mHomeView = new MutableLiveData<>();
+        mMineView = new MutableLiveData<>();
+    }
+
+    public void setTemplateView(View v) {
+        mTemplateView.setValue(v);
+    }
+
+    public void setHomeView(View v) {
+        mHomeView.setValue(v);
+    }
+
+    public void setMineView(View v) {
+        mMineView.setValue(v);
+    }
+
+    public LiveData<View> getTemplateView() {
+        return mTemplateView;
+    }
+
+    public LiveData<View> getHomeView() {
+        return mHomeView;
+    }
+
+    public LiveData<View> getMineView() {
+        return mMineView;
+    }
+}

+ 165 - 0
app/src/main/java/com/itant/shibei/ui/TabActivity.java

@@ -0,0 +1,165 @@
+package com.itant.shibei.ui;
+
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.Fragment;
+import androidx.viewpager.widget.ViewPager;
+
+import com.flyco.tablayout.SlidingTabLayout;
+import com.flyco.tablayout.listener.OnTabSelectListener;
+import com.google.android.material.appbar.AppBarLayout;
+import com.itant.shibei.R;
+import com.itant.shibei.base.BaseBeiActivity;
+import com.itant.shibei.base.ITopActionListener;
+import com.itant.shibei.bean.UpgradeBean;
+import com.itant.shibei.common.ICommonView;
+import com.itant.shibei.manager.UserInfoManager;
+import com.itant.shibei.tool.SystemTool;
+import com.itant.shibei.ui.function.FunctionFragment;
+import com.itant.shibei.ui.home.about.AboutFragment;
+import com.itant.shibei.ui.home.about.upgrade.UpgradePresenter;
+import com.itant.shibei.ui.home.coupon.TemplateFragment;
+import com.itant.shibei.ui.home.goods.GoodsFragment;
+import com.itant.shibei.ui.home.search.SearchActivity;
+import com.itant.shibei.ui.home.tool.ToolFragment;
+import com.itant.shibei.ui.mine.MineActivity;
+import com.itant.shibei.ui.mine.login.LoginActivity;
+import com.itant.shibei.widget.AppbarTranslateListener;
+import com.miekir.common.adapter.TabFragmentAdapter;
+import com.miekir.common.utils.ActivityTool;
+import com.miekir.common.utils.ToastTool;
+import com.miekir.common.utils.ViewTool;
+import com.miekir.mvp.presenter.InjectPresenter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TabActivity extends BaseBeiActivity implements View.OnClickListener, ICommonView<UpgradeBean> {
+
+    @InjectPresenter
+    UpgradePresenter upgradePresenter;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        // 获取版本更新
+        upgradePresenter.getUpgradeInfo();
+    }
+
+    @Override
+    public int getLayoutID() {
+        return R.layout.activity_tab;
+    }
+
+    @Override
+    public void initViews(Bundle savedInstanceState) {
+        String[] titles = {"推荐", "好券", "工具", "关于"};
+        List<Fragment> fragments = new ArrayList<>();
+        fragments.add(new GoodsFragment());
+        fragments.add(new TemplateFragment(FunctionFragment.TEMPLATE_TYPE_BONUS));
+        //fragments.add(new TemplateFragment(FunctionFragment.TEMPLATE_TYPE_TEMPLATE));
+        fragments.add(new ToolFragment());
+        fragments.add(new AboutFragment());
+
+        ViewPager vp_main = findViewById(R.id.vp_main);
+        TabFragmentAdapter adapter = new TabFragmentAdapter(getSupportFragmentManager(), fragments);
+        vp_main.setAdapter(adapter);
+        vp_main.setOffscreenPageLimit(titles.length);
+        //vp_home.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
+
+        SlidingTabLayout stl_home = findViewById(R.id.stl_home);
+        stl_home.setViewPager(vp_main, titles);
+        // 默认选中返利商品列表
+        stl_home.setCurrentTab(0);
+        stl_home.setOnTabSelectListener(new OnTabSelectListener() {
+            @Override
+            public void onTabSelect(int position) {
+            }
+
+            @Override
+            public void onTabReselect(int position) {
+                // 重复选中Tab可以让该Tab对应的列表滚动到顶部
+                Fragment fragment = fragments.get(position);
+                if (fragment instanceof ITopActionListener) {
+                    ((ITopActionListener) fragment).onTopAction();
+                }
+            }
+        });
+
+        ViewTool.setOnClickListener(this, this,
+                new int[]{R.id.fl_search, R.id.fl_search_top, R.id.fl_more});
+
+        double defaultHeight = getResources().getDimension(R.dimen.margin_default);
+        double defaultWidth = getResources().getDimension(R.dimen.height_edit_text);
+
+        View rl_search_top = findViewById(R.id.rl_search_top);
+        View rl_search_top_shadow = findViewById(R.id.rl_search_top_shadow);
+        View rl_search = findViewById(R.id.rl_search);
+        // 搜索图标动画
+        AppBarLayout abl_main = findViewById(R.id.abl_main);
+        AppbarTranslateListener listener = new AppbarTranslateListener(
+                this,
+                defaultWidth, defaultHeight,
+                rl_search_top, rl_search_top_shadow, rl_search);
+        abl_main.addOnOffsetChangedListener(listener);
+    }
+
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.fl_more:
+                // 点击更多
+                if (UserInfoManager.getInstance().isLogin()) {
+                    startActivity(new Intent(this, MineActivity.class));
+                } else {
+                    // 登录
+                    Intent intent = new Intent(this, LoginActivity.class);
+                    startActivity(intent);
+                }
+                break;
+            case R.id.fl_search_top:
+            case R.id.fl_search:
+                // 点击搜索
+                startActivity(new Intent(this, SearchActivity.class));
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    @Override
+    public void onCommonResult(boolean success, String message, UpgradeBean resultBean) {
+        // 获取到了版本信息
+        if (success && resultBean != null && SystemTool.getVersionCode(this) < resultBean.versionCode) {
+            AlertDialog alertDialog = new AlertDialog.Builder(this)
+                    .setMessage(resultBean.content)
+                    .setNegativeButton("取消", (dialog, which) -> dialog.dismiss())
+                    .setPositiveButton("确定", (DialogInterface dialog, int which) -> {
+                        dialog.dismiss();
+                        if (!TextUtils.isEmpty(resultBean.url)) {
+                            ActivityTool.openUrl(TabActivity.this, resultBean.url);
+                        }
+                    }).create();
+            alertDialog.show();
+        }
+    }
+
+    private long mLastBackMillis;
+    @Override
+    public void onBackPressed() {
+        if (System.currentTimeMillis() - mLastBackMillis > 3000) {
+            ToastTool.showShort("再按一次退出");
+            mLastBackMillis = System.currentTimeMillis();
+        } else {
+            super.onBackPressed();
+        }
+    }
+}

+ 48 - 0
app/src/main/java/com/itant/shibei/ui/function/FunctionFragment.java

@@ -0,0 +1,48 @@
+package com.itant.shibei.ui.function;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.viewpager.widget.ViewPager;
+
+import com.flyco.tablayout.SlidingTabLayout;
+import com.itant.shibei.R;
+import com.itant.shibei.ui.home.coupon.TemplateFragment;
+import com.miekir.common.adapter.TabFragmentAdapter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 模板Fragment
+ */
+public class FunctionFragment extends Fragment {
+    public static final int TEMPLATE_TYPE_BONUS = 1;
+    public static final int TEMPLATE_TYPE_TEMPLATE = 2;
+    public static final int TEMPLATE_TYPE_GAME = 3;
+
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
+        View root = inflater.inflate(R.layout.fragment_function, container, false);
+        String[] titles = {"游戏", "优惠", "模板"};
+        List<Fragment> fragments = new ArrayList<>();
+        fragments.add(new TemplateFragment(TEMPLATE_TYPE_GAME));
+        fragments.add(new TemplateFragment(TEMPLATE_TYPE_BONUS));
+        fragments.add(new TemplateFragment(TEMPLATE_TYPE_TEMPLATE));
+
+        ViewPager vp_home = root.findViewById(R.id.vp_home);
+        TabFragmentAdapter adapter = new TabFragmentAdapter(getChildFragmentManager(), fragments);
+        vp_home.setAdapter(adapter);
+        vp_home.setOffscreenPageLimit(titles.length);
+        //vp_home.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
+
+        SlidingTabLayout stl_home = root.findViewById(R.id.stl_home);
+        stl_home.setViewPager(vp_home, titles);
+        return root;
+    }
+}

+ 97 - 0
app/src/main/java/com/itant/shibei/ui/home/about/AboutFragment.java

@@ -0,0 +1,97 @@
+package com.itant.shibei.ui.home.about;
+
+import android.content.DialogInterface;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.appcompat.app.AlertDialog;
+
+import com.itant.shibei.R;
+import com.itant.shibei.bean.UpgradeBean;
+import com.itant.shibei.common.ICommonView;
+import com.itant.shibei.tool.SystemTool;
+import com.itant.shibei.ui.home.about.upgrade.UpgradePresenter;
+import com.miekir.common.utils.ActivityTool;
+import com.miekir.common.utils.ToastTool;
+import com.miekir.mvp.presenter.InjectPresenter;
+import com.miekir.mvp.view.BaseMVPFragment;
+
+/**
+ * @author Miekir
+ * @date 2020/6/18 16:48
+ * Description: 关于界面
+ * todo 点击版本号检查更新
+ */
+public class AboutFragment extends BaseMVPFragment implements View.OnClickListener, ICommonView<UpgradeBean> {
+
+    @InjectPresenter
+    UpgradePresenter upgradePresenter;
+
+    @Override
+    protected void onViewInit() {
+        TextView tv_title = rootView.findViewById(R.id.tv_title);
+        tv_title.setText(" 拾贝 v" + SystemTool.getVersionName(getActivity()));
+        rootView.findViewById(R.id.tv_feedback).setOnClickListener(this);
+        rootView.findViewById(R.id.tv_update).setOnClickListener(this);
+        rootView.findViewById(R.id.tv_more).setOnClickListener(this);
+        rootView.findViewById(R.id.tv_protocol).setOnClickListener(this);
+    }
+
+    @Override
+    protected void onLazyLoad() {
+
+    }
+
+    @Override
+    public int getLayoutResId() {
+        return R.layout.fragment_about;
+    }
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.tv_feedback:
+                SystemTool.sendEmail(getActivity());
+                break;
+
+            case R.id.tv_update:
+                showLoading();
+                upgradePresenter.getUpgradeInfo();
+                break;
+
+            case R.id.tv_more:
+                SystemTool.copyText(getActivity(), "http://jianjie.life");
+                ToastTool.showShort("已拷贝主页链接");
+                break;
+            case R.id.tv_protocol:
+                ActivityTool.openUrl(getActivity(), "http://note.youdao.com/s/KTiCW1qH");
+                break;
+            default:
+                break;
+        }
+    }
+
+    @Override
+    public void onCommonResult(boolean success, String message, UpgradeBean resultBean) {
+        dismissLoading();
+        // 获取到了版本信息
+        if (success &&
+                resultBean != null &&
+                SystemTool.getVersionCode(getActivity()) < resultBean.versionCode &&
+                !TextUtils.isEmpty(resultBean.url)) {
+            AlertDialog alertDialog = new AlertDialog.Builder(getActivity())
+                    .setMessage(resultBean.content)
+                    .setNegativeButton("取消", (dialog, which) -> dialog.dismiss())
+                    .setPositiveButton("确定", (DialogInterface dialog, int which) -> {
+                        dialog.dismiss();
+                        ActivityTool.openUrl(getActivity(), resultBean.url);
+                    }).create();
+            alertDialog.setCancelable(false);
+            alertDialog.setCanceledOnTouchOutside(false);
+            alertDialog.show();
+        } else {
+            ToastTool.showShort("当前已经是最新版本啦");
+        }
+    }
+}

+ 49 - 0
app/src/main/java/com/itant/shibei/ui/home/about/upgrade/UpgradePresenter.java

@@ -0,0 +1,49 @@
+package com.itant.shibei.ui.home.about.upgrade;
+
+import android.text.TextUtils;
+
+import com.itant.shibei.base.ApiService;
+import com.itant.shibei.bean.UpgradeBean;
+import com.itant.shibei.common.ICommonView;
+import com.itant.shibei.net.RetrofitHelper;
+import com.miekir.mvp.presenter.BasePresenter;
+import com.miekir.network.core.base.BaseObserver;
+
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/7/8 19:43
+ * Description: 模板的Presenter
+ */
+public class UpgradePresenter extends BasePresenter<ICommonView<UpgradeBean>> {
+    /**
+     * 获取版本信息
+     */
+    public void getUpgradeInfo() {
+        RetrofitHelper.getInstance()
+                .getRequestApi(ApiService.class)
+                .getUpgradeInfo()
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new BaseObserver<UpgradeBean>() {
+                    @Override
+                    public void onSuccess(UpgradeBean result) {
+                        if (getView() != null) {
+                            getView().onCommonResult(true, "", result);
+                        }
+                    }
+
+                    @Override
+                    public void onFailure(Throwable e, String errMsg) {
+                        if (getView() != null) {
+                            getView().onCommonResult(false, TextUtils.isEmpty(errMsg) ? "获取失败:"+e.getMessage() : errMsg, null);
+                        }
+                    }
+                });
+    }
+
+}

+ 68 - 0
app/src/main/java/com/itant/shibei/ui/home/coupon/CouponBean.java

@@ -0,0 +1,68 @@
+package com.itant.shibei.ui.home.coupon;
+
+import com.itant.shibei.constant.ConstantUrl;
+
+import java.io.Serializable;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/7/7 19:37
+ * Description: 优惠券实体
+ */
+public class CouponBean implements Serializable {
+    /**
+     * 模板Id
+     */
+    public long id;
+    /**
+     * 模板类型
+     */
+    public int couponType;
+
+    /**
+     * 模板名称
+     */
+    public String couponName;
+    /**
+     * 点击之后跳转的链接
+     */
+    public String jumpUrl;
+    /**
+     * 封面图片URL
+     */
+    public String coverUrl = ConstantUrl.URL_RANDOM_PHOTO_WALLPAPER;
+
+
+    /**
+     * 是否可以响应点击
+     */
+    public boolean actionEnable;
+
+    /**是否是本地写死的数据*/
+    public boolean isLocal;
+
+    /**
+     * 创建时间
+     */
+    public long createTimeMillis;
+
+    /**
+     * 更新时间
+     */
+    public long updateTimeMillis;
+
+    public boolean isCoverUrlLocal;
+
+    public void updateData(CouponBean couponBean) {
+        this.couponType = couponBean.couponType;
+        this.couponName = couponBean.couponName;
+        this.coverUrl = couponBean.coverUrl;
+        this.jumpUrl = couponBean.jumpUrl;
+        this.actionEnable = couponBean.actionEnable;
+        this.isLocal = couponBean.isLocal;
+        this.createTimeMillis = couponBean.createTimeMillis;
+        this.updateTimeMillis = couponBean.updateTimeMillis;
+    }
+}

+ 17 - 0
app/src/main/java/com/itant/shibei/ui/home/coupon/ITemplateView.java

@@ -0,0 +1,17 @@
+package com.itant.shibei.ui.home.coupon;
+
+import com.miekir.mvp.view.IView;
+
+import java.util.List;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/7/8 19:44
+ * Description: Template的View
+ */
+public interface ITemplateView<T> extends IView {
+    void onTemplateDataCome(boolean success, String message, List<T> couponBeanList);
+    void onDeleteCouponResult(boolean success, String message, int position);
+}

+ 129 - 0
app/src/main/java/com/itant/shibei/ui/home/coupon/TemplateAdapter.java

@@ -0,0 +1,129 @@
+package com.itant.shibei.ui.home.coupon;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.target.SimpleTarget;
+import com.bumptech.glide.request.transition.Transition;
+import com.chad.library.adapter.base.BaseQuickAdapter;
+import com.chad.library.adapter.base.BaseViewHolder;
+import com.itant.shibei.R;
+import com.itant.shibei.base.ItemLongClickListener;
+import com.itant.shibei.manager.UserInfoManager;
+import com.miekir.common.utils.ActivityTool;
+import com.miekir.common.utils.ToastTool;
+
+import java.util.List;
+
+
+/**
+ * @author Miekir
+ * @date 2020/7/6 20:08
+ * Description: 首页商品适配器
+ */
+public class TemplateAdapter extends BaseQuickAdapter<CouponBean, BaseViewHolder> {
+    private int mRadius = 8;
+    private Context mContext;
+
+    public TemplateAdapter(Context context, @Nullable List<CouponBean> data) {
+        super(R.layout.item_template, data);
+        mRadius = (int) context.getResources().getDimension(R.dimen.margin_s);
+        mContext = context;
+    }
+
+    @Override
+    protected void convert(@NonNull BaseViewHolder holder, CouponBean couponBean) {
+        ImageView iv_template = holder.getView(R.id.iv_template);
+        // 解决图片错乱
+        iv_template.setTag(R.id.aciv_goods, couponBean.coverUrl);
+        if (couponBean.isCoverUrlLocal) {
+            int resourceId = Integer.parseInt(couponBean.coverUrl);
+            iv_template.setScaleType(ImageView.ScaleType.CENTER_CROP);
+            iv_template.setImageResource(resourceId);
+            //Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), resourceId);
+            // 圆角
+            //RoundedBitmapDrawable roundDrawable = RoundedBitmapDrawableFactory.create(mContext.getResources(), bitmap);
+            //roundDrawable.setCornerRadius(48);
+            //iv_template.setImageDrawable(roundDrawable);
+            // 这些处理都是把drawable圆角了,如果drawable本身尺寸比较小,就起不到圆角效果
+        } else {
+            // 圆角
+            Glide.with(mContext).load(couponBean.coverUrl)
+                    //.transform(new CenterCrop(), new RoundedCorners(48))
+                    //.apply(RequestOptions.bitmapTransform(new RoundedCorners(mRadius)))
+                    //.apply(new RequestOptions()
+                    //        .skipMemoryCache(true)
+                    //        .diskCacheStrategy(DiskCacheStrategy.NONE))
+                    //.centerCrop() 千万不要加,加了就没有圆角效果了
+                    //先加载原图大小的十分之一
+                    .thumbnail(0.1f)
+                    .into(new SimpleTarget<Drawable>() {
+                        @Override
+                        public void onResourceReady(Drawable resource, Transition<? super Drawable> transition) {
+                            //iv_template.setScaleType(ImageView.ScaleType.CENTER_CROP);
+                            //iv_template.setImageDrawable(resource);
+                            if (resource == null) {
+                                iv_template.setImageResource(R.mipmap.logo_gray);
+                                return;
+                            }
+
+                            String coverUrl = null;
+                            try {
+                                coverUrl = (String) iv_template.getTag(R.id.aciv_goods);
+                            } catch (Exception e) {
+                                e.printStackTrace();
+                            }
+                            if (TextUtils.isEmpty(coverUrl) || !TextUtils.equals(coverUrl, couponBean.coverUrl)) {
+                                iv_template.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+                                iv_template.setImageResource(R.mipmap.logo_gray);
+                            } else {
+                                iv_template.setScaleType(ImageView.ScaleType.CENTER_CROP);
+                                iv_template.setImageDrawable(resource);
+                            }
+                        }
+                    });
+        }
+
+
+        holder.setText(R.id.tv_template, couponBean.couponName);
+        holder.setOnClickListener(R.id.rl_template, new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (!couponBean.actionEnable) {
+                    ToastTool.showShort("敬请期待");
+                    return;
+                }
+
+                ActivityTool.openUrl((Activity) mContext, couponBean.jumpUrl);
+            }
+        });
+
+        if (UserInfoManager.getInstance().isLogin() &&
+                TextUtils.equals("[email protected]", UserInfoManager.getInstance().getBeiUser().email)) {
+            View view = holder.getView(R.id.rl_template);
+            view.setOnLongClickListener(v -> {
+                if (couponLongClickListener != null) {
+                    couponLongClickListener.onItemLongClick(holder.getLayoutPosition());
+                }
+                return false;
+            });
+        }
+    }
+
+    private ItemLongClickListener couponLongClickListener;
+    public ItemLongClickListener getCouponLongClickListener() {
+        return couponLongClickListener;
+    }
+
+    public void setCouponLongClickListener(ItemLongClickListener couponListener) {
+        this.couponLongClickListener = couponListener;
+    }
+}

+ 238 - 0
app/src/main/java/com/itant/shibei/ui/home/coupon/TemplateFragment.java

@@ -0,0 +1,238 @@
+package com.itant.shibei.ui.home.coupon;
+
+import android.content.DialogInterface;
+import android.content.Intent;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+
+import com.itant.shibei.R;
+import com.itant.shibei.base.ITopActionListener;
+import com.itant.shibei.tool.DataTool;
+import com.itant.shibei.ui.function.FunctionFragment;
+import com.itant.shibei.ui.mine.coupon.AddCouponActivity;
+import com.itant.shibei.widget.bottomlistener.OnRcvScrollListener;
+import com.itant.shibei.widget.decoration.NormalDividerItemDecoration;
+import com.miekir.common.utils.ToastTool;
+import com.miekir.mvp.presenter.InjectPresenter;
+import com.miekir.mvp.view.BaseMVPFragment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import rx_activity_result2.RxActivityResult;
+
+import static android.app.Activity.RESULT_OK;
+
+/**
+ * 模板Fragment
+ */
+public class TemplateFragment extends BaseMVPFragment implements ITemplateView<CouponBean>, ITopActionListener {
+    private static final int PAGE_START = 0;
+    private static final int PAGE_SIZE = 20;
+    
+    private int mTemplateType = FunctionFragment.TEMPLATE_TYPE_BONUS;
+
+    @InjectPresenter
+    TemplatePresenter mPresenter;
+    
+    private SwipeRefreshLayout srl_template;
+    private List<CouponBean> mCouponBeanList = new ArrayList<>();
+    private TemplateAdapter mAdapter;
+    private RecyclerView rv_template;
+
+    /**当前页*/
+    private int mCurrentPage = PAGE_START;
+    /**是否下拉获取数据*/
+    private boolean mIsRefresh = true;
+
+    public TemplateFragment(int templateType) {
+        mTemplateType = templateType;
+    }
+
+    @Override
+    public int getLayoutResId() {
+        return R.layout.fragment_function_template;
+    }
+
+    @Override
+    protected void onViewInit() {
+        rv_template = rootView.findViewById(R.id.rv_template);
+        // 必须要设置LayoutManager,否则RecyclerView不知道要使用什么布局,从而在界面上不显示
+        LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
+        rv_template.setLayoutManager(layoutManager);
+
+        int dividerWidth = (int) getResources().getDimension(R.dimen.margin_s);
+        NormalDividerItemDecoration decoration = new NormalDividerItemDecoration(dividerWidth);
+        rv_template.addItemDecoration(decoration);
+        mAdapter = new TemplateAdapter(getActivity(), mCouponBeanList);
+        mAdapter.setCouponLongClickListener(this::showAdminDialog);
+        rv_template.setAdapter(mAdapter);
+        // 必须先绑定RecyclerView
+        mAdapter.setEmptyView(R.layout.view_empty, rv_template);
+
+        // 不要滑动一段距离
+        rv_template.smoothScrollToPosition(0);
+        srl_template = rootView.findViewById(R.id.srl_template);
+        srl_template.setColorSchemeResources(
+                R.color.black_theme,
+                R.color.blue_droid,
+                R.color.yellow_droid,
+                R.color.red_droid);
+
+        // 下拉刷新
+        srl_template.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
+            @Override
+            public void onRefresh() {
+                mIsRefresh = true;
+                mCurrentPage = PAGE_START;
+                mPresenter.getTemplateData(mCurrentPage, PAGE_SIZE);
+            }
+        });
+
+        // 加载更多
+        rv_template.addOnScrollListener(new OnRcvScrollListener(){
+            @Override
+            public void onBottom() {
+                super.onBottom();
+                // 如果到底部了,而且不是正在加载状态,就变为正在加载状态,并及时去加载数据
+                if (!srl_template.isRefreshing()) {
+                    mIsRefresh = false;
+                    srl_template.setRefreshing(true);
+                    mPresenter.getTemplateData(mCurrentPage, PAGE_SIZE);
+                }
+            }
+        });
+    }
+
+    @Override
+    protected void onLazyLoad() {
+        // 获取数据
+        srl_template.setRefreshing(true);
+        mPresenter.getTemplateData(mCurrentPage, PAGE_SIZE);
+    }
+
+    /**
+     * 修改商品或者删除商品
+     */
+    private void showAdminDialog(int position) {
+        CouponBean couponBean = mCouponBeanList.get(position);
+        if (couponBean.isLocal) {
+            // 本地写死的不能删除
+            return;
+        }
+        AlertDialog alertDialog = new AlertDialog.Builder(getActivity())
+                .setMessage("选择操作")
+                .setPositiveButton("修改", (dialog, which) -> {
+                    dialog.dismiss();
+                    Intent modifyIntent = new Intent(getActivity(), AddCouponActivity.class);
+                    modifyIntent.putExtra(AddCouponActivity.KEY_MODIFY_COUPON, couponBean);
+                    RxActivityResult.on(getActivity())
+                            .startIntent(modifyIntent)
+                            .filter(result -> result.resultCode() == RESULT_OK)
+                            .doOnNext(result -> {
+                                // 修改商品成功之后刷新item
+                                CouponBean modifiedBean = (CouponBean) result.data().getSerializableExtra(AddCouponActivity.KEY_MODIFY_COUPON);
+                                if (modifiedBean == null) {
+                                    return;
+                                }
+                                couponBean.updateData(modifiedBean);
+                                mAdapter.notifyItemChanged(position);
+                            })
+                            .subscribe();
+                })
+                .setNeutralButton("取消", (dialog, which) -> {
+                    dialog.dismiss();
+                })
+                .setNegativeButton("删除", (DialogInterface dialog, int which) -> {
+                    dialog.dismiss();
+                    showDeleteDialog(position);
+                }).create();
+        alertDialog.setCanceledOnTouchOutside(false);
+        alertDialog.setCancelable(false);
+        alertDialog.show();
+    }
+
+    /**
+     * 是否删除商品
+     */
+    private void showDeleteDialog(int position) {
+        CouponBean couponBean = mCouponBeanList.get(position);
+        AlertDialog alertDialog = new AlertDialog.Builder(getActivity())
+                .setMessage("确定删除优惠券:" + couponBean.couponName)
+                .setNegativeButton("取消", (dialog, which) -> dialog.dismiss())
+                .setPositiveButton("确定", (DialogInterface dialog, int which) -> {
+                    dialog.dismiss();
+                    // 删除商品
+                    mPresenter.deleteCouponById(position, couponBean.id);
+                }).create();
+        alertDialog.show();
+    }
+
+    @Override
+    public void onTemplateDataCome(boolean success, String message, List<CouponBean> couponBeanList) {
+        srl_template.setRefreshing(false);
+        if (!success) {
+            ToastTool.showShort(message);
+            if (mCouponBeanList.size() == 0) {
+                // 本地写死的数据
+                mCouponBeanList.addAll(DataTool.getTemplateList(mTemplateType));
+                mAdapter.notifyDataSetChanged();
+            }
+            return;
+        }
+
+        if (mCurrentPage == PAGE_START) {
+            mCouponBeanList.clear();
+            if (couponBeanList != null) {
+                mCouponBeanList.addAll(couponBeanList);
+            }
+
+            // 本地写死的数据
+            mCouponBeanList.addAll(DataTool.getTemplateList(mTemplateType));
+            mAdapter.notifyDataSetChanged();
+            // 如果是下拉刷新获取的第0页数据,item不要自动滚动一段距离
+            // 或者用这个mLayoutManager.scrollToPositionWithOffset(0, 0);
+            if (mIsRefresh) {
+                ToastTool.showShort("刷新成功");
+                rv_template.smoothScrollToPosition(0);
+            }
+        } else {
+            if (couponBeanList != null) {
+                mCouponBeanList.addAll(couponBeanList);
+            }
+
+            mAdapter.notifyDataSetChanged();
+        }
+
+        // 请求到数据了,页数自增
+        if (couponBeanList != null && couponBeanList.size() > 0) {
+            mCurrentPage++;
+        } else {
+            ToastTool.showShort("没有更多数据了");
+        }
+    }
+
+    /**
+     * 删除商品结果
+     * @param success
+     * @param message
+     * @param position
+     */
+    @Override
+    public void onDeleteCouponResult(boolean success, String message, int position) {
+        if (success) {
+            mAdapter.notifyItemRemoved(position);
+            ToastTool.showShort("删除成功");
+        } else {
+            ToastTool.showShort(message);
+        }
+    }
+
+    @Override
+    public void onTopAction() {
+        rv_template.smoothScrollToPosition(0);
+    }
+}

+ 71 - 0
app/src/main/java/com/itant/shibei/ui/home/coupon/TemplatePresenter.java

@@ -0,0 +1,71 @@
+package com.itant.shibei.ui.home.coupon;
+
+import android.text.TextUtils;
+
+import com.itant.shibei.base.ApiService;
+import com.itant.shibei.net.RetrofitHelper;
+import com.miekir.mvp.presenter.BasePresenter;
+import com.miekir.network.core.base.BaseObserver;
+
+import java.util.List;
+
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/7/8 19:43
+ * Description: 模板的Presenter
+ */
+public class TemplatePresenter extends BasePresenter<ITemplateView<CouponBean>> {
+
+
+    public void getTemplateData(int pageNum, int pageSize) {
+        RetrofitHelper.getInstance()
+                .getRequestApi(ApiService.class)
+                .getCouponList(pageNum, pageSize)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new BaseObserver<List<CouponBean>>() {
+                    @Override
+                    public void onSuccess(List<CouponBean> result) {
+                        if (getView() != null) {
+                            getView().onTemplateDataCome(true, "", result);
+                        }
+                    }
+
+                    @Override
+                    public void onFailure(Throwable e, String errMsg) {
+                        if (getView() != null) {
+                            getView().onTemplateDataCome(false, TextUtils.isEmpty(errMsg) ? "获取失败:"+e.getMessage() : errMsg, null);
+                        }
+                    }
+                });
+    }
+
+
+    public void deleteCouponById(int position, long couponId) {
+        RetrofitHelper.getInstance()
+                .getRequestApi(ApiService.class)
+                .deleteCouponById(couponId)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new BaseObserver<String>() {
+                    @Override
+                    public void onSuccess(String result) {
+                        if (getView() != null) {
+                            getView().onDeleteCouponResult(true, result, position);
+                        }
+                    }
+
+                    @Override
+                    public void onFailure(Throwable e, String errMsg) {
+                        if (getView() != null) {
+                            getView().onDeleteCouponResult(false, TextUtils.isEmpty(errMsg) ? "删除失败:"+e.getMessage() : errMsg, position);
+                        }
+                    }
+                });
+    }
+}

+ 179 - 0
app/src/main/java/com/itant/shibei/ui/home/goods/GoodsAdapter.java

@@ -0,0 +1,179 @@
+package com.itant.shibei.ui.home.goods;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Paint;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
+import com.bumptech.glide.request.RequestOptions;
+import com.bumptech.glide.request.target.SimpleTarget;
+import com.bumptech.glide.request.transition.Transition;
+import com.chad.library.adapter.base.BaseQuickAdapter;
+import com.chad.library.adapter.base.BaseViewHolder;
+import com.itant.shibei.R;
+import com.itant.shibei.base.ItemLongClickListener;
+import com.itant.shibei.constant.ConstantString;
+import com.itant.shibei.manager.UserInfoManager;
+import com.itant.shibei.tool.StringTool;
+import com.itant.shibei.ui.home.goods.play.VideoPlayActivity;
+import com.makeramen.roundedimageview.RoundedImageView;
+import com.miekir.common.utils.ActivityTool;
+import com.miekir.common.utils.ToastTool;
+
+import java.util.List;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/7/6 20:08
+ * Description: 首页商品适配器
+ */
+public class GoodsAdapter extends BaseQuickAdapter<GoodsBean, BaseViewHolder> {
+    private Context mContext;
+    private int mRadius;
+
+    public GoodsAdapter(Context context, @Nullable List<GoodsBean> data) {
+        super(R.layout.item_goods, data);
+        mRadius = (int) context.getResources().getDimension(R.dimen.margin_ss);
+        mContext = context;
+    }
+
+    @Override
+    protected void convert(@NonNull BaseViewHolder holder, GoodsBean goodsBean) {
+        holder.setText(R.id.tv_title, goodsBean.title);
+        holder.setText(R.id.tv_shop_name, goodsBean.shopName);
+
+        // 好评
+        holder.setText(R.id.tv_good_comment,
+                String.format(ConstantString.GOOD_COMMENT, Math.round(goodsBean.goodCommentPercent*100)));
+
+        // 评论条数
+        holder.setText(R.id.tv_comment_num,
+                String.format(ConstantString.COMMENT_NUM, StringTool.getNumberString(goodsBean.commentNum)));
+
+        // 返现
+        TextView tv_rebate = holder.getView(R.id.tv_rebate);
+        tv_rebate.setText(String.format(ConstantString.MONEY_GAME,
+                StringTool.longCent2Yuan(goodsBean.oldPrice-goodsBean.nowPrice)));
+        // 走马灯
+        tv_rebate.setSelected(true);
+
+        // 自营
+        TextView tv_self = holder.getView(R.id.tv_self);
+        if (goodsBean.isSelfBusiness) {
+            tv_self.setVisibility(View.VISIBLE);
+        } else {
+            tv_self.setVisibility(View.GONE);
+        }
+
+        // 原价
+        TextView tv_old_price = holder.getView(R.id.tv_old_price);
+        tv_old_price.setText(String.format(ConstantString.MONEY_RMB, StringTool.longCent2Yuan(goodsBean.oldPrice)));
+        // 增加删除线
+        tv_old_price.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);
+
+        // 现价
+        holder.setText(R.id.tv_now_price, String.format(ConstantString.MONEY_RMB, StringTool.longCent2Yuan(goodsBean.nowPrice)));
+
+        // 一句话推荐
+        TextView tv_reason = holder.getView(R.id.tv_reason);
+        if (TextUtils.isEmpty(goodsBean.reason)) {
+            tv_reason.setText("拾贝推荐");
+        } else {
+            tv_reason.setText(goodsBean.reason);
+        }
+
+        holder.setOnClickListener(R.id.cv_goods, v -> {
+            if (!goodsBean.enable) {
+                ToastTool.showShort("敬请期待");
+                return;
+            }
+            ActivityTool.openUrl((Activity) mContext, goodsBean.goodsUrl);
+        });
+
+        // 解决图片错乱
+        RoundedImageView aciv_goods = holder.getView(R.id.aciv_goods);
+        aciv_goods.setTag(R.id.aciv_goods, goodsBean.coverImageUrl);
+        Glide.with(mContext).load(goodsBean.coverImageUrl)
+                .apply(RequestOptions.bitmapTransform(new RoundedCorners(mRadius)))
+                //.apply(new RequestOptions()
+                //        .skipMemoryCache(true)
+                //        .diskCacheStrategy(DiskCacheStrategy.NONE))
+                //先加载原图大小的十分之一
+                .thumbnail(0.1f)
+                .into(new SimpleTarget<Drawable>() {
+                    @Override
+                    public void onResourceReady(Drawable resource, Transition<? super Drawable> transition) {
+                        if (resource == null) {
+                            aciv_goods.setImageResource(R.mipmap.logo_gray);
+                            return;
+                        }
+
+                        String coverUrl = null;
+                        try {
+                            coverUrl = (String) aciv_goods.getTag(R.id.aciv_goods);
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                        }
+                        if (TextUtils.isEmpty(coverUrl) || !TextUtils.equals(coverUrl, goodsBean.coverImageUrl)) {
+                            aciv_goods.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+                            aciv_goods.setImageResource(R.mipmap.logo_gray);
+                        } else {
+                            aciv_goods.setScaleType(ImageView.ScaleType.CENTER_CROP);
+                            aciv_goods.setImageDrawable(resource);
+                        }
+                    }
+                });
+
+        View fl_video_play = holder.getView(R.id.fl_video_play);
+        View iv_video_play = holder.getView(R.id.iv_video_play);
+        if (!TextUtils.isEmpty(goodsBean.videoUrl)) {
+            iv_video_play.setVisibility(View.VISIBLE);
+            fl_video_play.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    // 全屏播放视频
+                    Intent playIntent = new Intent(mContext, VideoPlayActivity.class);
+                    playIntent.putExtra(VideoPlayActivity.KEY_URL, goodsBean.videoUrl);
+                    playIntent.putExtra(VideoPlayActivity.KEY_TITLE, goodsBean.title);
+                    mContext.startActivity(playIntent);
+                    //JzvdStd.startFullscreen(this, JZVideoPlayerStandard.class, "http://2449.vod.myqcloud.com/2449_22ca37a6ea9011e5acaaf51d105342e3.f20.mp4", "嫂子辛苦了");
+                }
+            });
+        } else {
+            iv_video_play.setVisibility(View.GONE);
+        }
+
+        if (UserInfoManager.getInstance().isLogin() &&
+                TextUtils.equals("[email protected]", UserInfoManager.getInstance().getBeiUser().email)) {
+            View view = holder.getView(R.id.cv_goods);
+            view.setOnLongClickListener(v -> {
+                if (goodsLongClickListener != null) {
+                    goodsLongClickListener.onItemLongClick(holder.getLayoutPosition());
+                }
+                return false;
+            });
+        }
+    }
+
+    private ItemLongClickListener goodsLongClickListener;
+    public ItemLongClickListener getGoodsLongClickListener() {
+        return goodsLongClickListener;
+    }
+
+    public void setGoodsLongClickListener(ItemLongClickListener goodsLongClickListener) {
+        this.goodsLongClickListener = goodsLongClickListener;
+    }
+
+}

+ 136 - 0
app/src/main/java/com/itant/shibei/ui/home/goods/GoodsBean.java

@@ -0,0 +1,136 @@
+package com.itant.shibei.ui.home.goods;
+
+import java.io.Serializable;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/7/5 21:50
+ * Description: 商品实体
+ */
+public class GoodsBean implements Serializable {
+    public static final int TYPE_RECOMMEND = 0;
+    public static final int TYPE_TECHNOLOGY = 1;
+    public static final int TYPE_LIFE = 2;
+    public static final int TYPE_NETWORK = 3;
+
+
+    /**
+     * 商品id
+     */
+    public long id;
+    /**
+     * 封面图片地址
+     */
+    public String coverImageUrl;
+    /**
+     * 体验视频地址
+     */
+    public String videoUrl;
+    /**
+     * 标题
+     */
+    public String title;
+    /**
+     * 商品描述
+     */
+    public String description;
+    /**
+     * 商品推荐理由(一句话推荐、推荐者心声)
+     */
+    public String reason;
+    /**
+     * 原价
+     */
+    public long oldPrice;
+    /**
+     * 现价
+     */
+    public long nowPrice;
+    /**
+     * 返利
+     */
+    public long rebate;
+    /**
+     * 店名
+     */
+    public String shopName;
+    /**
+     * 商店所属省份
+     */
+    public String province;
+    /**
+     * 是否自营
+     */
+    public boolean isSelfBusiness;
+    /**
+     * 是否有券
+     */
+    public boolean hasCoupon;
+    /**
+     * 优惠券信息
+     */
+    public String couponInfo;
+    /**
+     * 所属类型
+     */
+    public int goodsType;
+    /**
+     * 商品链接
+     */
+    public String goodsUrl;
+    /**
+     * 月销量
+     */
+    public long salesPerMonth;
+
+    /**
+     * 评论条数
+     */
+    public long commentNum;
+
+    /**
+     * 好评率
+     */
+    public double goodCommentPercent;
+
+    /**
+     * 创建时间
+     */
+    public long createTimeMillis;
+
+    /**
+     * 更新时间
+     */
+    public long updateTimeMillis;
+
+    public boolean enable;
+
+    /**是否是本地写死的数据*/
+    public boolean isLocal;
+
+    public void updateData(GoodsBean goodsBean) {
+        this.coverImageUrl = goodsBean.coverImageUrl;
+        this.videoUrl = goodsBean.videoUrl;
+        this.title = goodsBean.title;
+        this.description = goodsBean.description;
+        this.reason = goodsBean.reason;
+        this.oldPrice = goodsBean.oldPrice;
+        this.nowPrice = goodsBean.nowPrice;
+        this.rebate = goodsBean.rebate;
+        this.shopName = goodsBean.shopName;
+        this.province = goodsBean.province;
+        this.isSelfBusiness = goodsBean.isSelfBusiness;
+        this.hasCoupon = goodsBean.hasCoupon;
+        this.couponInfo = goodsBean.couponInfo;
+        this.goodsType = goodsBean.goodsType;
+        this.goodsUrl = goodsBean.goodsUrl;
+        this.salesPerMonth = goodsBean.salesPerMonth;
+        this.goodCommentPercent = goodsBean.goodCommentPercent;
+        this.createTimeMillis = goodsBean.createTimeMillis;
+        this.updateTimeMillis = goodsBean.updateTimeMillis;
+        this.enable = goodsBean.enable;
+        this.isLocal = goodsBean.isLocal;
+    }
+}

+ 243 - 0
app/src/main/java/com/itant/shibei/ui/home/goods/GoodsFragment.java

@@ -0,0 +1,243 @@
+package com.itant.shibei.ui.home.goods;
+
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.util.TypedValue;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+
+import com.itant.shibei.R;
+import com.itant.shibei.base.ITopActionListener;
+import com.itant.shibei.tool.DataTool;
+import com.itant.shibei.ui.mine.goods.AddGoodsActivity;
+import com.itant.shibei.widget.bottomlistener.OnRcvScrollListener;
+import com.itant.shibei.widget.decoration.SpacesItemDecoration;
+import com.miekir.common.utils.ToastTool;
+import com.miekir.mvp.presenter.InjectPresenter;
+import com.miekir.mvp.view.BaseMVPFragment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import rx_activity_result2.RxActivityResult;
+
+import static android.app.Activity.RESULT_OK;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/7/5 22:07
+ * Description: 商品列表Fragment
+ */
+public class GoodsFragment extends BaseMVPFragment implements IGoodsView, ITopActionListener {
+    private static final int PAGE_START = 0;
+    private static final int PAGE_SIZE = 20;
+
+    @InjectPresenter
+    GoodsPresenter goodsPresenter;
+
+    private SwipeRefreshLayout srl_goods;
+    private GoodsAdapter mAdapter;
+    private RecyclerView rv_goods;
+    private List<GoodsBean> mGoodsList = new ArrayList<>();
+
+    /**当前页*/
+    private int mCurrentPage = PAGE_START;
+    /**是否下拉获取数据*/
+    private boolean mIsRefresh = true;
+
+
+    @Override
+    public int getLayoutResId() {
+        return R.layout.fragment_home_goods;
+    }
+
+    @Override
+    protected void onViewInit() {
+        rv_goods = rootView.findViewById(R.id.rv_goods);
+        // 必须要设置LayoutManager,否则RecyclerView不知道要使用什么布局,从而在界面上不显示
+        LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
+        rv_goods.setLayoutManager(layoutManager);
+
+        //int dividerWidth = (int) getResources().getDimension(R.dimen.margin_s);
+        //DividerItemDecoration decoration = new DividerItemDecoration(dividerWidth);
+        int dividerWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getResources().getDisplayMetrics());
+        SpacesItemDecoration decoration = new SpacesItemDecoration(dividerWidth);
+        rv_goods.addItemDecoration(decoration);
+        mAdapter = new GoodsAdapter(getActivity(), mGoodsList);
+        mAdapter.setGoodsLongClickListener(this::showAdminDialog);
+        rv_goods.setAdapter(mAdapter);
+        // 必须先绑定RecyclerView
+        mAdapter.setEmptyView(R.layout.view_empty, rv_goods);
+        // 不要滑动一段距离
+        rv_goods.smoothScrollToPosition(0);
+        srl_goods = rootView.findViewById(R.id.srl_goods);
+        srl_goods.setColorSchemeResources(
+                R.color.black_theme,
+                R.color.blue_droid,
+                R.color.yellow_droid,
+                R.color.red_droid);
+
+        // 下拉刷新
+        srl_goods.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
+            @Override
+            public void onRefresh() {
+                mIsRefresh = true;
+                mCurrentPage = PAGE_START;
+                goodsPresenter.getGoodsData(mCurrentPage, PAGE_SIZE);
+            }
+        });
+
+        // 加载更多
+        rv_goods.addOnScrollListener(new OnRcvScrollListener(){
+            @Override
+            public void onBottom() {
+                super.onBottom();
+                // 如果到底部了,而且不是正在加载状态,就变为正在加载状态,并及时去加载数据
+                if (!srl_goods.isRefreshing()) {
+                    mIsRefresh = false;
+                    srl_goods.setRefreshing(true);
+                    goodsPresenter.getGoodsData(mCurrentPage, PAGE_SIZE);
+                }
+            }
+        });
+    }
+
+    @Override
+    protected void onLazyLoad() {
+        // 获取数据
+        srl_goods.setRefreshing(true);
+        goodsPresenter.getGoodsData(mCurrentPage, PAGE_SIZE);
+    }
+
+    /**
+     * 修改商品或者删除商品
+     */
+    private void showAdminDialog(int position) {
+        GoodsBean goodsBean = mGoodsList.get(position);
+        if (goodsBean.isLocal) {
+            // 本地写死的不能删除
+            return;
+        }
+        AlertDialog alertDialog = new AlertDialog.Builder(getActivity())
+                .setMessage("选择操作")
+                .setPositiveButton("修改", (dialog, which) -> {
+                    dialog.dismiss();
+                    Intent modifyIntent = new Intent(getActivity(), AddGoodsActivity.class);
+                    modifyIntent.putExtra(AddGoodsActivity.KEY_MODIFY_GOODS, goodsBean);
+                    RxActivityResult.on(getActivity()).startIntent(modifyIntent)
+                            .filter(result -> result.resultCode() == RESULT_OK)
+                            .doOnNext(result -> {
+                                // 修改商品成功之后刷新item
+                                GoodsBean modifiedBean = (GoodsBean) result.data().getSerializableExtra(AddGoodsActivity.KEY_MODIFY_GOODS);
+                                if (modifiedBean == null) {
+                                    return;
+                                }
+                                goodsBean.updateData(modifiedBean);
+                                mAdapter.notifyItemChanged(position);
+                            })
+                            .subscribe();
+                })
+                .setNeutralButton("取消", (dialog, which) -> {
+                    dialog.dismiss();
+                })
+                .setNegativeButton("删除", (DialogInterface dialog, int which) -> {
+                    dialog.dismiss();
+                    showDeleteDialog(position);
+                }).create();
+        alertDialog.setCanceledOnTouchOutside(false);
+        alertDialog.setCancelable(false);
+        alertDialog.show();
+    }
+
+    /**
+     * 是否删除商品
+     */
+    private void showDeleteDialog(int position) {
+        GoodsBean goodsBean = mGoodsList.get(position);
+        AlertDialog alertDialog = new AlertDialog.Builder(getActivity())
+                .setMessage("确定删除商品:" + goodsBean.title)
+                .setNegativeButton("取消", (dialog, which) -> dialog.dismiss())
+                .setPositiveButton("确定", (DialogInterface dialog, int which) -> {
+                    dialog.dismiss();
+                    // 删除商品
+                    goodsPresenter.deleteGoodsById(position, goodsBean.id);
+                }).create();
+        alertDialog.show();
+    }
+
+    /**
+     * 获取商品结果
+     * @param success
+     * @param message
+     * @param goodsList
+     */
+    @Override
+    public void onGoodsDataCome(boolean success, String message, List<GoodsBean> goodsList) {
+        srl_goods.setRefreshing(false);
+        if (!success) {
+            if (mGoodsList.size() == 0) {
+                // 本地写死的数据
+                mGoodsList.addAll(DataTool.getGoodsList());
+                mAdapter.notifyDataSetChanged();
+            }
+            ToastTool.showShort(message);
+            return;
+        }
+
+        if (mCurrentPage == PAGE_START) {
+            mGoodsList.clear();
+            if (goodsList != null) {
+                mGoodsList.addAll(goodsList);
+            }
+
+            // 本地写死的数据
+            mGoodsList.addAll(DataTool.getGoodsList());
+            mAdapter.notifyDataSetChanged();
+            // 如果是下拉刷新获取的第0页数据,item不要自动滚动一段距离
+            // 或者用这个mLayoutManager.scrollToPositionWithOffset(0, 0);
+            if (mIsRefresh) {
+                ToastTool.showShort("刷新成功");
+                rv_goods.smoothScrollToPosition(0);
+            }
+        } else {
+            if (goodsList != null) {
+                mGoodsList.addAll(goodsList);
+            }
+
+            mAdapter.notifyDataSetChanged();
+        }
+
+        // 请求到数据了,页数自增
+        if (goodsList != null && goodsList.size() > 0) {
+            mCurrentPage++;
+        } else {
+            ToastTool.showShort("没有更多数据了");
+        }
+    }
+
+    /**
+     * 删除商品结果
+     * @param success
+     * @param message
+     * @param position
+     */
+    @Override
+    public void onDeleteGoodsResult(boolean success, String message, int position) {
+        if (success) {
+            mAdapter.notifyItemRemoved(position);
+            ToastTool.showShort("删除成功");
+        } else {
+            ToastTool.showShort(message);
+        }
+    }
+
+    @Override
+    public void onTopAction() {
+        rv_goods.smoothScrollToPosition(0);
+    }
+}

+ 68 - 0
app/src/main/java/com/itant/shibei/ui/home/goods/GoodsPresenter.java

@@ -0,0 +1,68 @@
+package com.itant.shibei.ui.home.goods;
+
+import android.text.TextUtils;
+
+import com.itant.shibei.base.ApiService;
+import com.itant.shibei.net.RetrofitHelper;
+import com.miekir.mvp.presenter.BasePresenter;
+import com.miekir.network.core.base.BaseObserver;
+
+import java.util.List;
+
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/7/9 20:54
+ * Description: 商品的相关数据接口处理
+ */
+public class GoodsPresenter extends BasePresenter<IGoodsView> {
+    public void getGoodsData(int pageNum, int pageSize) {
+        RetrofitHelper.getInstance()
+                .getRequestApi(ApiService.class)
+                .getGoodsList(pageNum, pageSize)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new BaseObserver<List<GoodsBean>>() {
+                    @Override
+                    public void onSuccess(List<GoodsBean> result) {
+                        if (getView() != null) {
+                            getView().onGoodsDataCome(true, "", result);
+                        }
+                    }
+
+                    @Override
+                    public void onFailure(Throwable e, String errMsg) {
+                        if (getView() != null) {
+                            getView().onGoodsDataCome(false, TextUtils.isEmpty(errMsg) ? "获取失败:"+e.getMessage() : errMsg, null);
+                        }
+                    }
+                });
+    }
+
+    public void deleteGoodsById(int position, long goodsId) {
+        RetrofitHelper.getInstance()
+                .getRequestApi(ApiService.class)
+                .deleteGoodsById(goodsId)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new BaseObserver<String>() {
+                    @Override
+                    public void onSuccess(String result) {
+                        if (getView() != null) {
+                            getView().onDeleteGoodsResult(true, result, position);
+                        }
+                    }
+
+                    @Override
+                    public void onFailure(Throwable e, String errMsg) {
+                        if (getView() != null) {
+                            getView().onDeleteGoodsResult(false, TextUtils.isEmpty(errMsg) ? "删除失败:"+e.getMessage() : errMsg, position);
+                        }
+                    }
+                });
+    }
+}

+ 17 - 0
app/src/main/java/com/itant/shibei/ui/home/goods/IGoodsView.java

@@ -0,0 +1,17 @@
+package com.itant.shibei.ui.home.goods;
+
+import com.miekir.mvp.view.IView;
+
+import java.util.List;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/7/9 20:52
+ * Description: 商品的View回调
+ */
+public interface IGoodsView extends IView {
+    void onGoodsDataCome(boolean success, String message, List<GoodsBean> goodsList);
+    void onDeleteGoodsResult(boolean success, String message, int position);
+}

+ 62 - 0
app/src/main/java/com/itant/shibei/ui/home/goods/play/VideoPlayActivity.java

@@ -0,0 +1,62 @@
+package com.itant.shibei.ui.home.goods.play;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+
+import com.itant.shibei.R;
+import com.itant.shibei.widget.VideoPlayer;
+
+import cn.jzvd.Jzvd;
+import cn.jzvd.JzvdStd;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/8/25 11:28
+ * Description: 视频播放类,这是一个全屏的界面
+ */
+public class VideoPlayActivity extends Activity {
+    public static final String KEY_URL = "url";
+    public static final String KEY_TITLE = "title";
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_video_play);
+
+        String url = getIntent().getStringExtra(KEY_URL);
+        String title = getIntent().getStringExtra(KEY_TITLE);
+
+        Jzvd.WIFI_TIP_DIALOG_SHOWED = true;
+        // 直接播放视频
+        VideoPlayer.setVideoPlayListener(new VideoPlayer.VideoPlayListener() {
+            @Override
+            public void onPlayComplete() {
+                finish();
+            }
+        });
+        JzvdStd.setCurrentJzvd(VideoPlayer.CURRENT_JZVD);
+        JzvdStd.startFullscreenDirectly(this, VideoPlayer.class, url, title);
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        Jzvd.releaseAllVideos();
+    }
+
+    @Override
+    public void onBackPressed() {
+        Jzvd.backPress();
+        super.onBackPressed();
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        VideoPlayer.setVideoPlayListener(null);
+    }
+}

+ 16 - 0
app/src/main/java/com/itant/shibei/ui/home/search/ISearchView.java

@@ -0,0 +1,16 @@
+package com.itant.shibei.ui.home.search;
+
+import com.itant.shibei.ui.home.goods.GoodsBean;
+import com.miekir.mvp.view.IView;
+
+import java.util.List;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/7/8 19:44
+ */
+public interface ISearchView extends IView {
+    void onSearchKeywordResult(boolean success, String message, List<GoodsBean> goodsList);
+}

+ 267 - 0
app/src/main/java/com/itant/shibei/ui/home/search/SearchActivity.java

@@ -0,0 +1,267 @@
+package com.itant.shibei.ui.home.search;
+
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.itant.shibei.R;
+import com.itant.shibei.base.BaseBeiActivity;
+import com.itant.shibei.ui.home.goods.GoodsAdapter;
+import com.itant.shibei.ui.home.goods.GoodsBean;
+import com.itant.shibei.ui.home.goods.GoodsPresenter;
+import com.itant.shibei.ui.home.goods.IGoodsView;
+import com.itant.shibei.ui.mine.goods.AddGoodsActivity;
+import com.itant.shibei.widget.bottomlistener.OnRcvScrollListener;
+import com.itant.shibei.widget.decoration.CardViewDividerItemDecoration;
+import com.miekir.common.utils.ToastTool;
+import com.miekir.common.utils.ViewTool;
+import com.miekir.mvp.presenter.InjectPresenter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import rx_activity_result2.RxActivityResult;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/8/12 19:40
+ * Description: 输入文字搜索
+ */
+public class SearchActivity extends BaseBeiActivity implements View.OnClickListener, ISearchView, View.OnFocusChangeListener, IGoodsView {
+    private static final int PAGE_START = 0;
+    private static final int PAGE_SIZE = 20;
+    private int mCurrentPage = PAGE_START;
+
+    private EditText et_search;
+    private Button btn_search;
+
+    private RecyclerView rv_search_result;
+    private List<GoodsBean> mGoodsList = new ArrayList<>();
+    private GoodsAdapter mAdapter;
+    private boolean mIsRefresh = true;
+
+    private String mKeyword;
+
+    @InjectPresenter
+    SearchPresenter searchPresenter;
+
+    @InjectPresenter
+    GoodsPresenter goodsPresenter;
+
+    @Override
+    public int getLayoutID() {
+        return R.layout.activity_search;
+    }
+
+    @Override
+    public void initViews(Bundle savedInstanceState) {
+        setTitle("搜索");
+        et_search = findViewById(R.id.et_search);
+        et_search.setOnFocusChangeListener(this);
+        btn_search = findViewById(R.id.btn_search);
+
+        rv_search_result = findViewById(R.id.rv_search_result);
+        // 必须要设置LayoutManager,否则RecyclerView不知道要使用什么布局,从而在界面上不显示
+        LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
+        rv_search_result.setLayoutManager(layoutManager);
+        int dividerWidth = (int) getResources().getDimension(R.dimen.margin_s);
+        CardViewDividerItemDecoration decoration = new CardViewDividerItemDecoration(dividerWidth);
+        rv_search_result.addItemDecoration(decoration);
+        mAdapter = new GoodsAdapter(this, mGoodsList);
+        mAdapter.setGoodsLongClickListener(this::showAdminDialog);
+        rv_search_result.setAdapter(mAdapter);
+        mAdapter.setEmptyView(R.layout.view_empty, rv_search_result);
+        // 加载更多
+        rv_search_result.addOnScrollListener(new OnRcvScrollListener(){
+            @Override
+            public void onBottom() {
+                super.onBottom();
+                if (mKeyword.startsWith("http")) {
+                    // 搜索链接不要加载更多功能
+                    return;
+                }
+                // 如果到底部了,而且不是正在加载状态,就变为正在加载状态,并及时去加载数据
+                showLoading();
+                mIsRefresh = false;
+                searchPresenter.searchByKeyword(mKeyword, mCurrentPage, PAGE_SIZE);
+            }
+        });
+
+        ViewTool.requestInputFocus(this, et_search);
+        ViewTool.setOnClickListener(this, this, new int[]{R.id.ll_search, R.id.btn_search, R.id.fl_clear});
+    }
+
+    @Override
+    public void onClick(View v) {
+
+        switch (v.getId()) {
+            case R.id.btn_search:
+                et_search.clearFocus();
+                mKeyword = et_search.getText().toString();
+                if (TextUtils.isEmpty(mKeyword)) {
+                    ToastTool.showShort("请输入关键字或链接");
+                    return;
+                }
+                showLoading();
+                mCurrentPage = PAGE_START;
+                mGoodsList.clear();
+                mAdapter.notifyDataSetChanged();
+                mIsRefresh = true;
+                searchPresenter.searchByKeyword(mKeyword, mCurrentPage, PAGE_SIZE);
+                break;
+            case R.id.ll_search:
+                et_search.clearFocus();
+                break;
+            case R.id.fl_clear:
+                et_search.setText("");
+                ViewTool.requestInputFocus(this, et_search);
+                break;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * 修改商品或者删除商品
+     */
+    private void showAdminDialog(int position) {
+        GoodsBean goodsBean = mGoodsList.get(position);
+        if (goodsBean.isLocal) {
+            // 本地写死的不能删除
+            return;
+        }
+        AlertDialog alertDialog = new AlertDialog.Builder(this)
+                .setMessage("选择操作")
+                .setPositiveButton("修改", (dialog, which) -> {
+                    dialog.dismiss();
+                    Intent modifyIntent = new Intent(this, AddGoodsActivity.class);
+                    modifyIntent.putExtra(AddGoodsActivity.KEY_MODIFY_GOODS, goodsBean);
+                    RxActivityResult.on(this).startIntent(modifyIntent)
+                            .filter(result -> result.resultCode() == RESULT_OK)
+                            .doOnNext(result -> {
+                                // 修改商品成功之后刷新item
+                                GoodsBean modifiedBean = (GoodsBean) result.data().getSerializableExtra(AddGoodsActivity.KEY_MODIFY_GOODS);
+                                if (modifiedBean == null) {
+                                    return;
+                                }
+                                goodsBean.updateData(modifiedBean);
+                                mAdapter.notifyItemChanged(position);
+                            })
+                            .subscribe();
+                })
+                .setNeutralButton("取消", (dialog, which) -> {
+                    dialog.dismiss();
+                })
+                .setNegativeButton("删除", (DialogInterface dialog, int which) -> {
+                    dialog.dismiss();
+                    showDeleteDialog(position);
+                }).create();
+        alertDialog.setCanceledOnTouchOutside(false);
+        alertDialog.setCancelable(false);
+        alertDialog.show();
+    }
+
+    /**
+     * 是否删除商品
+     */
+    private void showDeleteDialog(int position) {
+        GoodsBean goodsBean = mGoodsList.get(position);
+        AlertDialog alertDialog = new AlertDialog.Builder(this)
+                .setMessage("确定删除商品:" + goodsBean.title)
+                .setNegativeButton("取消", (dialog, which) -> dialog.dismiss())
+                .setPositiveButton("确定", (DialogInterface dialog, int which) -> {
+                    dialog.dismiss();
+                    // 删除商品
+                    goodsPresenter.deleteGoodsById(position, goodsBean.id);
+                }).create();
+        alertDialog.show();
+    }
+
+    @Override
+    public void onSearchKeywordResult(boolean success, String message, List<GoodsBean> goodsList) {
+        dismissLoading();
+
+        if (!success) {
+            ToastTool.showShort(message);
+            return;
+        }
+
+        if (mCurrentPage == PAGE_START) {
+            mGoodsList.clear();
+            if (goodsList != null) {
+                mGoodsList.addAll(goodsList);
+            }
+
+            // 本地写死的数据
+            mAdapter.notifyDataSetChanged();
+            // 如果是下拉刷新获取的第0页数据,item不要自动滚动一段距离
+            // 或者用这个mLayoutManager.scrollToPositionWithOffset(0, 0);
+            if (mIsRefresh) {
+                rv_search_result.smoothScrollToPosition(0);
+            }
+        } else {
+            if (goodsList != null) {
+                mGoodsList.addAll(goodsList);
+            }
+
+            mAdapter.notifyDataSetChanged();
+        }
+
+        // 请求到数据了,页数自增
+        if (goodsList != null && goodsList.size() > 0) {
+            mCurrentPage++;
+        } else {
+            ToastTool.showShort("没有更多数据了");
+        }
+    }
+
+    /**
+     * 获取商品结果
+     * @param success
+     * @param message
+     * @param goodsList
+     */
+    @Override
+    public void onGoodsDataCome(boolean success, String message, List<GoodsBean> goodsList) {
+
+    }
+
+    /**
+     * 删除商品结果
+     * @param success
+     * @param message
+     * @param position
+     */
+    @Override
+    public void onDeleteGoodsResult(boolean success, String message, int position) {
+        if (success) {
+            mAdapter.notifyItemRemoved(position);
+            ToastTool.showShort("删除成功");
+        } else {
+            ToastTool.showShort(message);
+        }
+    }
+
+    @Override
+    public void onFocusChange(View v, boolean hasFocus) {
+        if (v.getId() == R.id.et_search) {
+            if (hasFocus) {
+                rv_search_result.setVisibility(View.GONE);
+                btn_search.setVisibility(View.VISIBLE);
+            } else {
+                rv_search_result.setVisibility(View.VISIBLE);
+                btn_search.setVisibility(View.GONE);
+            }
+        }
+    }
+}

+ 47 - 0
app/src/main/java/com/itant/shibei/ui/home/search/SearchPresenter.java

@@ -0,0 +1,47 @@
+package com.itant.shibei.ui.home.search;
+
+import android.text.TextUtils;
+
+import com.itant.shibei.base.ApiService;
+import com.itant.shibei.net.RetrofitHelper;
+import com.itant.shibei.ui.home.goods.GoodsBean;
+import com.miekir.mvp.presenter.BasePresenter;
+import com.miekir.network.core.base.BaseObserver;
+
+import java.util.List;
+
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/8/16 9:34
+ * Description: 搜索
+ */
+public class SearchPresenter extends BasePresenter<ISearchView> {
+
+    public void searchByKeyword(String keyword, int pageNum, int pageSize) {
+        RetrofitHelper.getInstance()
+                .getRequestApi(ApiService.class)
+                .getGoodsListByKeyword(keyword, pageNum, pageSize)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new BaseObserver<List<GoodsBean>>() {
+                    @Override
+                    public void onSuccess(List<GoodsBean> result) {
+                        if (getView() != null) {
+                            getView().onSearchKeywordResult(true, "", result);
+                        }
+                    }
+
+                    @Override
+                    public void onFailure(Throwable e, String errMsg) {
+                        if (getView() != null) {
+                            getView().onSearchKeywordResult(false, TextUtils.isEmpty(errMsg) ? "获取失败:"+e.getMessage() : errMsg, null);
+                        }
+                    }
+                });
+    }
+}

+ 15 - 0
app/src/main/java/com/itant/shibei/ui/home/tool/ISystemView.java

@@ -0,0 +1,15 @@
+package com.itant.shibei.ui.home.tool;
+
+import com.itant.shibei.bean.SystemBean;
+import com.miekir.mvp.view.IView;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/7/8 19:44
+ */
+public interface ISystemView extends IView {
+    void onGetConfigResult(boolean success, String message, SystemBean resultBean);
+    void onSetApiResult(boolean success, String message, String resultBean);
+}

+ 74 - 0
app/src/main/java/com/itant/shibei/ui/home/tool/SystemPresenter.java

@@ -0,0 +1,74 @@
+package com.itant.shibei.ui.home.tool;
+
+import android.text.TextUtils;
+
+import com.itant.shibei.base.ApiService;
+import com.itant.shibei.bean.SystemBean;
+import com.itant.shibei.net.RetrofitHelper;
+import com.miekir.mvp.presenter.BasePresenter;
+import com.miekir.network.core.base.BaseObserver;
+
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/8/20 19:18
+ * Description:
+ */
+public class SystemPresenter extends BasePresenter<ISystemView> {
+
+    /**
+     * 获取配置信息
+     */
+    public void getSystemConfig() {
+        RetrofitHelper.getInstance()
+                .getRequestApi(ApiService.class)
+                .getSystemConfig()
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new BaseObserver<SystemBean>() {
+                    @Override
+                    public void onSuccess(SystemBean result) {
+                        if (getView() != null) {
+                            getView().onGetConfigResult(true, "", result);
+                        }
+                    }
+
+                    @Override
+                    public void onFailure(Throwable e, String errMsg) {
+                        if (getView() != null) {
+                            getView().onGetConfigResult(false, TextUtils.isEmpty(errMsg) ? "获取失败:"+e.getMessage() : errMsg, null);
+                        }
+                    }
+                });
+    }
+
+    /**
+     * 设置API是否仅对会员开放
+     */
+    public void setApiConfig(boolean isApiVipOnly) {
+        RetrofitHelper.getInstance()
+                .getRequestApi(ApiService.class)
+                .setApiConfig(isApiVipOnly)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new BaseObserver<String>() {
+                    @Override
+                    public void onSuccess(String result) {
+                        if (getView() != null) {
+                            getView().onSetApiResult(true, "", result);
+                        }
+                    }
+
+                    @Override
+                    public void onFailure(Throwable e, String errMsg) {
+                        if (getView() != null) {
+                            getView().onSetApiResult(false, TextUtils.isEmpty(errMsg) ? "设置失败:"+e.getMessage() : errMsg, null);
+                        }
+                    }
+                });
+    }
+}

+ 122 - 0
app/src/main/java/com/itant/shibei/ui/home/tool/ToolFragment.java

@@ -0,0 +1,122 @@
+package com.itant.shibei.ui.home.tool;
+
+import android.content.Intent;
+import android.view.View;
+import android.widget.TextView;
+
+import com.itant.shibei.R;
+import com.itant.shibei.bean.SystemBean;
+import com.itant.shibei.constant.ConstantUrl;
+import com.itant.shibei.manager.UserInfoManager;
+import com.itant.shibei.ui.home.tool.json.JsonActivity;
+import com.itant.shibei.ui.home.tool.weather.WeatherActivity;
+import com.itant.shibei.ui.home.tool.yiji.YijiActivity;
+import com.itant.shibei.ui.mine.login.LoginActivity;
+import com.miekir.common.utils.ActivityTool;
+import com.miekir.common.utils.ToastTool;
+import com.miekir.mvp.presenter.InjectPresenter;
+import com.miekir.mvp.view.BaseMVPFragment;
+
+/**
+ * @author Miekir
+ * @date 2020/6/18 16:48
+ * Description: 工具界面
+ */
+public class ToolFragment extends BaseMVPFragment implements View.OnClickListener, ISystemView {
+
+    @InjectPresenter
+    SystemPresenter mSystemPresenter;
+
+    private TextView tv_weather;
+    private TextView tv_yiji;
+
+    @Override
+    protected void onViewInit() {
+        tv_weather = rootView.findViewById(R.id.tv_weather);
+        tv_yiji = rootView.findViewById(R.id.tv_yiji);
+        rootView.findViewById(R.id.fl_get_json).setOnClickListener(this);
+        rootView.findViewById(R.id.fl_pc_template).setOnClickListener(this);
+        rootView.findViewById(R.id.fl_weather).setOnClickListener(this);
+        rootView.findViewById(R.id.fl_yiji).setOnClickListener(this);
+        rootView.findViewById(R.id.fl_biao_qing).setOnClickListener(this);
+    }
+
+    @Override
+    protected void onLazyLoad() {
+        mSystemPresenter.getSystemConfig();
+    }
+
+    @Override
+    public int getLayoutResId() {
+        return R.layout.fragment_tool;
+    }
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+
+            case R.id.fl_pc_template:
+                // 跳转京东模板
+                ActivityTool.openUrl(getActivity(), ConstantUrl.URL_JD_TEMPLATE_COMPUTER);
+                break;
+            case R.id.fl_get_json:
+                // JSON界面
+                if (UserInfoManager.getInstance().isLogin()) {
+                    startActivity(new Intent(getActivity(), JsonActivity.class));
+                } else {
+                    ToastTool.showShort("请先登录");
+                    startActivity(new Intent(getActivity(), LoginActivity.class));
+                }
+                break;
+
+            case R.id.fl_weather:
+                // 天气界面
+                if (UserInfoManager.getInstance().isLogin()) {
+                    startActivity(new Intent(getActivity(), WeatherActivity.class));
+                } else {
+                    ToastTool.showShort("请先登录");
+                    startActivity(new Intent(getActivity(), LoginActivity.class));
+                }
+                break;
+
+            case R.id.fl_yiji:
+                // 宜忌信息
+                if (UserInfoManager.getInstance().isLogin()) {
+                    startActivity(new Intent(getActivity(), YijiActivity.class));
+                } else {
+                    ToastTool.showShort("请先登录");
+                    startActivity(new Intent(getActivity(), LoginActivity.class));
+                }
+                break;
+
+            case R.id.fl_biao_qing:
+                // 跳转表情包
+                ActivityTool.openUrl(getActivity(), ConstantUrl.URL_BIAO_QING);
+                break;
+            default:
+                break;
+        }
+    }
+
+    @Override
+    public void onGetConfigResult(boolean success, String message, SystemBean resultBean) {
+        if (!success || resultBean == null) {
+            return;
+        }
+
+        String tips;
+        if (resultBean.isVipLimit) {
+            tips = getResources().getString(R.string.api_tips_vip_only);
+        } else {
+            tips = getResources().getString(R.string.api_tips_free);
+        }
+
+        tv_weather.setText(tv_weather.getText().toString() + tips);
+        tv_yiji.setText(tv_yiji.getText().toString() + tips);
+    }
+
+    @Override
+    public void onSetApiResult(boolean success, String message, String resultBean) {
+
+    }
+}

+ 15 - 0
app/src/main/java/com/itant/shibei/ui/home/tool/json/IJsonView.java

@@ -0,0 +1,15 @@
+package com.itant.shibei.ui.home.tool.json;
+
+import com.miekir.mvp.view.IView;
+
+/**
+ *
+ *
+ * @author Miekir
+ * @date 2020/7/8 19:44
+ * Description: Template的View
+ */
+public interface IJsonView extends IView {
+    void onSaveJsonResult(boolean success, String message, JsonBean jsonBean);
+    void onGetJsonResult(boolean success, String message, JsonBean jsonBean);
+}

+ 106 - 0
app/src/main/java/com/itant/shibei/ui/home/tool/json/JsonActivity.java

@@ -0,0 +1,106 @@
+package com.itant.shibei.ui.home.tool.json;
+
+
+import android.os.Bundle;
+import android.view.View;
+import android.widget.EditText;
+
+import androidx.annotation.Nullable;
+
+import com.itant.shibei.BuildConfig;
+import com.itant.shibei.R;
+import com.itant.shibei.base.BaseBeiActivity;
+import com.itant.shibei.bean.BeiUser;
+import com.itant.shibei.manager.UserInfoManager;
+import com.itant.shibei.tool.StringTool;
+import com.itant.shibei.tool.SystemTool;
+import com.miekir.common.utils.ToastTool;
+import com.miekir.common.view.AlignTextView;
+import com.miekir.mvp.presenter.InjectPresenter;
+
+public class JsonActivity extends BaseBeiActivity implements View.OnClickListener, IJsonView {
+    private static final String FORMAT_URL = "%sshibei/api/getJson?s=%s";
+
+    @InjectPresenter
+    JsonPresenter jsonPresenter;
+
+    private BeiUser mUser;
+
+    private AlignTextView tv_json_url;
+    private EditText et_json;
+
+    private JsonBean mJsonBean;
+
+    @Override
+    public int getLayoutID() {
+        return R.layout.activity_json;
+    }
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        showLoading();
+        // 需要在super.onCreate后执行,否则会空指针
+        jsonPresenter.getJsonBean();
+    }
+
+    @Override
+    public void initViews(Bundle savedInstanceState) {
+        mUser = UserInfoManager.getInstance().getBeiUser();
+        setTitle("GetJson微服务");
+
+        tv_json_url = findViewById(R.id.tv_json_url);
+        tv_json_url.setText(String.format(FORMAT_URL, BuildConfig.BASE_URL, StringTool.getMixToken(mUser.token)));
+        et_json = findViewById(R.id.et_json);
+        findViewById(R.id.fl_json_url).setOnClickListener(this);
+        findViewById(R.id.btn_save_json).setOnClickListener(this);
+    }
+
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.fl_json_url:
+                // 复制GET链接URL
+                if (SystemTool.copyText(getApplicationContext(), tv_json_url.getText().toString())) {
+                    ToastTool.showShort("复制成功");
+                } else {
+                    ToastTool.showShort("复制失败");
+                }
+                break;
+
+            case R.id.btn_save_json:
+                // 保存JSON
+                showLoading();
+                if (mJsonBean == null) {
+                    JsonBean jsonBean = new JsonBean();
+                    jsonBean.json = et_json.getText().toString();
+                    jsonBean.email = mUser.email;
+                    jsonPresenter.saveJsonBean(jsonBean);
+                } else {
+                    mJsonBean.json = et_json.getText().toString();
+                    jsonPresenter.saveJsonBean(mJsonBean);
+                }
+                break;
+
+            default:
+                break;
+        }
+    }
+
+    @Override
+    public void onSaveJsonResult(boolean success, String message, JsonBean jsonBean) {
+        dismissLoading();
+        ToastTool.showShort(message);
+        mJsonBean = jsonBean;
+    }
+
+    @Override
+    public void onGetJsonResult(boolean success, String message, JsonBean jsonBean) {
+        dismissLoading();
+        if (jsonBean != null) {
+            mJsonBean = jsonBean;
+            et_json.setText(jsonBean.json);
+        }
+    }
+}

+ 14 - 0
app/src/main/java/com/itant/shibei/ui/home/tool/json/JsonBean.java

@@ -0,0 +1,14 @@
+package com.itant.shibei.ui.home.tool.json;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/8/13 20:20
+ * Description: json
+ */
+public class JsonBean {
+    public long id;
+    public String email;
+    public String json;
+}

+ 67 - 0
app/src/main/java/com/itant/shibei/ui/home/tool/json/JsonPresenter.java

@@ -0,0 +1,67 @@
+package com.itant.shibei.ui.home.tool.json;
+
+import android.text.TextUtils;
+
+import com.itant.shibei.base.ApiService;
+import com.itant.shibei.net.RetrofitHelper;
+import com.miekir.mvp.presenter.BasePresenter;
+import com.miekir.network.core.base.BaseObserver;
+
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/8/15 12:41
+ * Description:
+ */
+public class JsonPresenter extends BasePresenter<IJsonView> {
+
+    public void getJsonBean() {
+        RetrofitHelper.getInstance()
+                .getRequestApi(ApiService.class)
+                .getJsonBean()
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new BaseObserver<JsonBean>() {
+                    @Override
+                    public void onSuccess(JsonBean result) {
+                        if (getView() != null) {
+                            getView().onGetJsonResult(true, "", result);
+                        }
+                    }
+
+                    @Override
+                    public void onFailure(Throwable e, String errMsg) {
+                        if (getView() != null) {
+                            getView().onGetJsonResult(false, TextUtils.isEmpty(errMsg) ? "获取失败:"+e.getMessage() : errMsg, null);
+                        }
+                    }
+                });
+    }
+
+    public void saveJsonBean(JsonBean jsonBean) {
+        RetrofitHelper.getInstance()
+                .getRequestApi(ApiService.class)
+                .saveJson(jsonBean)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new BaseObserver<JsonBean>() {
+                    @Override
+                    public void onSuccess(JsonBean result) {
+                        if (getView() != null) {
+                            getView().onSaveJsonResult(true, "保存成功", result);
+                        }
+                    }
+
+                    @Override
+                    public void onFailure(Throwable e, String errMsg) {
+                        if (getView() != null) {
+                            getView().onSaveJsonResult(false, TextUtils.isEmpty(errMsg) ? "获取失败:"+e.getMessage() : errMsg, null);
+                        }
+                    }
+                });
+    }
+}

+ 69 - 0
app/src/main/java/com/itant/shibei/ui/home/tool/weather/WeatherActivity.java

@@ -0,0 +1,69 @@
+package com.itant.shibei.ui.home.tool.weather;
+
+
+import android.os.Bundle;
+import android.view.View;
+import android.widget.EditText;
+
+import com.itant.shibei.BuildConfig;
+import com.itant.shibei.R;
+import com.itant.shibei.base.BaseBeiActivity;
+import com.itant.shibei.bean.BeiUser;
+import com.itant.shibei.manager.UserInfoManager;
+import com.itant.shibei.tool.StringTool;
+import com.itant.shibei.tool.SystemTool;
+import com.miekir.common.utils.ToastTool;
+import com.miekir.common.view.AlignTextView;
+
+/**
+ * 天气界面
+ */
+public class WeatherActivity extends BaseBeiActivity implements View.OnClickListener {
+    private static final String FORMAT_URL = "%sshibei/api/getWeather?s=%s&city=深圳";
+
+    private BeiUser mUser;
+
+    private AlignTextView tv_weather_url;
+    @Override
+    public int getLayoutID() {
+        return R.layout.activity_weather;
+    }
+
+    @Override
+    public void initViews(Bundle savedInstanceState) {
+        mUser = UserInfoManager.getInstance().getBeiUser();
+        setTitle("日期天气API");
+
+        tv_weather_url = findViewById(R.id.tv_weather_url);
+        tv_weather_url.setText(String.format(FORMAT_URL, BuildConfig.BASE_URL, StringTool.getMixToken(mUser.token)));
+
+        findViewById(R.id.fl_weather_url).setOnClickListener(this);
+
+        EditText et_weather = findViewById(R.id.et_weather);
+        et_weather.setText("{\n" +
+                "  \"code\": 0,\n" +
+                "  \"msg\": \"\",\n" +
+                "  \"temperatureRange\": \"28.5 ~ 31 ℃\",\n" +
+                "  \"temperatureNow\": \"29.2\",\n" +
+                "  \"wind\": \"无持续风,微风\",\n" +
+                "  \"air\": \"优\",\n" +
+                "  \"desc\": \"阵雨转多云\"\n" +
+                "}");
+    }
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.fl_weather_url:
+                // 复制GET链接URL
+                if (SystemTool.copyText(getApplicationContext(), tv_weather_url.getText().toString())) {
+                    ToastTool.showShort("复制成功");
+                } else {
+                    ToastTool.showShort("复制失败");
+                }
+                break;
+            default:
+                break;
+        }
+    }
+}

+ 18 - 0
app/src/main/java/com/itant/shibei/ui/home/tool/weather/WeatherBean.java

@@ -0,0 +1,18 @@
+package com.itant.shibei.ui.home.tool.weather;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/8/14 20:44
+ * Description: 天气实体
+ */
+public class WeatherBean {
+    public int code;
+    public String msg;
+    public String temperatureRange;
+    public String temperatureNow;
+    public String wind;
+    public String air;
+    public String desc;
+}

+ 71 - 0
app/src/main/java/com/itant/shibei/ui/home/tool/yiji/YijiActivity.java

@@ -0,0 +1,71 @@
+package com.itant.shibei.ui.home.tool.yiji;
+
+
+import android.os.Bundle;
+import android.view.View;
+import android.widget.EditText;
+
+import com.itant.shibei.BuildConfig;
+import com.itant.shibei.R;
+import com.itant.shibei.base.BaseBeiActivity;
+import com.itant.shibei.bean.BeiUser;
+import com.itant.shibei.manager.UserInfoManager;
+import com.itant.shibei.tool.StringTool;
+import com.itant.shibei.tool.SystemTool;
+import com.miekir.common.utils.ToastTool;
+import com.miekir.common.view.AlignTextView;
+
+/**
+ * 黄历界面
+ */
+public class YijiActivity extends BaseBeiActivity implements View.OnClickListener {
+    private static final String FORMAT_URL = "%sshibei/api/getYiji?s=%s";
+
+    private BeiUser mUser;
+
+    private AlignTextView tv_yiji_url;
+
+    @Override
+    public int getLayoutID() {
+        return R.layout.activity_yiji;
+    }
+
+    @Override
+    public void initViews(Bundle savedInstanceState) {
+        mUser = UserInfoManager.getInstance().getBeiUser();
+        setTitle("宜忌API");
+
+        tv_yiji_url = findViewById(R.id.tv_yiji_url);
+        tv_yiji_url.setText(String.format(FORMAT_URL, BuildConfig.BASE_URL, StringTool.getMixToken(mUser.token)));
+
+        findViewById(R.id.fl_yiji_url).setOnClickListener(this);
+
+        EditText et_yiji = findViewById(R.id.et_yiji);
+        et_yiji.setText("{\n" +
+                "  \"code\": 0,\n" +
+                "  \"msg\": \"\",\n" +
+                "  \"newDate\": \"2020年8月14日 星期五\",\n" +
+                "  \"oldDate\": \"农历二零二零年 六月(小)廿五\",\n" +
+                "  \"hsDate\": \"庚子鼠年 甲申月 己丑日\",\n" +
+                "  \"yi\": \"结婚、领证、动土、安床\",\n" +
+                "  \"ji\": \"搬家、装修、开业\"\n" +
+                "}");
+    }
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.fl_yiji_url:
+                // 复制GET链接URL
+                if (SystemTool.copyText(getApplicationContext(), tv_yiji_url.getText().toString())) {
+                    ToastTool.showShort("复制成功");
+                } else {
+                    ToastTool.showShort("复制失败");
+                }
+                break;
+
+            default:
+                break;
+        }
+    }
+}

+ 18 - 0
app/src/main/java/com/itant/shibei/ui/home/tool/yiji/YijiBean.java

@@ -0,0 +1,18 @@
+package com.itant.shibei.ui.home.tool.yiji;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/8/14 22:16
+ * Description: 宜忌实体
+ */
+public class YijiBean {
+    public int code;
+    public String msg;
+    public String newDate;
+    public String oldDate;
+    public String hsDate;
+    public String yi;
+    public String ji;
+}

+ 166 - 0
app/src/main/java/com/itant/shibei/ui/mine/MineActivity.java

@@ -0,0 +1,166 @@
+package com.itant.shibei.ui.mine;
+
+
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.CompoundButton;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+
+import com.itant.shibei.R;
+import com.itant.shibei.base.BaseBeiActivity;
+import com.itant.shibei.bean.BeiUser;
+import com.itant.shibei.bean.SystemBean;
+import com.itant.shibei.constant.ConstantString;
+import com.itant.shibei.manager.UserInfoManager;
+import com.itant.shibei.tool.StringTool;
+import com.itant.shibei.tool.TimeTool;
+import com.itant.shibei.ui.home.tool.ISystemView;
+import com.itant.shibei.ui.home.tool.SystemPresenter;
+import com.itant.shibei.ui.mine.coupon.AddCouponActivity;
+import com.itant.shibei.ui.mine.goods.AddGoodsActivity;
+import com.miekir.common.utils.ToastTool;
+import com.miekir.common.utils.ViewTool;
+import com.miekir.mvp.presenter.InjectPresenter;
+
+public class MineActivity extends BaseBeiActivity implements View.OnClickListener, ISystemView, CompoundButton.OnCheckedChangeListener {
+
+    @InjectPresenter
+    SystemPresenter mSystemPresenter;
+
+    // 当前金额
+    private TextView tv_amount_rest;
+    // 提现支付宝
+    private TextView tv_cash_account;
+    private Switch switch_api;
+
+    private BeiUser mUser;
+
+    @Override
+    public int getLayoutID() {
+        return R.layout.activity_mine;
+    }
+
+    @Override
+    public void initViews(Bundle savedInstanceState) {
+        mUser = UserInfoManager.getInstance().getBeiUser();
+        setTitle(String.format(ConstantString.WELCOME_HELLO, TimeTool.getCurrentTimePeriod(), mUser.nickName));
+        ViewTool.setOnClickListener(this, this,
+                new int[]{R.id.ll_user, R.id.tv_add_goods, R.id.btn_exit_login, R.id.tv_add_coupon,
+                R.id.tv_add_goods_from_url, R.id.tv_deal_cash});
+
+        // 只有我才能管理后台
+        View ll_admin = findViewById(R.id.ll_admin);
+        if (TextUtils.equals("[email protected]", mUser.email)) {
+            ll_admin.setVisibility(View.VISIBLE);
+        } else {
+            ll_admin.setVisibility(View.GONE);
+        }
+
+        switch_api = findViewById(R.id.switch_api);
+        switch_api.setOnCheckedChangeListener(this);
+
+        tv_amount_rest = findViewById(R.id.tv_amount_rest);
+        tv_cash_account = findViewById(R.id.tv_cash_account);
+        tv_amount_rest.setText(String.format(ConstantString.MONEY_RMB, StringTool.longCent2Yuan(mUser.currentMoney)));
+        tv_cash_account.setText("提现支付宝:" + mUser.cashAccount);
+    }
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // 这个界面只有我才需要获取API设置
+        if (TextUtils.equals("[email protected]", mUser.email)) {
+            mSystemPresenter.getSystemConfig();
+        }
+    }
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+
+            case R.id.ll_user:
+                // todo 查看账户明细
+                break;
+
+            case R.id.tv_deal_cash:
+                // todo 处理提现工单
+                break;
+
+            case R.id.tv_add_goods_from_url:
+                // todo 解析链接添加商品
+                break;
+
+            case R.id.tv_add_goods:
+                // 上架新商品
+                startActivity(new Intent(this, AddGoodsActivity.class));
+                break;
+
+            case R.id.tv_add_coupon:
+                // 上架优惠券
+                startActivity(new Intent(this, AddCouponActivity.class));
+                break;
+
+            case R.id.btn_exit_login:
+                sureToExit();
+                break;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * 确认退出登录
+     */
+    private void sureToExit() {
+        AlertDialog alertDialog = new AlertDialog.Builder(this)
+               .setMessage("确定退出当前账号?")
+               .setNegativeButton("取消", (dialog, which) -> dialog.dismiss())
+               .setPositiveButton("确定", (DialogInterface dialog, int which) -> {
+            dialog.dismiss();
+            UserInfoManager.getInstance().setBeiUser(null);
+            finish();
+        }).create();
+        alertDialog.show();
+    }
+
+
+    @Override
+    public void onGetConfigResult(boolean success, String message, SystemBean resultBean) {
+        if (!success || resultBean == null) {
+            return;
+        }
+
+        switch_api.setOnCheckedChangeListener(null);
+        switch_api.setChecked(resultBean.isVipLimit);
+        switch_api.setOnCheckedChangeListener(this);
+    }
+
+    @Override
+    public void onSetApiResult(boolean success, String message, String resultBean) {
+        dismissLoading();
+        if (success) {
+            ToastTool.showShort("设置成功");
+        } else {
+            ToastTool.showShort("设置失败");
+            switch_api.setOnCheckedChangeListener(null);
+            switch_api.setChecked(!switch_api.isChecked());
+            switch_api.setOnCheckedChangeListener(this);
+        }
+    }
+
+    @Override
+    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+        if (buttonView.getId() == switch_api.getId()) {
+            showLoading();
+            mSystemPresenter.setApiConfig(isChecked);
+        }
+    }
+}

+ 45 - 0
app/src/main/java/com/itant/shibei/ui/mine/MineFragment.java

@@ -0,0 +1,45 @@
+package com.itant.shibei.ui.mine;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+
+import com.itant.shibei.R;
+import com.itant.shibei.manager.UserInfoManager;
+import com.itant.shibei.ui.mine.login.LoginActivity;
+
+public class MineFragment extends Fragment implements View.OnClickListener {
+
+
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater,
+                             ViewGroup container, Bundle savedInstanceState) {
+        View root = inflater.inflate(R.layout.activity_mine, container, false);
+        root.findViewById(R.id.ll_user).setOnClickListener(this);
+        //root.findViewById(R.id.ll_feedback).setOnClickListener(this);
+        return root;
+
+    }
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.ll_user:
+                if (!UserInfoManager.getInstance().isLogin()) {
+                    // 未登录,跳转登录
+                    startActivity(new Intent(getActivity(), LoginActivity.class));
+                } else {
+                    // 退出登录对话框
+                }
+                break;
+
+            default:
+                break;
+        }
+    }
+}

+ 104 - 0
app/src/main/java/com/itant/shibei/ui/mine/coupon/AddCouponActivity.java

@@ -0,0 +1,104 @@
+package com.itant.shibei.ui.mine.coupon;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.CheckBox;
+
+import com.google.android.material.textfield.TextInputEditText;
+import com.itant.shibei.R;
+import com.itant.shibei.base.BaseBeiActivity;
+import com.itant.shibei.ui.home.coupon.CouponBean;
+import com.miekir.common.utils.ToastTool;
+import com.miekir.common.utils.ViewTool;
+import com.miekir.mvp.presenter.InjectPresenter;
+
+/**
+ * @author Miekir
+ * @date 2020/6/18 16:48
+ * Description: 添加优惠券界面
+ */
+public class AddCouponActivity extends BaseBeiActivity implements View.OnClickListener, IAddCouponView {
+    public static final String KEY_MODIFY_COUPON = "key_modify_coupon";
+
+    private TextInputEditText et_coupon_title;
+    private TextInputEditText et_cover_url;
+    private TextInputEditText et_jump_url;
+
+    private CheckBox cb_enable;
+
+    private CouponBean couponBean;
+
+    @InjectPresenter
+    AddCouponPresenter presenter;
+
+    @Override
+    public int getLayoutID() {
+        return R.layout.activity_coupon_add;
+    }
+
+    @Override
+    public void initViews(Bundle savedInstanceState) {
+
+        et_coupon_title = findViewById(R.id.et_coupon_title);
+        et_cover_url = findViewById(R.id.et_cover_url);
+        et_jump_url = findViewById(R.id.et_jump_url);
+        cb_enable = findViewById(R.id.cb_enable);
+        ViewTool.setOnClickListener(this, this, new int[]{R.id.btn_add_goods});
+        Button btn_add_goods = findViewById(R.id.btn_add_goods);
+
+        couponBean = (CouponBean) getIntent().getSerializableExtra(KEY_MODIFY_COUPON);
+        if (couponBean != null) {
+            initCoupon();
+            setTitle("更新优惠券");
+            btn_add_goods.setText("立即更新");
+        } else {
+            setTitle("上架新的优惠券");
+        }
+    }
+
+    private void initCoupon() {
+        et_coupon_title.setText(couponBean.couponName);
+        et_cover_url.setText(couponBean.coverUrl);
+        et_jump_url.setText(couponBean.jumpUrl);
+        cb_enable.setChecked(couponBean.actionEnable);
+    }
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.btn_add_goods:
+                String title = et_coupon_title.getEditableText().toString();
+                String coverUrl = et_cover_url.getEditableText().toString();
+                String jumpUrl = et_jump_url.getEditableText().toString();
+                boolean isEnable = cb_enable.isChecked();
+
+                if (couponBean == null) {
+                    couponBean = new CouponBean();
+                }
+                couponBean.couponName = title;
+                couponBean.coverUrl = coverUrl;
+                couponBean.jumpUrl = jumpUrl;
+                couponBean.actionEnable = isEnable;
+
+                showLoading();
+                presenter.addCoupon(couponBean);
+                break;
+            default:
+                break;
+        }
+    }
+
+    @Override
+    public void onAddCouponResult(boolean success, String message) {
+        dismissLoading();
+        ToastTool.showShort(message);
+        if (success) {
+            Intent intent = getIntent();
+            intent.putExtra(KEY_MODIFY_COUPON, couponBean);
+            setResult(RESULT_OK, intent);
+            finish();
+        }
+    }
+}

+ 43 - 0
app/src/main/java/com/itant/shibei/ui/mine/coupon/AddCouponPresenter.java

@@ -0,0 +1,43 @@
+package com.itant.shibei.ui.mine.coupon;
+
+import android.text.TextUtils;
+
+import com.itant.shibei.base.ApiService;
+import com.itant.shibei.net.RetrofitHelper;
+import com.itant.shibei.ui.home.coupon.CouponBean;
+import com.miekir.mvp.presenter.BasePresenter;
+import com.miekir.network.core.base.BaseObserver;
+
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ * @author Miekir
+ * @date 2020/7/9 20:54
+ * Description: 商品的相关数据接口处理
+ */
+public class AddCouponPresenter extends BasePresenter<IAddCouponView> {
+
+    public void addCoupon(CouponBean couponBean) {
+        RetrofitHelper.getInstance()
+                .getRequestApi(ApiService.class)
+                .addCoupon(couponBean)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new BaseObserver<String>() {
+                    @Override
+                    public void onSuccess(String result) {
+                        if (getView() != null) {
+                            getView().onAddCouponResult(true, result);
+                        }
+                    }
+
+                    @Override
+                    public void onFailure(Throwable e, String errMsg) {
+                        if (getView() != null) {
+                            getView().onAddCouponResult(false, TextUtils.isEmpty(errMsg) ? "操作失败"+e.getMessage() : errMsg);
+                        }
+                    }
+                });
+    }
+}

+ 18 - 0
app/src/main/java/com/itant/shibei/ui/mine/coupon/IAddCouponView.java

@@ -0,0 +1,18 @@
+package com.itant.shibei.ui.mine.coupon;
+
+import com.miekir.mvp.view.IView;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/8/2 10:29
+ */
+public interface IAddCouponView extends IView {
+    /**
+     * 增加优惠券的结果
+     * @param success
+     * @param message
+     */
+    void onAddCouponResult(boolean success, String message);
+}

+ 130 - 0
app/src/main/java/com/itant/shibei/ui/mine/forget/ForgetActivity.java

@@ -0,0 +1,130 @@
+package com.itant.shibei.ui.mine.forget;
+
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.View;
+
+import com.google.android.material.textfield.TextInputEditText;
+import com.itant.shibei.R;
+import com.itant.shibei.base.BaseBeiActivity;
+import com.itant.shibei.bean.BeiUser;
+import com.itant.shibei.manager.UserInfoManager;
+import com.itant.shibei.tool.StringTool;
+import com.itant.shibei.ui.mine.register.CodePresenter;
+import com.itant.shibei.ui.mine.register.ICodeView;
+import com.miekir.common.utils.ToastTool;
+import com.miekir.common.utils.ViewTool;
+import com.miekir.mvp.presenter.InjectPresenter;
+
+/**
+ * @author Miekir
+ * @date 2020/6/18 16:48
+ * Description: 登录界面
+ */
+public class ForgetActivity extends BaseBeiActivity implements View.OnClickListener, ICodeView, IForgetView {
+    private TextInputEditText et_email;
+    private TextInputEditText et_code;
+    private TextInputEditText et_new_password;
+
+    private String email;
+    private String code;
+    private String password;
+
+    @InjectPresenter
+    private CodePresenter mCodePresenter;
+
+    @InjectPresenter
+    private ForgetPresenter mForgetPresenter;
+
+    @Override
+    public int getLayoutID() {
+        return R.layout.activity_forget;
+    }
+
+    @Override
+    public void initViews(Bundle savedInstanceState) {
+        setTitle("重置密码");
+
+        et_email = findViewById(R.id.et_email);
+        et_code = findViewById(R.id.et_code);
+        et_new_password = findViewById(R.id.et_new_password);
+        ViewTool.setOnClickListener(this, this,
+                new int[]{R.id.btn_get_code, R.id.btn_reset_password});
+    }
+
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.btn_get_code:
+                // 获取验证码
+                email = et_email.getEditableText().toString();
+                if (TextUtils.isEmpty(email)) {
+                    ToastTool.showShort("邮箱不能为空");
+                    return;
+                }
+
+                showLoading();
+                mCodePresenter.getCode(email);
+                break;
+            case R.id.btn_reset_password:
+                email = et_email.getEditableText().toString();
+                if (TextUtils.isEmpty(email)) {
+                    ToastTool.showShort("邮箱不能为空");
+                    return;
+                }
+
+                if (!email.contains("@")) {
+                    ToastTool.showShort("请输入合法的邮箱");
+                    return;
+                }
+
+                // 重设密码
+                code = et_code.getEditableText().toString();
+                if (TextUtils.isEmpty(code)) {
+                    ToastTool.showShort("验证码不能为空");
+                    return;
+                }
+
+                password = et_new_password.getEditableText().toString();
+                if (TextUtils.isEmpty(password)) {
+                    ToastTool.showShort("新密码不能为空");
+                    return;
+                }
+
+                String encodePassword = StringTool.getEncodeString(password);
+                if (TextUtils.isEmpty(encodePassword)) {
+                    ToastTool.showShort("该手机不支持加密算法");
+                    return;
+                }
+                showLoading();
+                mForgetPresenter.submitReset(email, code, encodePassword);
+                break;
+            default:
+                break;
+        }
+    }
+
+    @Override
+    public void onGetCode(boolean isSuccess, String message) {
+        dismissLoading();
+        if (isSuccess) {
+            ToastTool.showShort("验证码发送成功");
+        } else {
+            ToastTool.showShort(message);
+        }
+    }
+
+    @Override
+    public void onForgetResult(BeiUser user, String message) {
+        dismissLoading();
+        if (user != null) {
+            UserInfoManager.getInstance().setBeiUser(user);
+            ToastTool.showShort("重设密码成功");
+            setResult(RESULT_OK);
+            finish();
+        } else {
+            ToastTool.showShort(message);
+        }
+    }
+}

+ 50 - 0
app/src/main/java/com/itant/shibei/ui/mine/forget/ForgetPresenter.java

@@ -0,0 +1,50 @@
+package com.itant.shibei.ui.mine.forget;
+
+import android.text.TextUtils;
+
+import com.itant.shibei.base.ApiService;
+import com.itant.shibei.bean.BeiUser;
+import com.itant.shibei.net.RetrofitHelper;
+import com.miekir.mvp.presenter.BasePresenter;
+import com.miekir.network.core.base.BaseObserver;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ * @author Miekir
+ * @date 2020/7/9 20:54
+ * Description: 商品的相关数据接口处理
+ */
+public class ForgetPresenter extends BasePresenter<IForgetView> {
+
+    public void submitReset(String email, String code, String password) {
+        Map<String, Object> map = new HashMap<>();
+        map.put("email", email);
+        map.put("code", code);
+        map.put("password", password);
+        RetrofitHelper.getInstance()
+                .getRequestApi(ApiService.class)
+                .resetPassword(map)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new BaseObserver<BeiUser>() {
+                    @Override
+                    public void onSuccess(BeiUser result) {
+                        if (getView() != null) {
+                            getView().onForgetResult(result, null);
+                        }
+                    }
+
+                    @Override
+                    public void onFailure(Throwable e, String errMsg) {
+                        if (getView() != null) {
+                            getView().onForgetResult(null, TextUtils.isEmpty(errMsg) ? "密码重设失败" : errMsg);
+                        }
+                    }
+                });
+    }
+}

+ 16 - 0
app/src/main/java/com/itant/shibei/ui/mine/forget/IForgetView.java

@@ -0,0 +1,16 @@
+package com.itant.shibei.ui.mine.forget;
+
+import com.itant.shibei.bean.BeiUser;
+import com.miekir.mvp.view.IView;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/8/2 10:29
+ * Description: 忘记密码的回调
+ */
+public interface IForgetView extends IView {
+
+    void onForgetResult(BeiUser user, String message);
+}

+ 193 - 0
app/src/main/java/com/itant/shibei/ui/mine/goods/AddGoodsActivity.java

@@ -0,0 +1,193 @@
+package com.itant.shibei.ui.mine.goods;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Button;
+import android.widget.CheckBox;
+
+import androidx.annotation.NonNull;
+
+import com.google.android.material.textfield.TextInputEditText;
+import com.itant.shibei.R;
+import com.itant.shibei.base.BaseBeiActivity;
+import com.itant.shibei.constant.ConstantUrl;
+import com.itant.shibei.ui.home.goods.GoodsBean;
+import com.miekir.common.utils.ActivityTool;
+import com.miekir.common.utils.ToastTool;
+import com.miekir.common.utils.ViewTool;
+import com.miekir.mvp.presenter.InjectPresenter;
+
+/**
+ * @author Miekir
+ * @date 2020/6/18 16:48
+ * Description: 添加京东商品界面
+ */
+public class AddGoodsActivity extends BaseBeiActivity implements View.OnClickListener, IAddGoodsView {
+    public static final String KEY_MODIFY_GOODS = "key_modify_goods";
+
+    private TextInputEditText et_goods_title;
+    private TextInputEditText et_cover_url;
+    private TextInputEditText et_video_url;
+    private TextInputEditText et_desc;
+    private TextInputEditText et_reason;
+    private TextInputEditText et_old_price;
+    private TextInputEditText et_rebate_all;
+    private TextInputEditText et_province;
+    private TextInputEditText et_coupon;
+    private TextInputEditText et_goods_url;
+    private TextInputEditText et_sales_per_month;
+    private TextInputEditText et_good_comment_percent;
+    private TextInputEditText et_shop_name;
+    private TextInputEditText et_comment_num;
+    private CheckBox cb_self;
+    private CheckBox cb_enable;
+
+    private GoodsBean mGoodsBean;
+
+    @InjectPresenter
+    AddGoodsPresenter presenter;
+
+    @Override
+    public int getLayoutID() {
+        return R.layout.activity_goods_add;
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.menu_done, menu);
+        MenuItem item = menu.findItem(R.id.action_done);
+        item.setTitle("  返利链接  ");
+        return super.onCreateOptionsMenu(menu);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.action_done:
+                // 注册
+                ActivityTool.openUrl(this, ConstantUrl.URL_JD_UNION);
+                break;
+            default:
+                break;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    @Override
+    public void initViews(Bundle savedInstanceState) {
+        et_goods_title = findViewById(R.id.et_goods_title);
+        et_cover_url = findViewById(R.id.et_cover_url);
+        et_video_url = findViewById(R.id.et_video_url);
+        et_desc = findViewById(R.id.et_desc);
+        et_reason = findViewById(R.id.et_reason);
+        et_old_price = findViewById(R.id.et_old_price);
+        et_rebate_all = findViewById(R.id.et_rebate_all);
+        et_province = findViewById(R.id.et_province);
+        et_coupon = findViewById(R.id.et_coupon);
+        et_goods_url = findViewById(R.id.et_goods_url);
+        et_sales_per_month = findViewById(R.id.et_sales_per_month);
+        et_good_comment_percent = findViewById(R.id.et_good_comment_percent);
+        et_shop_name = findViewById(R.id.et_shop_name);
+        et_comment_num = findViewById(R.id.et_comment_num);
+        cb_self = findViewById(R.id.cb_self);
+        cb_enable = findViewById(R.id.cb_enable);
+        ViewTool.setOnClickListener(this, this, new int[]{R.id.btn_add_goods});
+        Button btn_add_goods = findViewById(R.id.btn_add_goods);
+
+        mGoodsBean = (GoodsBean) getIntent().getSerializableExtra(KEY_MODIFY_GOODS);
+        if (mGoodsBean != null) {
+            initGoods();
+            setTitle("更新商品");
+            btn_add_goods.setText("立即更新");
+        } else {
+            setTitle("上架新的商品");
+        }
+    }
+
+    private void initGoods() {
+        et_goods_title.setText(mGoodsBean.title);
+        et_cover_url.setText(mGoodsBean.coverImageUrl);
+        et_video_url.setText(mGoodsBean.videoUrl);
+        et_desc.setText(mGoodsBean.description);
+        et_reason.setText(mGoodsBean.reason);
+        et_old_price.setText(String.valueOf(mGoodsBean.oldPrice));
+        et_rebate_all.setText(String.valueOf(mGoodsBean.rebate));
+        et_province.setText(mGoodsBean.province);
+        et_coupon.setText(mGoodsBean.couponInfo);
+        et_goods_url.setText(mGoodsBean.goodsUrl);
+        et_sales_per_month.setText(String.valueOf(mGoodsBean.salesPerMonth));
+        et_good_comment_percent.setText(String.valueOf(mGoodsBean.goodCommentPercent));
+        et_shop_name.setText(mGoodsBean.shopName);
+        et_comment_num.setText(String.valueOf(mGoodsBean.commentNum));
+        cb_self.setChecked(mGoodsBean.isSelfBusiness);
+        cb_enable.setChecked(mGoodsBean.enable);
+    }
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.btn_add_goods:
+                String title = et_goods_title.getEditableText().toString();
+                String coverUrl = et_cover_url.getEditableText().toString();
+                String videoUrl = et_video_url.getEditableText().toString();
+                String description = et_desc.getEditableText().toString();
+                String reason = et_reason.getEditableText().toString();
+                long oldPrice = Long.parseLong(et_old_price.getEditableText().toString());
+                long rebate = Long.parseLong(et_rebate_all.getEditableText().toString());
+                long nowPrice = oldPrice - rebate/2;
+                String province = et_province.getEditableText().toString();
+                String shopName = et_shop_name.getEditableText().toString();
+                String coupon = et_coupon.getEditableText().toString();
+                String goodsUrl = et_goods_url.getEditableText().toString();
+                String salesPerMonth = et_sales_per_month.getEditableText().toString();
+                String goodCommentPercent = et_good_comment_percent.getEditableText().toString();
+                String commentNum = et_comment_num.getEditableText().toString();
+                boolean isSelf = cb_self.isChecked();
+                boolean isEnable = cb_enable.isChecked();
+
+                if (mGoodsBean == null) {
+                    mGoodsBean = new GoodsBean();
+                }
+                mGoodsBean.title = title;
+                mGoodsBean.coverImageUrl = coverUrl;
+                mGoodsBean.videoUrl = videoUrl;
+                mGoodsBean.description = description;
+                mGoodsBean.reason = reason;
+                mGoodsBean.oldPrice = oldPrice;
+                mGoodsBean.nowPrice = nowPrice;
+                mGoodsBean.rebate = rebate;
+                mGoodsBean.province = province;
+                mGoodsBean.shopName = shopName;
+                mGoodsBean.couponInfo = coupon;
+                mGoodsBean.goodsUrl = goodsUrl;
+                mGoodsBean.salesPerMonth = Long.parseLong(salesPerMonth);
+                mGoodsBean.goodCommentPercent = Double.parseDouble(goodCommentPercent);
+                mGoodsBean.commentNum = Long.parseLong(commentNum);
+                mGoodsBean.isSelfBusiness = isSelf;
+                mGoodsBean.enable = isEnable;
+                mGoodsBean.hasCoupon = !TextUtils.isEmpty(coupon);
+
+                showLoading();
+                presenter.addGoods(mGoodsBean);
+                break;
+            default:
+                break;
+        }
+    }
+
+    @Override
+    public void onAddGoodsResult(boolean success, String message) {
+        dismissLoading();
+        ToastTool.showShort(message);
+        if (success) {
+            Intent intent = getIntent();
+            intent.putExtra(KEY_MODIFY_GOODS, mGoodsBean);
+            setResult(RESULT_OK, intent);
+            finish();
+        }
+    }
+}

+ 43 - 0
app/src/main/java/com/itant/shibei/ui/mine/goods/AddGoodsPresenter.java

@@ -0,0 +1,43 @@
+package com.itant.shibei.ui.mine.goods;
+
+import android.text.TextUtils;
+
+import com.itant.shibei.base.ApiService;
+import com.itant.shibei.net.RetrofitHelper;
+import com.itant.shibei.ui.home.goods.GoodsBean;
+import com.miekir.mvp.presenter.BasePresenter;
+import com.miekir.network.core.base.BaseObserver;
+
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ * @author Miekir
+ * @date 2020/7/9 20:54
+ * Description: 商品的相关数据接口处理
+ */
+public class AddGoodsPresenter extends BasePresenter<IAddGoodsView> {
+
+    public void addGoods(GoodsBean goodsBean) {
+        RetrofitHelper.getInstance()
+                .getRequestApi(ApiService.class)
+                .addGoods(goodsBean)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new BaseObserver<String>() {
+                    @Override
+                    public void onSuccess(String result) {
+                        if (getView() != null) {
+                            getView().onAddGoodsResult(true, result);
+                        }
+                    }
+
+                    @Override
+                    public void onFailure(Throwable e, String errMsg) {
+                        if (getView() != null) {
+                            getView().onAddGoodsResult(false, TextUtils.isEmpty(errMsg) ? "操作失败"+e.getMessage() : errMsg);
+                        }
+                    }
+                });
+    }
+}

+ 15 - 0
app/src/main/java/com/itant/shibei/ui/mine/goods/IAddGoodsView.java

@@ -0,0 +1,15 @@
+package com.itant.shibei.ui.mine.goods;
+
+import com.miekir.mvp.view.IView;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/8/2 10:29
+ * Description: 获取验证码的回调
+ */
+public interface IAddGoodsView extends IView {
+
+    void onAddGoodsResult(boolean success, String message);
+}

+ 16 - 0
app/src/main/java/com/itant/shibei/ui/mine/login/ILoginView.java

@@ -0,0 +1,16 @@
+package com.itant.shibei.ui.mine.login;
+
+import com.itant.shibei.bean.BeiUser;
+import com.miekir.mvp.view.IView;
+
+/**
+ * Copyright (C), 2019-2020, Miekir
+ *
+ * @author Miekir
+ * @date 2020/8/2 10:29
+ * Description: 获取验证码的回调
+ */
+public interface ILoginView extends IView {
+
+    void onLoginResult(BeiUser user, String message);
+}

+ 134 - 0
app/src/main/java/com/itant/shibei/ui/mine/login/LoginActivity.java

@@ -0,0 +1,134 @@
+package com.itant.shibei.ui.mine.login;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+
+import com.google.android.material.textfield.TextInputEditText;
+import com.itant.shibei.R;
+import com.itant.shibei.base.BaseBeiActivity;
+import com.itant.shibei.bean.BeiUser;
+import com.itant.shibei.manager.UserInfoManager;
+import com.itant.shibei.tool.StringTool;
+import com.itant.shibei.ui.mine.forget.ForgetActivity;
+import com.itant.shibei.ui.mine.register.RegisterActivity;
+import com.miekir.common.utils.ToastTool;
+import com.miekir.common.utils.ViewTool;
+import com.miekir.mvp.presenter.InjectPresenter;
+
+import rx_activity_result2.RxActivityResult;
+
+/**
+ * @author Miekir
+ * @date 2020/6/18 16:48
+ * Description: 登录界面
+ */
+public class LoginActivity extends BaseBeiActivity implements View.OnClickListener, ILoginView {
+    private TextInputEditText et_email;
+    private TextInputEditText et_password;
+
+    @InjectPresenter
+    LoginPresenter presenter;
+
+    @Override
+    public int getLayoutID() {
+        return R.layout.activity_login;
+    }
+
+    @Override
+    public void initViews(Bundle savedInstanceState) {
+        setTitle("使用电子邮箱登录");
+        et_email = findViewById(R.id.et_email);
+        et_password = findViewById(R.id.et_password);
+        ViewTool.setOnClickListener(this, this, new int[]{R.id.btn_login, R.id.tv_forget});
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        getMenuInflater().inflate(R.menu.menu_done, menu);
+        MenuItem item = menu.findItem(R.id.action_done);
+        item.setTitle("  注册账号  ");
+        return super.onCreateOptionsMenu(menu);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.action_done:
+                // 注册
+                Intent registerIntent = new Intent(this, RegisterActivity.class);
+                RxActivityResult.on(this).startIntent(registerIntent)
+                        .filter(result -> result.resultCode() == RESULT_OK)
+                        .doOnNext(result -> {
+                            // 注册成功之后关闭登录界面
+                            ToastTool.showShort("注册成功");
+                            //startActivity(new Intent(LoginActivity.this, MineActivity.class));
+                            finish();
+                        })
+                        .subscribe();
+                break;
+            default:
+                break;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    @Override
+    public void onClick(View v) {
+        switch (v.getId()) {
+            case R.id.tv_forget:
+                // 忘记密码
+                Intent forgetIntent = new Intent(this, ForgetActivity.class);
+                RxActivityResult.on(this).startIntent(forgetIntent)
+                        .filter(result -> result.resultCode() == RESULT_OK)
+                        .doOnNext(result -> {
+                            // 找回密码成功之后关闭登录界面
+                            //startActivity(new Intent(LoginActivity.this, MineActivity.class));
+                            finish();
+                        })
+                        .subscribe();
+                break;
+
+            case R.id.btn_login:
+                String email = et_email.getEditableText().toString();
+                String password = et_password.getEditableText().toString();
+                if (TextUtils.isEmpty(email)) {
+                    ToastTool.showShort("邮箱不能为空");
+                    return;
+                }
+                if (TextUtils.isEmpty(password)) {
+                    ToastTool.showShort("密码不能为空");
+                    return;
+                }
+
+                password = StringTool.getEncodeString(password);
+                if (TextUtils.isEmpty(password)) {
+                    ToastTool.showShort("该手机不支持加密算法");
+                    return;
+                }
+                showLoading();
+                presenter.submitLogin(email, password);
+                break;
+            default:
+                break;
+        }
+    }
+
+    @Override
+    public void onLoginResult(BeiUser user, String message) {
+        dismissLoading();
+        if (user != null) {
+            UserInfoManager.getInstance().setBeiUser(user);
+            ToastTool.showShort("登录成功");
+            //startActivity(new Intent(this, MineActivity.class));
+            finish();
+        } else {
+            ToastTool.showShort(message);
+        }
+    }
+}

+ 43 - 0
app/src/main/java/com/itant/shibei/ui/mine/login/LoginPresenter.java

@@ -0,0 +1,43 @@
+package com.itant.shibei.ui.mine.login;
+
+import android.text.TextUtils;
+
+import com.itant.shibei.base.ApiService;
+import com.itant.shibei.bean.BeiUser;
+import com.itant.shibei.net.RetrofitHelper;
+import com.miekir.mvp.presenter.BasePresenter;
+import com.miekir.network.core.base.BaseObserver;
+
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.schedulers.Schedulers;
+
+/**
+ * @author Miekir
+ * @date 2020/7/9 20:54
+ * Description: 商品的相关数据接口处理
+ */
+public class LoginPresenter extends BasePresenter<ILoginView> {
+
+    public void submitLogin(String email, String password) {
+        RetrofitHelper.getInstance()
+                .getRequestApi(ApiService.class)
+                .submitLogin(email, password)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new BaseObserver<BeiUser>() {
+                    @Override
+                    public void onSuccess(BeiUser result) {
+                        if (getView() != null) {
+                            getView().onLoginResult(result, null);
+                        }
+                    }
+
+                    @Override
+                    public void onFailure(Throwable e, String errMsg) {
+                        if (getView() != null) {
+                            getView().onLoginResult(null, TextUtils.isEmpty(errMsg) ? "登录失败" : errMsg);
+                        }
+                    }
+                });
+    }
+}

+ 0 - 0
app/src/main/java/com/itant/shibei/ui/mine/register/CodePresenter.java


Неке датотеке нису приказане због велике количине промена