Commit 456ba80d8333a5f9b76c2a55dcec5881ba29c919

Authored by 陶汉栋
1 parent 1496174c
Exists in master

no message

Showing 166 changed files with 15196 additions and 19 deletions   Show diff stats
.idea/gradle.xml
@@ -9,6 +9,7 @@ @@ -9,6 +9,7 @@
9 <set> 9 <set>
10 <option value="$PROJECT_DIR$" /> 10 <option value="$PROJECT_DIR$" />
11 <option value="$PROJECT_DIR$/app" /> 11 <option value="$PROJECT_DIR$/app" />
  12 + <option value="$PROJECT_DIR$/mvpsdk" />
12 </set> 13 </set>
13 </option> 14 </option>
14 <option name="resolveModulePerSourceSet" value="false" /> 15 <option name="resolveModulePerSourceSet" value="false" />
.idea/misc.xml
1 <?xml version="1.0" encoding="UTF-8"?> 1 <?xml version="1.0" encoding="UTF-8"?>
2 <project version="4"> 2 <project version="4">
  3 + <component name="NullableNotNullManager">
  4 + <option name="myDefaultNullable" value="android.support.annotation.Nullable" />
  5 + <option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
  6 + <option name="myNullables">
  7 + <value>
  8 + <list size="4">
  9 + <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
  10 + <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
  11 + <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
  12 + <item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
  13 + </list>
  14 + </value>
  15 + </option>
  16 + <option name="myNotNulls">
  17 + <value>
  18 + <list size="4">
  19 + <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
  20 + <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
  21 + <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
  22 + <item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
  23 + </list>
  24 + </value>
  25 + </option>
  26 + </component>
3 <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK"> 27 <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
4 <output url="file://$PROJECT_DIR$/build/classes" /> 28 <output url="file://$PROJECT_DIR$/build/classes" />
5 </component> 29 </component>
.idea/modules.xml
@@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
4 <modules> 4 <modules>
5 <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" /> 5 <module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
6 <module fileurl="file://$PROJECT_DIR$/expressscanner.iml" filepath="$PROJECT_DIR$/expressscanner.iml" /> 6 <module fileurl="file://$PROJECT_DIR$/expressscanner.iml" filepath="$PROJECT_DIR$/expressscanner.iml" />
  7 + <module fileurl="file://$PROJECT_DIR$/mvpsdk/mvpsdk.iml" filepath="$PROJECT_DIR$/mvpsdk/mvpsdk.iml" />
7 </modules> 8 </modules>
8 </component> 9 </component>
9 </project> 10 </project>
10 \ No newline at end of file 11 \ No newline at end of file
app/build.gradle
@@ -19,10 +19,13 @@ android { @@ -19,10 +19,13 @@ android {
19 } 19 }
20 20
21 dependencies { 21 dependencies {
22 - implementation fileTree(dir: 'libs', include: ['*.jar']) 22 + implementation fileTree(include: ['*.jar'], dir: 'libs')
23 implementation 'com.android.support:appcompat-v7:26.1.0' 23 implementation 'com.android.support:appcompat-v7:26.1.0'
24 implementation 'com.android.support.constraint:constraint-layout:1.1.0' 24 implementation 'com.android.support.constraint:constraint-layout:1.1.0'
  25 + implementation 'com.android.support:support-v4:26.1.0'
25 testImplementation 'junit:junit:4.12' 26 testImplementation 'junit:junit:4.12'
26 androidTestImplementation 'com.android.support.test:runner:1.0.1' 27 androidTestImplementation 'com.android.support.test:runner:1.0.1'
27 androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' 28 androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
  29 + implementation project(':mvpsdk')
  30 + implementation files('libs/zkcsdk.jar')
28 } 31 }
app/libs/zkcsdk.jar 0 → 100644
No preview for this file type
app/src/main/AndroidManifest.xml
1 <?xml version="1.0" encoding="utf-8"?> 1 <?xml version="1.0" encoding="utf-8"?>
2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3 - package="com.shunzhi.expressscanner" > 3 + package="com.shunzhi.expressscanner">
  4 +
  5 + <uses-permission android:name="android.permission.INTERNET" />
4 6
5 <application 7 <application
  8 + android:name=".AppContext"
6 android:allowBackup="true" 9 android:allowBackup="true"
7 android:icon="@mipmap/ic_launcher" 10 android:icon="@mipmap/ic_launcher"
8 android:label="@string/app_name" 11 android:label="@string/app_name"
9 android:roundIcon="@mipmap/ic_launcher_round" 12 android:roundIcon="@mipmap/ic_launcher_round"
10 android:supportsRtl="true" 13 android:supportsRtl="true"
11 - android:theme="@style/AppTheme" >  
12 - <activity android:name=".MainActivity" > 14 + android:theme="@style/AppTheme">
  15 + <activity
  16 + android:name=".MainActivity"
  17 + android:theme="@style/Theme.AppCompat.Light.NoActionBar">
13 <intent-filter> 18 <intent-filter>
14 <action android:name="android.intent.action.MAIN" /> 19 <action android:name="android.intent.action.MAIN" />
15 20
16 <category android:name="android.intent.category.LAUNCHER" /> 21 <category android:name="android.intent.category.LAUNCHER" />
17 </intent-filter> 22 </intent-filter>
18 </activity> 23 </activity>
  24 + <activity
  25 + android:name=".base.BaseActivity"
  26 + android:label="@string/title_activity_base"
  27 + android:theme="@style/AppTheme.NoActionBar"></activity>
19 </application> 28 </application>
20 29
21 </manifest> 30 </manifest>
22 \ No newline at end of file 31 \ No newline at end of file
app/src/main/java/com/shunzhi/expressscanner/AppConfig.java 0 → 100644
@@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
  1 +package com.shunzhi.expressscanner;
  2 +
  3 +import android.content.Context;
  4 +import android.content.SharedPreferences;
  5 +import android.preference.PreferenceManager;
  6 +import android.text.TextUtils;
  7 +
  8 +/**
  9 + * Created by ToaHanDong on 2018/4/24.
  10 + */
  11 +
  12 +public class AppConfig {
  13 +
  14 +// public static String BASE_URL="http://ecampus.zjyzzx.net/";
  15 +
  16 + public static String BASE_URL="http://60.190.202.57:1000/";
  17 +
  18 + public static String LOGIN_NAME="15305755683";
  19 + public static String LOGIN_PWD="755683";
  20 +
  21 + public static String ACCESS_TOKEN = "access_token";
  22 + public static final String OPEN_SCAN = "open_scan";
  23 + public static String CURRENT_USERID = "current_userid";
  24 + public static String SCHOOL_ID="school_id";
  25 +
  26 + private static AppConfig appConfig = null;
  27 + public static AppConfig getAppConfig() {
  28 + if (appConfig == null) {
  29 + appConfig = new AppConfig();
  30 + }
  31 + return appConfig;
  32 + }
  33 +
  34 + //得到保存的值
  35 + public String get(String key) {
  36 + return getSharedPreferences(AppContext.getContext()).getString(key, null);
  37 + }
  38 +
  39 + private SharedPreferences getSharedPreferences(Context context) {
  40 + return PreferenceManager.getDefaultSharedPreferences(context);
  41 + }
  42 +
  43 + //保存键值对
  44 + public void set(String key, String value) {
  45 + SharedPreferences.Editor editor = getSharedPreferences(AppContext.getContext()).edit();
  46 + if (TextUtils.isEmpty(value)) {
  47 + editor.putString(key, value);
  48 + } else {
  49 + editor.putString(key, value.trim());
  50 + }
  51 + editor.commit();
  52 + }
  53 +
  54 + public boolean getBoolean(String openScan) {
  55 + return true;
  56 + }
  57 +}
app/src/main/java/com/shunzhi/expressscanner/AppContext.java 0 → 100644
@@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
  1 +package com.shunzhi.expressscanner;
  2 +
  3 +import com.share.mvpsdk.global.GlobalApplication;
  4 +import com.share.mvpsdk.helper.RetrofitCreateHelper;
  5 +
  6 +/**
  7 + * Created by ToaHanDong on 2018/4/24.
  8 + */
  9 +
  10 +public class AppContext extends GlobalApplication {
  11 +
  12 + @Override
  13 + public void onCreate() {
  14 + super.onCreate();
  15 +
  16 + RetrofitCreateHelper.getInstance().setAuthorization(AppConfig.getAppConfig().get(AppConfig.ACCESS_TOKEN));
  17 +
  18 + }
  19 +}
app/src/main/java/com/shunzhi/expressscanner/MainActivity.java
1 package com.shunzhi.expressscanner; 1 package com.shunzhi.expressscanner;
2 2
  3 +import android.annotation.SuppressLint;
  4 +import android.content.Context;
  5 +import android.media.MediaPlayer;
  6 +import android.os.Message;
  7 +import android.os.RemoteException;
  8 +import android.os.Vibrator;
  9 +import android.support.v4.app.FragmentTransaction;
3 import android.support.v7.app.AppCompatActivity; 10 import android.support.v7.app.AppCompatActivity;
4 import android.os.Bundle; 11 import android.os.Bundle;
  12 +import android.widget.FrameLayout;
  13 +import android.widget.Toast;
5 14
6 -public class MainActivity extends AppCompatActivity { 15 +import com.share.mvpsdk.base.activity.BaseCompatActivity;
  16 +import com.shunzhi.expressscanner.base.BaseActivity;
  17 +import com.shunzhi.expressscanner.fragment.MainFragment;
  18 +import com.smartdevice.aidl.ICallBack;
  19 +import com.smartdevice.aidl.IZKCService;
  20 +import com.zkc.baseLibrary.MessageType;
  21 +
  22 +public class MainActivity extends BaseCompatActivity {
  23 +
  24 + FrameLayout frame;
  25 +
  26 + FragmentTransaction fragmentTransaction = null;
  27 +
  28 + MainFragment mainFragment;
  29 +
  30 + @Override
  31 + protected void initView(Bundle savedInstanceState) {
  32 +
  33 + frame = findViewById(R.id.frame);
  34 + fragmentTransaction = getSupportFragmentManager().beginTransaction();
  35 + mainFragment = new MainFragment();
  36 + fragmentTransaction.add(R.id.frame, mainFragment)
  37 + .show(mainFragment).commit();
  38 +
  39 + }
7 40
8 @Override 41 @Override
9 - protected void onCreate(Bundle savedInstanceState) {  
10 - super.onCreate(savedInstanceState);  
11 - setContentView(R.layout.activity_main); 42 + protected int getLayoutId() {
  43 + return R.layout.activity_main;
12 } 44 }
13 } 45 }
app/src/main/java/com/shunzhi/expressscanner/api/MainApi.java 0 → 100644
@@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
  1 +package com.shunzhi.expressscanner.api;
  2 +
  3 +import com.google.gson.JsonObject;
  4 +
  5 +import io.reactivex.Observable;
  6 +import retrofit2.http.Field;
  7 +import retrofit2.http.FormUrlEncoded;
  8 +import retrofit2.http.GET;
  9 +import retrofit2.http.POST;
  10 +import retrofit2.http.Query;
  11 +
  12 +/**
  13 + * Created by ToaHanDong on 2018/4/24.
  14 + */
  15 +
  16 +public interface MainApi {
  17 +
  18 + @FormUrlEncoded
  19 + @POST("Token")
  20 + Observable<JsonObject> login(@Field("grant_type") String grant_type, @Field("username") String username
  21 + , @Field("password") String password);
  22 +
  23 + @GET("api/NewAssets/IsExpressReceive")
  24 + Observable<JsonObject> getExpressInfo(@Query("ExpressNumber") String expressCode,@Query("schoolid") String schoolId);
  25 +
  26 + @POST("api/Account/CurrentInfo")
  27 + Observable<JsonObject> getCurrentInfo();
  28 +
  29 + @GET("api/NewAssets/SearchExpressPhone")
  30 + Observable<JsonObject> SearchExpressPhone(@Query("moilb") String moilb);
  31 +
  32 + @GET("api/NewAssets/SearchNameByPhone")
  33 + Observable<JsonObject> SearchNameByPhone(@Query("moilb") String moilb);
  34 +
  35 + @GET("api/NewAssets/InsertExpress")
  36 + Observable<JsonObject> InsertExpress(@Query("ExpressNumber") String ExpressNumber,@Query("MoilePhone") String MoilePhone,
  37 + @Query("UserName") String UserName,@Query("schoolId") String schoolId);
  38 +
  39 + @GET("api/NewAssets/UpdateIsReceive")
  40 + Observable<JsonObject> UpdateIsReceive(@Query("ExpressNumber") String ExpressNumber,@Query("schoolId") String schoolId);
  41 +
  42 +}
app/src/main/java/com/shunzhi/expressscanner/base/BaseActivity.java 0 → 100644
@@ -0,0 +1,77 @@ @@ -0,0 +1,77 @@
  1 +package com.shunzhi.expressscanner.base;
  2 +
  3 +import android.content.Context;
  4 +import android.os.Bundle;
  5 +import android.os.Handler;
  6 +import android.os.Message;
  7 +import android.support.design.widget.FloatingActionButton;
  8 +import android.support.design.widget.Snackbar;
  9 +import android.support.v7.app.AppCompatActivity;
  10 +import android.support.v7.widget.Toolbar;
  11 +import android.view.View;
  12 +import android.view.inputmethod.InputMethodManager;
  13 +
  14 +import com.share.mvpsdk.base.activity.BaseCompatActivity;
  15 +import com.shunzhi.expressscanner.R;
  16 +import com.shunzhi.expressscanner.common.MessageCenter;
  17 +import com.smartdevice.aidl.IZKCService;
  18 +import com.zkc.baseLibrary.ZkcManager;
  19 +
  20 +public abstract class BaseActivity extends BaseCompatActivity {
  21 + public static int DEVICE_MODEL = 0;
  22 + public Handler mhanlder;
  23 + public IZKCService mIzkcService = null;
  24 +
  25 + @Override
  26 + protected void onCreate(Bundle savedInstanceState) {
  27 + super.onCreate(savedInstanceState);
  28 + setContentView(getLayoutId());
  29 + MessageCenter.getInstance().addHandler(getHandler());
  30 + initView(savedInstanceState);
  31 + InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
  32 + imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
  33 + //创建接口管理者对象 create the object of interface manager
  34 + ZkcManager.getInstance().onCreate(this, mhanlder);
  35 +// Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
  36 +// setSupportActionBar(toolbar);
  37 +//
  38 +// FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
  39 +// fab.setOnClickListener(new View.OnClickListener() {
  40 +// @Override
  41 +// public void onClick(View view) {
  42 +// Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
  43 +// .setAction("Action", null).show();
  44 +// }
  45 +// });
  46 + }
  47 +
  48 + protected void handleStateMessage(Message message) {
  49 + }
  50 +
  51 + /**
  52 + * handler
  53 + */
  54 + protected Handler getHandler() {
  55 + if (mhanlder == null) {
  56 + mhanlder = new Handler() {
  57 + public void handleMessage(Message msg) {
  58 + handleStateMessage(msg);
  59 + }
  60 + };
  61 + }
  62 + return mhanlder;
  63 + }
  64 +
  65 + protected void sendMessage(int what, Object obj) {
  66 + Message message = new Message();
  67 + message.what = what;
  68 + message.obj = obj;
  69 + getHandler().sendMessage(message);
  70 + }
  71 +
  72 + protected abstract void initView(Bundle savedInstanceState);
  73 +
  74 + protected abstract int getLayoutId();
  75 +
  76 +
  77 +}
app/src/main/java/com/shunzhi/expressscanner/bean/ExpressBean.java 0 → 100644
@@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
  1 +package com.shunzhi.expressscanner.bean;
  2 +
  3 +/**
  4 + * Created by ToaHanDong on 2018/4/24.
  5 + */
  6 +
  7 +public class ExpressBean {
  8 +
  9 + public String expressCode;
  10 +
  11 + public String teacherName;
  12 +
  13 + public String teacherNum;
  14 +
  15 + public int state;//0:未领取 1:已领取 2:未录入
  16 +
  17 + @Override
  18 + public String toString() {
  19 + return "ExpressBean{" +
  20 + "expressCode='" + expressCode + '\'' +
  21 + ", teacherName='" + teacherName + '\'' +
  22 + ", teacherNum='" + teacherNum + '\'' +
  23 + ", state=" + state +
  24 + '}';
  25 + }
  26 +}
app/src/main/java/com/shunzhi/expressscanner/common/MessageCenter.java 0 → 100644
@@ -0,0 +1,60 @@ @@ -0,0 +1,60 @@
  1 +package com.shunzhi.expressscanner.common;
  2 +
  3 +import android.os.Handler;
  4 +import android.os.Message;
  5 +
  6 +import java.util.List;
  7 +import java.util.Vector;
  8 +
  9 +public class MessageCenter {
  10 +
  11 + private List<Handler> mHandlerList = new Vector<Handler>();
  12 + private static MessageCenter CENTER = null;
  13 +
  14 + private MessageCenter() {
  15 +
  16 + }
  17 +
  18 + public static MessageCenter getInstance() {
  19 + if (CENTER == null) {
  20 + CENTER = new MessageCenter();
  21 + }
  22 + return CENTER;
  23 + }
  24 +
  25 + public synchronized void addHandler(Handler handler) {
  26 + mHandlerList.add(handler);
  27 + }
  28 +
  29 + public synchronized void removeHandler(Handler handler) {
  30 + mHandlerList.remove(handler);
  31 + }
  32 +
  33 + public synchronized void sendMessage(int what, Object obj) {
  34 + Message message = new Message();
  35 + message.obj = obj;
  36 + message.what = what;
  37 + sendMessage(message);
  38 + }
  39 +
  40 + public synchronized void sendMessageWithPre(int what, Object obj, int arg1) {
  41 + Message message = new Message();
  42 + message.obj = obj;
  43 + message.arg1 = arg1;
  44 + message.what = what;
  45 + sendMessage(message);
  46 + }
  47 +
  48 + public synchronized void sendMessage(Message message) {
  49 + for (Handler handler : mHandlerList) {
  50 + handler.sendMessage(Message.obtain(message));
  51 + }
  52 + }
  53 +
  54 + public synchronized void sendEmptyMessage(int what) {
  55 + for (Handler handler : mHandlerList) {
  56 + handler.sendEmptyMessage(what);
  57 + }
  58 + }
  59 +
  60 +}
app/src/main/java/com/shunzhi/expressscanner/contract/MainContract.java 0 → 100644
@@ -0,0 +1,70 @@ @@ -0,0 +1,70 @@
  1 +package com.shunzhi.expressscanner.contract;
  2 +
  3 +import com.google.gson.JsonObject;
  4 +import com.share.mvpsdk.base.BasePresenter;
  5 +import com.share.mvpsdk.base.IBaseFragment;
  6 +import com.share.mvpsdk.base.IBaseModel;
  7 +import com.share.mvpsdk.base.IBaseView;
  8 +import com.shunzhi.expressscanner.bean.ExpressBean;
  9 +
  10 +import java.util.List;
  11 +
  12 +import io.reactivex.Observable;
  13 +
  14 +/**
  15 + * Created by ToaHanDong on 2018/4/24.
  16 + */
  17 +
  18 +public interface MainContract {
  19 +
  20 + abstract class MainPresenter extends BasePresenter<IMainModel,IMainView>{
  21 +
  22 + public abstract void login(String loginName,String loginPwd);
  23 +
  24 + public abstract void getExpressInfo(String expressCode);
  25 +
  26 + public abstract void getTeacherName(String tel);
  27 +
  28 + public abstract void upExpressInfo(ExpressBean expressBean);
  29 +
  30 + public abstract void SearchExpressPhone(String mobile);
  31 +
  32 + public abstract void UpdateIsReceive(String ExpressNumber,String schoolId);
  33 +
  34 + }
  35 +
  36 +
  37 + interface IMainModel extends IBaseModel{
  38 +
  39 + Observable<JsonObject> getTeacherName(String tel);
  40 +
  41 + Observable<JsonObject> getExpressInfo(String expressCode,String schoolId);
  42 +
  43 + Observable<JsonObject> login(String logName,String logPwd);
  44 +
  45 + Observable<JsonObject> upExpressInfo(ExpressBean expressBean);
  46 +
  47 + Observable<JsonObject> getCurrentInfo();
  48 +
  49 + Observable<JsonObject> SearchExpressPhone(String mobile);
  50 +
  51 + Observable<JsonObject> UpdateIsReceive(String ExpressNumber,String schoolId);
  52 +
  53 + }
  54 +
  55 + interface IMainView extends IBaseFragment{
  56 +
  57 +
  58 + void showTeacherName(String name);
  59 +
  60 + void showExpressInfo(ExpressBean expressBean);
  61 +
  62 + void showExpressInfoSuccess(boolean isSuccess);
  63 +
  64 + void showSearchModel(List<String> stringList);
  65 +
  66 + void showUpdateIsReceive(boolean isUpdate);
  67 + }
  68 +
  69 +
  70 +}
app/src/main/java/com/shunzhi/expressscanner/fragment/MainFragment.java 0 → 100644
@@ -0,0 +1,463 @@ @@ -0,0 +1,463 @@
  1 +package com.shunzhi.expressscanner.fragment;
  2 +
  3 +import android.annotation.SuppressLint;
  4 +import android.content.Context;
  5 +import android.graphics.drawable.BitmapDrawable;
  6 +import android.media.MediaPlayer;
  7 +import android.os.Bundle;
  8 +import android.os.Handler;
  9 +import android.os.Message;
  10 +import android.os.RemoteException;
  11 +import android.os.Vibrator;
  12 +import android.support.annotation.NonNull;
  13 +import android.support.annotation.Nullable;
  14 +import android.support.v7.widget.LinearLayoutManager;
  15 +import android.support.v7.widget.RecyclerView;
  16 +import android.text.Editable;
  17 +import android.text.TextWatcher;
  18 +import android.view.LayoutInflater;
  19 +import android.view.View;
  20 +import android.view.ViewGroup;
  21 +import android.view.WindowManager;
  22 +import android.widget.Button;
  23 +import android.widget.EditText;
  24 +import android.widget.LinearLayout;
  25 +import android.widget.PopupWindow;
  26 +import android.widget.TextView;
  27 +
  28 +import com.share.mvpsdk.base.BasePresenter;
  29 +import com.share.mvpsdk.base.adapter.BaseRecyclerViewAdapter;
  30 +import com.share.mvpsdk.base.adapter.BaseRecyclerViewHolder;
  31 +import com.share.mvpsdk.base.adapter.OnItemClickListener;
  32 +import com.share.mvpsdk.base.fragment.BaseMVPCompatFragment;
  33 +import com.share.mvpsdk.utils.NetworkConnectionUtils;
  34 +import com.share.mvpsdk.utils.StringUtils;
  35 +import com.share.mvpsdk.utils.ToastUtils;
  36 +import com.shunzhi.expressscanner.AppConfig;
  37 +import com.shunzhi.expressscanner.R;
  38 +import com.shunzhi.expressscanner.bean.ExpressBean;
  39 +import com.shunzhi.expressscanner.contract.MainContract;
  40 +import com.shunzhi.expressscanner.present.MainPresenter;
  41 +import com.smartdevice.aidl.ICallBack;
  42 +import com.smartdevice.aidl.IZKCService;
  43 +import com.zkc.baseLibrary.MessageType;
  44 +import com.zkc.baseLibrary.ZkcManager;
  45 +
  46 +import java.util.List;
  47 +
  48 +/**
  49 + */
  50 +public class MainFragment extends BaseMVPCompatFragment<MainContract.MainPresenter, MainContract.IMainModel> implements MainContract.IMainView
  51 + , View.OnClickListener {
  52 +
  53 + public MainFragment newInstance() {
  54 + MainFragment mainFragment = new MainFragment();
  55 + return mainFragment;
  56 + }
  57 +
  58 + public final int INSERT_SUCCESS = 24;
  59 +
  60 + EditText etExpressCode, etTel, etName;
  61 +
  62 + Button tvCommint, tvCancle;
  63 +
  64 + TextView tvTips;
  65 +
  66 + public IZKCService mIzkcService = null;
  67 +
  68 + MediaPlayer player;
  69 +
  70 + Vibrator vibrator;
  71 +
  72 + public String text = "";
  73 +
  74 + MyPopu myPopu = null;
  75 +
  76 + LinearLayout layout_tel, layout_name, layout_express;
  77 +
  78 + @Override
  79 + public int getLayoutId() {
  80 + return R.layout.fragment_main;
  81 + }
  82 +
  83 + ICallBack.Stub mCallback = new ICallBack.Stub() {
  84 +
  85 + @SuppressLint("MissingPermission")
  86 + @Override
  87 + public void onReturnValue(byte[] buffer, int size)
  88 + throws RemoteException {
  89 + String codeStr = new String(buffer, 0, size);
  90 + text = codeStr;
  91 + player.start();
  92 +// vibrator.vibrate(100);
  93 + Message message = mhanlder.obtainMessage();
  94 + message.what = MessageType.BaiscMessage.SCAN_RESULT_GET_SUCCESS;
  95 + message.obj = text;
  96 + mhanlder.sendMessage(message);
  97 + }
  98 + };
  99 +
  100 + @Override
  101 + public void initUI(View view, @Nullable Bundle savedInstanceState) {
  102 + mPresenter.login(AppConfig.LOGIN_NAME, AppConfig.LOGIN_PWD);
  103 +
  104 + etExpressCode = view.findViewById(R.id.etExpressCode);
  105 + etTel = view.findViewById(R.id.etTel);
  106 + etName = view.findViewById(R.id.etName);
  107 + tvCommint = view.findViewById(R.id.tvCommint);
  108 + tvCancle = view.findViewById(R.id.tvCancle);
  109 + tvTips = view.findViewById(R.id.tvTips);
  110 + layout_tel = view.findViewById(R.id.layout_tel);
  111 + layout_name = view.findViewById(R.id.layout_name);
  112 + layout_express = view.findViewById(R.id.layout_express);
  113 +
  114 + tvCommint.setOnClickListener(this);
  115 + tvCancle.setOnClickListener(this);
  116 + player = MediaPlayer.create(getContext(), R.raw.scan);
  117 + vibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
  118 + initZkc();
  119 + if (!NetworkConnectionUtils.isConnected(getContext())){
  120 + ToastUtils.showToast("请连接网络");
  121 + tvTips.setText("网络已断开,请连接网络");
  122 + }
  123 + etTel.addTextChangedListener(new TextWatcher() {
  124 + @Override
  125 + public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
  126 +
  127 + }
  128 +
  129 + @Override
  130 + public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
  131 +
  132 + }
  133 +
  134 + @Override
  135 + public void afterTextChanged(Editable editable) {
  136 + if (editable.length() >= 3 && tvCommint.getText().toString().equals("确定录入"))
  137 + mPresenter.SearchExpressPhone(editable.toString());
  138 + }
  139 + });
  140 + }
  141 +
  142 + private void initZkc() {
  143 +
  144 + ZkcManager.getInstance().onCreate(getActivity(), mhanlder);
  145 +
  146 + }
  147 +
  148 + @NonNull
  149 + @Override
  150 + public BasePresenter initPresenter() {
  151 + return new MainPresenter();
  152 + }
  153 +
  154 + /**
  155 + * 扫描快递后,显示快递的状态
  156 + *
  157 + * @param expressBean
  158 + */
  159 + @Override
  160 + public void showExpressInfo(ExpressBean expressBean) {
  161 +
  162 + etExpressCode.setText(text);
  163 + switch (expressBean.state) {
  164 + case 0://未领取
  165 + noImport(expressBean);
  166 + break;
  167 + case 1://已领取
  168 + hasGetExpress(expressBean);
  169 + break;
  170 + case 2://未录入
  171 + insertExpress();
  172 + break;
  173 + }
  174 +
  175 + }
  176 +
  177 + /**
  178 + * 显示教师名字
  179 + *
  180 + * @param name
  181 + */
  182 + @Override
  183 + public void showTeacherName(String name) {
  184 + if (null != myPopu) myPopu.dismiss();
  185 + etName.setText(name);
  186 + tvCommint.setText("确定录入");
  187 + tvTips.setText("提示: 录入快递信息");
  188 + tvCancle.setVisibility(View.VISIBLE);
  189 + etExpressCode.setVisibility(View.VISIBLE);
  190 + etName.setFocusable(false);
  191 + etTel.setFocusable(false);
  192 + etExpressCode.setFocusable(false);
  193 + }
  194 +
  195 + //显示快递录入是否成功
  196 + @Override
  197 + public void showExpressInfoSuccess(boolean isSuccess) {
  198 + if (isSuccess) {
  199 + tvTips.setText("录入成功");
  200 + ToastUtils.showToast("录入成功");
  201 + mhanlder.sendEmptyMessageDelayed(INSERT_SUCCESS, 3000);
  202 + }
  203 + }
  204 +
  205 + /**
  206 + * 模糊查询的手机号
  207 + *
  208 + * @param stringList
  209 + */
  210 + @Override
  211 + public void showSearchModel(List<String> stringList) {
  212 + if (null == myPopu) myPopu = new MyPopu();
  213 + myPopu.showAsDropDown(etTel);
  214 + myPopu.showDatas(stringList);
  215 + //焦点还是要在手机号输入框
  216 + etTel.setFocusable(true);
  217 + }
  218 +
  219 + //显示快递是否领取成功
  220 + @Override
  221 + public void showUpdateIsReceive(boolean isUpdate) {
  222 + if (isUpdate) {
  223 + ToastUtils.showToast("领取成功");
  224 + mhanlder.sendEmptyMessageDelayed(INSERT_SUCCESS, 3000);
  225 + }
  226 + }
  227 +
  228 + @Override
  229 + public void onClick(View view) {
  230 + switch (view.getId()) {
  231 + case R.id.tvCommint:
  232 + String commintText = tvCommint.getText().toString();
  233 + //录入快递
  234 + if (commintText.equals("确定录入")) {
  235 +
  236 + if (!StringUtils.isPhoneNumberValid(etTel.getText().toString())) {
  237 + ToastUtils.showToast("请输入合法的手机号");
  238 + return;
  239 + }
  240 + ExpressBean expressBean = new ExpressBean();
  241 + expressBean.expressCode = etExpressCode.getText().toString();
  242 + expressBean.teacherNum = etTel.getText().toString();
  243 + expressBean.teacherName = etName.getText().toString();
  244 + mPresenter.upExpressInfo(expressBean);
  245 +
  246 + } else if (commintText.equals("确定并扫描快递")) {
  247 +
  248 + try {
  249 + mIzkcService.scan();
  250 + } catch (RemoteException e) {
  251 + e.printStackTrace();
  252 + }
  253 +
  254 + } else if (commintText.equals("领取")) {
  255 + mPresenter.UpdateIsReceive(etExpressCode.getText().toString(), AppConfig.getAppConfig().get(AppConfig.SCHOOL_ID));
  256 + } else if (commintText.equals("确定")) {
  257 + showExpress();
  258 + }
  259 + break;
  260 + case R.id.tvCancle:
  261 + showExpress();
  262 + break;
  263 + }
  264 + }
  265 +
  266 + //显示扫描界面
  267 + private void showExpress() {
  268 + layout_express.setVisibility(View.VISIBLE);
  269 + layout_name.setVisibility(View.INVISIBLE);
  270 + layout_tel.setVisibility(View.INVISIBLE);
  271 + tvCancle.setVisibility(View.GONE);
  272 + etExpressCode.setFocusable(true);
  273 + etName.setFocusable(true);
  274 + etTel.setFocusable(true);
  275 + etExpressCode.setFocusableInTouchMode(true);
  276 + etName.setFocusableInTouchMode(true);
  277 + etTel.setFocusableInTouchMode(true);
  278 + tvCommint.setText("确定并扫描快递");
  279 + etExpressCode.setText("");
  280 + etTel.setText("");
  281 + etName.setText("");
  282 + etExpressCode.setBackground(getResources().getDrawable(R.drawable.shape_edit));
  283 + tvTips.setText("点击扫描快递按钮扫描快递");
  284 + }
  285 +
  286 + /**
  287 + * 已录入
  288 + *
  289 + * @param expressBean
  290 + */
  291 + private void noImport(ExpressBean expressBean) {
  292 + showContents(expressBean);
  293 + tvCommint.setText("领取");
  294 + tvTips.setText("快递未领取,点击领取按钮可领取");
  295 + }
  296 +
  297 + /**
  298 + * 录入快递
  299 + */
  300 + private void insertExpress() {
  301 + layout_express.setVisibility(View.VISIBLE);
  302 + layout_name.setVisibility(View.VISIBLE);
  303 + layout_tel.setVisibility(View.VISIBLE);
  304 + tvCancle.setVisibility(View.VISIBLE);
  305 + etExpressCode.setBackground(getResources().getDrawable(R.drawable.shape_edit));
  306 + etName.setBackground(getResources().getDrawable(R.drawable.shape_edit));
  307 + etTel.setBackground(getResources().getDrawable(R.drawable.shape_edit));
  308 + tvCommint.setText("确定录入");
  309 + tvTips.setText("快递未录入请输入手机号");
  310 + }
  311 +
  312 + //已领取
  313 + private void hasGetExpress(ExpressBean expressBean) {
  314 + showContents(expressBean);
  315 + etExpressCode.setBackground(null);
  316 + etName.setBackground(null);
  317 + etTel.setBackground(null);
  318 + tvCommint.setText("确定");
  319 + tvTips.setText("快递已经被领取");
  320 + }
  321 +
  322 + //显示信息
  323 + private void showContents(ExpressBean expressBean) {
  324 + etExpressCode.setText(expressBean.expressCode);
  325 + etTel.setText(expressBean.teacherNum);
  326 + etName.setText(expressBean.teacherName);
  327 + layout_tel.setVisibility(View.VISIBLE);
  328 + layout_name.setVisibility(View.VISIBLE);
  329 + layout_express.setVisibility(View.VISIBLE);
  330 + etName.setFocusable(false);
  331 + etTel.setFocusable(false);
  332 + etExpressCode.setFocusable(false);
  333 + tvCancle.setVisibility(View.VISIBLE);
  334 + }
  335 +
  336 + Handler mhanlder = new Handler() {
  337 + @Override
  338 + public void handleMessage(Message message) {
  339 + super.handleMessage(message);
  340 + switch (message.what) {
  341 + //服务绑定成功 service bind success
  342 + case MessageType.BaiscMessage.SEVICE_BIND_SUCCESS:
  343 +// Toast.makeText(getContext(), getString(R.string.service_bind_success), Toast.LENGTH_SHORT).show();
  344 + mIzkcService = (IZKCService) message.obj;
  345 + registerCallbackAndInitScan();
  346 + break;
  347 + //服务绑定失败 service bind fail
  348 + case MessageType.BaiscMessage.SEVICE_BIND_FAIL:
  349 +// Toast.makeText(getContext(), getString(R.string.service_bind_fail), Toast.LENGTH_SHORT).show();
  350 + break;
  351 + case MessageType.BaiscMessage.SCAN_RESULT_GET_SUCCESS:
  352 + mPresenter.getExpressInfo(text);
  353 + break;
  354 + case INSERT_SUCCESS:
  355 + showExpress();
  356 + break;
  357 + }
  358 + }
  359 + };
  360 +
  361 + private void registerCallbackAndInitScan() {
  362 + try {
  363 + //设置扫描模块 set up scan module
  364 + mIzkcService.setModuleFlag(4);
  365 + //注册扫描数据回调接口
  366 + mIzkcService.registerCallBack("Scanner", mCallback);
  367 + //打开扫描 open scan
  368 + mIzkcService.openScan(true);
  369 +// btn_scan.setEnabled(true);
  370 + } catch (RemoteException e) {
  371 + e.printStackTrace();
  372 + }
  373 + }
  374 +
  375 + @Override
  376 + public void onDestroy() {
  377 + super.onDestroy();
  378 + try {
  379 + mIzkcService.unregisterCallBack("Scanner", mCallback);
  380 + } catch (RemoteException e) {
  381 + e.printStackTrace();
  382 + }
  383 + }
  384 +
  385 +
  386 + private class MyPopu extends PopupWindow {
  387 +
  388 + RecyclerView recyclerView;
  389 + MyAdapter myAdapter;
  390 +
  391 + public MyPopu() {
  392 +
  393 + View view = LayoutInflater.from(getContext()).inflate(R.layout.popu_mobile, null);
  394 + recyclerView = view.findViewById(R.id.recyclerView);
  395 +
  396 + setWidth(WindowManager.LayoutParams.MATCH_PARENT);
  397 + setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
  398 +
  399 + setFocusable(false);
  400 + setOutsideTouchable(true);
  401 + setBackgroundDrawable(new BitmapDrawable());
  402 +
  403 + setContentView(view);
  404 + update();
  405 + }
  406 +
  407 + public void showDatas(List<String> list) {
  408 + if (null == myAdapter) myAdapter = new MyAdapter();
  409 + if (null == recyclerView.getAdapter()) {
  410 + recyclerView.setAdapter(myAdapter);
  411 + myAdapter.setOnItemClickListener(new OnItemClickListener() {
  412 + @Override
  413 + public void onItemClickListener(Object object, int position) {
  414 + etTel.setText(object.toString());
  415 + mPresenter.getTeacherName(object.toString());
  416 + dismiss();
  417 + }
  418 + });
  419 + }
  420 + myAdapter.addAll(list);
  421 + }
  422 +
  423 + private class MyAdapter extends BaseRecyclerViewAdapter<String> {
  424 +
  425 + @Override
  426 + public void onAttachedToRecyclerView(RecyclerView recyclerView) {
  427 + super.onAttachedToRecyclerView(recyclerView);
  428 + LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
  429 + layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
  430 + recyclerView.setLayoutManager(layoutManager);
  431 + }
  432 +
  433 + @Override
  434 + public BaseRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
  435 + View view = LayoutInflater.from(getContext()).inflate(R.layout.item_mobile, parent, false);
  436 + return new MyViewholder(view);
  437 + }
  438 +
  439 + private class MyViewholder extends BaseRecyclerViewHolder<String> {
  440 +
  441 + TextView tvName;
  442 +
  443 + public MyViewholder(View itemView) {
  444 + super(itemView);
  445 + tvName = itemView.findViewById(R.id.tvName);
  446 + }
  447 +
  448 + @Override
  449 + public void onBindViewHolder(final String object, final int position) {
  450 + tvName.setText(object);
  451 + tvName.setOnClickListener(new View.OnClickListener() {
  452 + @Override
  453 + public void onClick(View view) {
  454 + onItemClickListener.onItemClickListener(object, position);
  455 + }
  456 + });
  457 + }
  458 + }
  459 + }
  460 +
  461 + }
  462 +
  463 +}
app/src/main/java/com/shunzhi/expressscanner/model/MainModel.java 0 → 100644
@@ -0,0 +1,70 @@ @@ -0,0 +1,70 @@
  1 +package com.shunzhi.expressscanner.model;
  2 +
  3 +import android.util.Log;
  4 +
  5 +import com.google.gson.JsonObject;
  6 +import com.share.mvpsdk.base.BaseModel;
  7 +import com.share.mvpsdk.helper.RetrofitCreateHelper;
  8 +import com.share.mvpsdk.helper.RxHelper;
  9 +import com.shunzhi.expressscanner.AppConfig;
  10 +import com.shunzhi.expressscanner.api.MainApi;
  11 +import com.shunzhi.expressscanner.bean.ExpressBean;
  12 +import com.shunzhi.expressscanner.contract.MainContract;
  13 +
  14 +import io.reactivex.Observable;
  15 +
  16 +/**
  17 + * Created by ToaHanDong on 2018/4/24.
  18 + */
  19 +
  20 +public class MainModel extends BaseModel implements MainContract.IMainModel {
  21 +
  22 +
  23 + public static MainModel newInstance(){
  24 + return new MainModel();
  25 + }
  26 +
  27 + @Override
  28 + public Observable<JsonObject> getTeacherName(String tel) {
  29 + return RetrofitCreateHelper.getInstance().createApi(MainApi.class,AppConfig.BASE_URL)
  30 + .SearchNameByPhone(tel).compose(RxHelper.<JsonObject>rxSchedulerHelper());
  31 + }
  32 +
  33 + @Override
  34 + public Observable<JsonObject> getExpressInfo(String expressCode,String schoolId) {
  35 + return RetrofitCreateHelper.getInstance().createApi(MainApi.class,AppConfig.BASE_URL)
  36 + .getExpressInfo(expressCode,schoolId).compose(RxHelper.<JsonObject>rxSchedulerHelper());
  37 + }
  38 +
  39 + @Override
  40 + public Observable<JsonObject> login(String logName, String logPwd) {
  41 + return RetrofitCreateHelper.getInstance().login(MainApi.class, AppConfig.BASE_URL)
  42 + .login("password",logName,logPwd).compose(RxHelper.<JsonObject>rxSchedulerHelper());
  43 + }
  44 +
  45 + @Override
  46 + public Observable<JsonObject> upExpressInfo(ExpressBean expressBean) {
  47 + String schoolId=AppConfig.getAppConfig().get(AppConfig.SCHOOL_ID);
  48 + return RetrofitCreateHelper.getInstance().createApi(MainApi.class,AppConfig.BASE_URL)
  49 + .InsertExpress(expressBean.expressCode,expressBean.teacherNum,expressBean.teacherName
  50 + ,schoolId).compose(RxHelper.<JsonObject>rxSchedulerHelper());
  51 + }
  52 +
  53 + @Override
  54 + public Observable<JsonObject> getCurrentInfo() {
  55 + return RetrofitCreateHelper.getInstance().createApi(MainApi.class,AppConfig.BASE_URL)
  56 + .getCurrentInfo().compose(RxHelper.<JsonObject>rxSchedulerHelper());
  57 + }
  58 +
  59 + @Override
  60 + public Observable<JsonObject> SearchExpressPhone(String mobile) {
  61 + return RetrofitCreateHelper.getInstance().createApi(MainApi.class,AppConfig.BASE_URL)
  62 + .SearchExpressPhone(mobile).compose(RxHelper.<JsonObject>rxSchedulerHelper());
  63 + }
  64 +
  65 + @Override
  66 + public Observable<JsonObject> UpdateIsReceive(String ExpressNumber, String schoolId) {
  67 + return RetrofitCreateHelper.getInstance().createApi(MainApi.class,AppConfig.BASE_URL)
  68 + .UpdateIsReceive(ExpressNumber,schoolId).compose(RxHelper.<JsonObject>rxSchedulerHelper());
  69 + }
  70 +}
app/src/main/java/com/shunzhi/expressscanner/present/MainPresenter.java 0 → 100644
@@ -0,0 +1,217 @@ @@ -0,0 +1,217 @@
  1 +package com.shunzhi.expressscanner.present;
  2 +
  3 +import android.util.Log;
  4 +
  5 +import com.google.gson.JsonArray;
  6 +import com.google.gson.JsonObject;
  7 +import com.share.mvpsdk.RxManager;
  8 +import com.share.mvpsdk.utils.OkHttpExceptionUtil;
  9 +import com.share.mvpsdk.utils.ToastUtils;
  10 +import com.shunzhi.expressscanner.AppConfig;
  11 +import com.shunzhi.expressscanner.bean.ExpressBean;
  12 +import com.shunzhi.expressscanner.contract.MainContract;
  13 +import com.shunzhi.expressscanner.model.MainModel;
  14 +
  15 +import org.json.JSONObject;
  16 +
  17 +import java.util.ArrayList;
  18 +import java.util.List;
  19 +
  20 +import io.reactivex.functions.Consumer;
  21 +import retrofit2.HttpException;
  22 +import timber.log.Timber;
  23 +
  24 +/**
  25 + * Created by ToaHanDong on 2018/4/24.
  26 + */
  27 +
  28 +public class MainPresenter extends MainContract.MainPresenter {
  29 + @Override
  30 + public MainContract.IMainModel getModel() {
  31 + return MainModel.newInstance();
  32 + }
  33 +
  34 + @Override
  35 + public void onStart() {
  36 +
  37 + }
  38 +
  39 + @Override
  40 + public void login(String loginName, String loginPwd) {
  41 +
  42 + mRxManager.register(mIModel.login(loginName, loginPwd).subscribe(new Consumer<JsonObject>() {
  43 + @Override
  44 + public void accept(JsonObject jsonObject) throws Exception {
  45 + String access_token = jsonObject.get("access_token").getAsString();
  46 + AppConfig.getAppConfig().set(AppConfig.ACCESS_TOKEN, access_token);
  47 + getCurrentInfo();
  48 + }
  49 + }, new Consumer<Throwable>() {
  50 + @Override
  51 + public void accept(Throwable throwable) throws Exception {
  52 + try {
  53 + OkHttpExceptionUtil.handOkHttpException((HttpException) throwable);
  54 + } catch (Exception e) {
  55 + e.printStackTrace();
  56 + }
  57 + }
  58 + }));
  59 +
  60 + }
  61 +
  62 + private void getCurrentInfo() {
  63 +
  64 + mRxManager.register(mIModel.getCurrentInfo().subscribe(new Consumer<JsonObject>() {
  65 + @Override
  66 + public void accept(JsonObject jsonObject) throws Exception {
  67 + if (jsonObject.get("status").getAsInt() == 1) {
  68 + JsonObject data = jsonObject.getAsJsonObject("data");
  69 + AppConfig.getAppConfig().set(AppConfig.CURRENT_USERID, data.get("id").getAsString());
  70 + JsonArray teachClass = data.getAsJsonArray("teachClass");
  71 + if (teachClass.size() > 0) {
  72 + JsonObject jsonObject1 = teachClass.get(0).getAsJsonObject();
  73 + AppConfig.getAppConfig().set(AppConfig.SCHOOL_ID, jsonObject1.get("schoolId").getAsString());
  74 + }
  75 + }
  76 + }
  77 + }, new Consumer<Throwable>() {
  78 + @Override
  79 + public void accept(Throwable throwable) throws Exception {
  80 + Log.d("55555", "getCurrentInfo=" + throwable.toString());
  81 + }
  82 + }));
  83 +
  84 + }
  85 +
  86 + @Override
  87 + public void getExpressInfo(String expressCode) {
  88 +
  89 + String scholId = AppConfig.getAppConfig().get(AppConfig.SCHOOL_ID);
  90 + mRxManager.register(mIModel.getExpressInfo(expressCode, scholId).subscribe(new Consumer<JsonObject>() {
  91 + @Override
  92 + public void accept(JsonObject jsonObject) throws Exception {
  93 + if (jsonObject.get("status").getAsInt() == 1) {
  94 + JsonArray jsonArray = jsonObject.getAsJsonArray("data");
  95 + ExpressBean expressBean = new ExpressBean();
  96 + if (jsonArray.size() > 0) {
  97 + JsonObject exoressBeanObj = jsonArray.get(0).getAsJsonObject();
  98 + expressBean.teacherName = exoressBeanObj.get("userName").getAsString();
  99 + expressBean.teacherNum = exoressBeanObj.get("moilePhone").getAsString();
  100 + expressBean.expressCode = exoressBeanObj.get("expressNumber").getAsString();
  101 + expressBean.state = exoressBeanObj.get("state").getAsInt();
  102 + } else {//未录入快递
  103 + expressBean.state = 2;
  104 + }
  105 + mIView.showExpressInfo(expressBean);
  106 + }
  107 + Log.d("55555", "getExpressInfo=" + jsonObject.toString());
  108 + }
  109 + }, new Consumer<Throwable>() {
  110 + @Override
  111 + public void accept(Throwable throwable) throws Exception {
  112 + Log.d("55555", "getExpressInfo=" + throwable.toString());
  113 + }
  114 + }));
  115 +
  116 + }
  117 +
  118 + @Override
  119 + public void getTeacherName(String tel) {
  120 + mRxManager.register(mIModel.getTeacherName(tel).subscribe(new Consumer<JsonObject>() {
  121 + @Override
  122 + public void accept(JsonObject jsonObject) throws Exception {
  123 + try {
  124 +
  125 + if (jsonObject.get("status").getAsInt() == 1) {
  126 + JsonObject data = jsonObject.getAsJsonObject("data");
  127 + mIView.showTeacherName(data.get("userName").getAsString());
  128 + } else ToastUtils.showToast(jsonObject.get("message").getAsString());
  129 +
  130 + } catch (Exception e) {
  131 + e.printStackTrace();
  132 + }
  133 + }
  134 + }, new Consumer<Throwable>() {
  135 + @Override
  136 + public void accept(Throwable throwable) throws Exception {
  137 +
  138 + }
  139 + }));
  140 + }
  141 +
  142 + //录入快递
  143 + @Override
  144 + public void upExpressInfo(ExpressBean expressBean) {
  145 + mRxManager.register(mIModel.upExpressInfo(expressBean).subscribe(new Consumer<JsonObject>() {
  146 + @Override
  147 + public void accept(JsonObject jsonObject) throws Exception {
  148 + try {
  149 + if (jsonObject.get("status").getAsInt() == 1) {
  150 + mIView.showExpressInfoSuccess(true);
  151 + } else ToastUtils.showToast(jsonObject.get("message").getAsString());
  152 + } catch (Exception e) {
  153 + e.printStackTrace();
  154 + }
  155 + }
  156 + }, new Consumer<Throwable>() {
  157 + @Override
  158 + public void accept(Throwable throwable) throws Exception {
  159 +// Log.d("55555","upExpressInfo="+throwable.toString());
  160 + }
  161 + }));
  162 + }
  163 +
  164 + @Override
  165 + public void SearchExpressPhone(String mobile) {
  166 + mRxManager.register(mIModel.SearchExpressPhone(mobile).subscribe(new Consumer<JsonObject>() {
  167 + @Override
  168 + public void accept(JsonObject jsonObject) throws Exception {
  169 + try {
  170 + Log.d("55555","SearchExpressPhone="+jsonObject.toString());
  171 + if (jsonObject.get("status").getAsInt() == 1) {
  172 + List<String> list = new ArrayList<>();
  173 + JsonArray data = jsonObject.getAsJsonArray("data");
  174 + for (int i = 0; i < data.size(); i++) {
  175 + JsonObject jsonObject1 = data.get(i).getAsJsonObject();
  176 + list.add(jsonObject1.get("moilePhone").getAsString());
  177 + }
  178 + mIView.showSearchModel(list);
  179 + } else ToastUtils.showToast(jsonObject.get("message").getAsString());
  180 + } catch (Exception e) {
  181 + e.printStackTrace();
  182 + }
  183 + }
  184 + }, new Consumer<Throwable>() {
  185 + @Override
  186 + public void accept(Throwable throwable) throws Exception {
  187 + Log.d("55555","SearchExpressPhone="+throwable.toString());
  188 + }
  189 + }));
  190 + }
  191 +
  192 + /**
  193 + * 领取快递
  194 + * @param ExpressNumber
  195 + * @param schoolId
  196 + */
  197 + @Override
  198 + public void UpdateIsReceive(String ExpressNumber, String schoolId) {
  199 + mRxManager.register(mIModel.UpdateIsReceive(ExpressNumber,schoolId).subscribe(new Consumer<JsonObject>() {
  200 + @Override
  201 + public void accept(JsonObject jsonObject) throws Exception {
  202 + try {
  203 + if (jsonObject.get("status").getAsInt()==1){
  204 + mIView.showUpdateIsReceive(true);
  205 + }else ToastUtils.showToast(jsonObject.get("message").getAsString());
  206 + }catch (Exception e){
  207 + e.printStackTrace();
  208 + }
  209 + }
  210 + }, new Consumer<Throwable>() {
  211 + @Override
  212 + public void accept(Throwable throwable) throws Exception {
  213 + ToastUtils.showToast(throwable.toString());
  214 + }
  215 + }));
  216 + }
  217 +}
app/src/main/res/drawable/selector_btn.xml 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<selector xmlns:android="http://schemas.android.com/apk/res/android">
  3 +
  4 + <item android:state_pressed="true" android:drawable="@drawable/shape_gray"/>
  5 + <item android:drawable="@drawable/shape_blue"/>
  6 +
  7 +</selector>
0 \ No newline at end of file 8 \ No newline at end of file
app/src/main/res/drawable/shape_blue.xml 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<shape xmlns:android="http://schemas.android.com/apk/res/android">
  3 +
  4 + <corners android:radius="@dimen/dp_8"/>
  5 + <solid android:color="@color/md_light_blue_500"/>
  6 +
  7 +</shape>
0 \ No newline at end of file 8 \ No newline at end of file
app/src/main/res/drawable/shape_edit.xml 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<shape xmlns:android="http://schemas.android.com/apk/res/android">
  3 +
  4 + <corners android:radius="@dimen/dp_8"/>
  5 +
  6 + <stroke android:color="@color/gray" android:width="1dp"/>
  7 +
  8 +</shape>
0 \ No newline at end of file 9 \ No newline at end of file
app/src/main/res/drawable/shape_gray.xml 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<shape xmlns:android="http://schemas.android.com/apk/res/android">
  3 + <corners android:radius="@dimen/dp_8"/>
  4 + <solid android:color="@color/gray"/>
  5 +</shape>
0 \ No newline at end of file 6 \ No newline at end of file
app/src/main/res/layout/activity_base.xml 0 → 100644
@@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + xmlns:app="http://schemas.android.com/apk/res-auto"
  4 + xmlns:tools="http://schemas.android.com/tools"
  5 + android:layout_width="match_parent"
  6 + android:layout_height="match_parent"
  7 + tools:context="com.shunzhi.expressscanner.base.BaseActivity">
  8 +
  9 + <android.support.design.widget.AppBarLayout
  10 + android:layout_width="match_parent"
  11 + android:layout_height="wrap_content"
  12 + android:theme="@style/AppTheme.AppBarOverlay">
  13 +
  14 + <android.support.v7.widget.Toolbar
  15 + android:id="@+id/toolbar"
  16 + android:layout_width="match_parent"
  17 + android:layout_height="?attr/actionBarSize"
  18 + android:background="?attr/colorPrimary"
  19 + app:popupTheme="@style/AppTheme.PopupOverlay" />
  20 +
  21 + </android.support.design.widget.AppBarLayout>
  22 +
  23 + <include layout="@layout/content_base" />
  24 +
  25 + <android.support.design.widget.FloatingActionButton
  26 + android:id="@+id/fab"
  27 + android:layout_width="wrap_content"
  28 + android:layout_height="wrap_content"
  29 + android:layout_gravity="bottom|end"
  30 + android:layout_margin="@dimen/fab_margin"
  31 + app:srcCompat="@android:drawable/ic_dialog_email" />
  32 +
  33 +</android.support.design.widget.CoordinatorLayout>
app/src/main/res/layout/activity_main.xml
1 <?xml version="1.0" encoding="utf-8"?> 1 <?xml version="1.0" encoding="utf-8"?>
2 -<android.support.constraint.ConstraintLayout 2 +<FrameLayout
3 xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:android="http://schemas.android.com/apk/res/android"
4 xmlns:tools="http://schemas.android.com/tools" 4 xmlns:tools="http://schemas.android.com/tools"
5 xmlns:app="http://schemas.android.com/apk/res-auto" 5 xmlns:app="http://schemas.android.com/apk/res-auto"
6 android:layout_width="match_parent" 6 android:layout_width="match_parent"
7 android:layout_height="match_parent" 7 android:layout_height="match_parent"
  8 + android:id="@+id/frame"
8 tools:context="com.shunzhi.expressscanner.MainActivity"> 9 tools:context="com.shunzhi.expressscanner.MainActivity">
9 10
10 - <TextView  
11 - android:layout_width="wrap_content"  
12 - android:layout_height="wrap_content"  
13 - android:text="Hello World!"  
14 - app:layout_constraintBottom_toBottomOf="parent"  
15 - app:layout_constraintLeft_toLeftOf="parent"  
16 - app:layout_constraintRight_toRightOf="parent"  
17 - app:layout_constraintTop_toTopOf="parent" />  
18 11
19 -</android.support.constraint.ConstraintLayout> 12 +</FrameLayout>
app/src/main/res/layout/content_base.xml 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + xmlns:app="http://schemas.android.com/apk/res-auto"
  4 + xmlns:tools="http://schemas.android.com/tools"
  5 + android:layout_width="match_parent"
  6 + android:layout_height="match_parent"
  7 + app:layout_behavior="@string/appbar_scrolling_view_behavior"
  8 + tools:context="com.shunzhi.expressscanner.base.BaseActivity"
  9 + tools:showIn="@layout/activity_base">
  10 +
  11 +</android.support.constraint.ConstraintLayout>
app/src/main/res/layout/fragment_main.xml 0 → 100644
@@ -0,0 +1,180 @@ @@ -0,0 +1,180 @@
  1 +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2 + xmlns:tools="http://schemas.android.com/tools"
  3 + android:layout_width="match_parent"
  4 + android:layout_height="match_parent"
  5 + android:background="@color/white"
  6 + tools:context="com.shunzhi.expressscanner.fragment.MainFragment">
  7 +
  8 +
  9 + <LinearLayout
  10 + android:layout_width="match_parent"
  11 + android:layout_height="wrap_content"
  12 + android:layout_gravity="center"
  13 + android:layout_marginBottom="@dimen/dp_60"
  14 + android:orientation="vertical">
  15 +
  16 + <LinearLayout
  17 + android:layout_width="match_parent"
  18 + android:gravity="center"
  19 + android:layout_height="wrap_content"
  20 + android:orientation="vertical"
  21 + >
  22 + <TextView
  23 + android:layout_width="wrap_content"
  24 + android:layout_height="wrap_content"
  25 + android:layout_marginBottom="@dimen/dp_10"
  26 + android:text="快递管理系统"
  27 + android:textColor="@color/text_color_dark"
  28 + android:textSize="@dimen/sp_20" />
  29 +
  30 +
  31 + <LinearLayout
  32 + android:id="@+id/layout_express"
  33 + android:layout_width="match_parent"
  34 + android:layout_height="wrap_content"
  35 + android:layout_marginLeft="10dp"
  36 + android:layout_marginRight="10dp"
  37 + android:layout_marginTop="@dimen/dp_10"
  38 + android:gravity="center">
  39 +
  40 + <TextView
  41 + android:layout_width="0dp"
  42 + android:layout_height="wrap_content"
  43 + android:layout_weight="1"
  44 + android:gravity="right"
  45 + android:text="快递号:"
  46 + android:textColor="@color/text_color_dark"
  47 + android:textSize="@dimen/sp_14" />
  48 +
  49 + <EditText
  50 + android:id="@+id/etExpressCode"
  51 + android:layout_width="0dp"
  52 + android:layout_height="@dimen/avatarSize"
  53 + android:layout_marginLeft="@dimen/dp_10"
  54 + android:layout_weight="5"
  55 + android:background="@drawable/shape_edit"
  56 + android:hint="快递单号"
  57 + android:maxLines="1"
  58 + android:paddingLeft="@dimen/dp_5"
  59 + android:singleLine="true"
  60 + android:textColor="@color/text_color_dark"
  61 + android:textColorHint="@color/gray"
  62 + android:textSize="@dimen/sp_14" />
  63 +
  64 + </LinearLayout>
  65 +
  66 + <LinearLayout
  67 + android:id="@+id/layout_tel"
  68 + android:layout_width="match_parent"
  69 + android:layout_height="wrap_content"
  70 + android:layout_marginLeft="10dp"
  71 + android:layout_marginRight="10dp"
  72 + android:layout_marginTop="@dimen/dp_10"
  73 + android:gravity="center"
  74 + android:visibility="invisible">
  75 +
  76 + <TextView
  77 + android:layout_width="0dp"
  78 + android:layout_height="wrap_content"
  79 + android:layout_weight="1"
  80 + android:gravity="right"
  81 + android:text="手机号:"
  82 + android:textColor="@color/text_color_dark"
  83 + android:textSize="@dimen/sp_14" />
  84 +
  85 + <EditText
  86 + android:id="@+id/etTel"
  87 + android:layout_width="0dp"
  88 + android:layout_height="@dimen/avatarSize"
  89 + android:layout_marginLeft="@dimen/dp_10"
  90 + android:layout_weight="5"
  91 + android:paddingLeft="@dimen/dp_5"
  92 + android:background="@drawable/shape_edit"
  93 + android:hint="请输入11位手机号"
  94 + android:maxLines="1"
  95 + android:singleLine="true"
  96 + android:textColor="@color/text_color_dark"
  97 + android:textColorHint="@color/gray"
  98 + android:textSize="@dimen/sp_14" />
  99 +
  100 + </LinearLayout>
  101 +
  102 + <LinearLayout
  103 + android:id="@+id/layout_name"
  104 + android:layout_width="match_parent"
  105 + android:layout_height="wrap_content"
  106 + android:layout_marginLeft="10dp"
  107 + android:layout_marginRight="10dp"
  108 + android:layout_marginTop="@dimen/dp_10"
  109 + android:gravity="center"
  110 + android:visibility="invisible">
  111 +
  112 + <TextView
  113 + android:layout_width="0dp"
  114 + android:layout_height="wrap_content"
  115 + android:layout_weight="1"
  116 + android:gravity="right"
  117 + android:text="姓名:"
  118 + android:textColor="@color/text_color_dark"
  119 + android:textSize="@dimen/sp_14" />
  120 +
  121 + <EditText
  122 + android:id="@+id/etName"
  123 + android:layout_width="0dp"
  124 + android:layout_height="@dimen/avatarSize"
  125 + android:layout_marginLeft="@dimen/dp_10"
  126 + android:layout_weight="5"
  127 + android:paddingLeft="@dimen/dp_5"
  128 + android:background="@drawable/shape_edit"
  129 + android:hint="无需输入,根据号码显示姓名"
  130 + android:maxLines="1"
  131 + android:singleLine="true"
  132 + android:textColor="@color/gray"
  133 + android:textColorHint="@color/gray"
  134 + android:textSize="@dimen/sp_14" />
  135 +
  136 + </LinearLayout>
  137 +
  138 + <Button
  139 + android:id="@+id/tvCommint"
  140 + android:layout_width="match_parent"
  141 + android:layout_height="wrap_content"
  142 + android:layout_marginLeft="@dimen/dp_10"
  143 + android:layout_marginRight="@dimen/dp_10"
  144 + android:layout_marginTop="@dimen/dp_30"
  145 + android:background="@drawable/selector_btn"
  146 + android:gravity="center"
  147 + android:text="确定并扫描快递"
  148 + android:textColor="@color/white"
  149 + android:textSize="@dimen/sp_16" />
  150 +
  151 + </LinearLayout>
  152 + <Button
  153 + android:id="@+id/tvCancle"
  154 + android:layout_width="match_parent"
  155 + android:layout_height="wrap_content"
  156 + android:layout_marginLeft="@dimen/dp_10"
  157 + android:layout_marginRight="@dimen/dp_10"
  158 + android:layout_marginTop="@dimen/dp_10"
  159 + android:background="@drawable/shape_gray"
  160 + android:gravity="center"
  161 + android:text="取消"
  162 + android:textColor="@color/white"
  163 + android:textSize="@dimen/sp_16"
  164 + android:visibility="gone" />
  165 +
  166 +
  167 + </LinearLayout>
  168 +
  169 + <TextView
  170 + android:id="@+id/tvTips"
  171 + android:layout_width="wrap_content"
  172 + android:layout_height="wrap_content"
  173 + android:layout_gravity="bottom|center"
  174 + android:layout_marginBottom="60dp"
  175 + android:text="提示:请扫描快递"
  176 + android:textColor="@color/md_red_500"
  177 + android:textSize="@dimen/sp_14" />
  178 +
  179 +
  180 +</FrameLayout>
app/src/main/res/layout/item_mobile.xml 0 → 100644
@@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:layout_width="match_parent"
  4 + android:layout_height="?android:actionBarSize">
  5 +
  6 + <TextView
  7 + android:layout_width="match_parent"
  8 + android:layout_height="match_parent"
  9 + android:textColor="@color/text_color_dark"
  10 + android:textSize="@dimen/sp_14"
  11 + android:gravity="center_vertical"
  12 + android:layout_gravity="center_vertical"
  13 + android:paddingLeft="15dp"
  14 + android:id="@+id/tvName"
  15 + />
  16 +
  17 + <View
  18 + android:layout_width="match_parent"
  19 + android:layout_height="0.5dp"
  20 + android:layout_gravity="bottom"
  21 + android:background="@color/gray"
  22 + android:layout_marginLeft="@dimen/dp_10"
  23 + android:layout_marginRight="@dimen/dp_10"
  24 + />
  25 +
  26 +</FrameLayout>
0 \ No newline at end of file 27 \ No newline at end of file
app/src/main/res/layout/popu_mobile.xml 0 → 100644
@@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:layout_width="match_parent"
  4 + android:layout_marginLeft="10dp"
  5 + android:layout_marginRight="10dp"
  6 + android:background="@color/white"
  7 + android:layout_height="match_parent">
  8 +
  9 + <android.support.v7.widget.RecyclerView
  10 + android:id="@+id/recyclerView"
  11 + android:layout_width="match_parent"
  12 + android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>
  13 +
  14 +</LinearLayout>
0 \ No newline at end of file 15 \ No newline at end of file
app/src/main/res/raw/beep.ogg 0 → 100644
No preview for this file type
app/src/main/res/raw/scan.ogg 0 → 100644
No preview for this file type
app/src/main/res/values/dimens.xml 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<resources>
  2 + <dimen name="fab_margin">16dp</dimen>
  3 +</resources>
app/src/main/res/values/strings.xml
1 <resources> 1 <resources>
2 <string name="app_name">ExpressScanner</string> 2 <string name="app_name">ExpressScanner</string>
  3 +
  4 + <!-- TODO: Remove or change this placeholder text -->
  5 + <string name="hello_blank_fragment">Hello blank fragment</string>
  6 + <string name="title_activity_base">BaseActivity</string>
  7 + <string name="service_bind_success">服务绑定成功</string>
  8 + <string name="service_bind_fail">服务绑定失败</string>
3 </resources> 9 </resources>
app/src/main/res/values/styles.xml
@@ -8,4 +8,13 @@ @@ -8,4 +8,13 @@
8 <item name="colorAccent">@color/colorAccent</item> 8 <item name="colorAccent">@color/colorAccent</item>
9 </style> 9 </style>
10 10
  11 + <style name="AppTheme.NoActionBar">
  12 + <item name="windowActionBar">false</item>
  13 + <item name="windowNoTitle">true</item>
  14 + </style>
  15 +
  16 + <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
  17 +
  18 + <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
  19 +
11 </resources> 20 </resources>
@@ -19,9 +19,49 @@ allprojects { @@ -19,9 +19,49 @@ allprojects {
19 repositories { 19 repositories {
20 google() 20 google()
21 jcenter() 21 jcenter()
  22 + maven { url 'https://jitpack.io' }
22 } 23 }
23 } 24 }
24 25
25 task clean(type: Delete) { 26 task clean(type: Delete) {
26 delete rootProject.buildDir 27 delete rootProject.buildDir
27 } 28 }
  29 +
  30 +
  31 +ext {
  32 + // Sdk and tools
  33 + minSdkVersion = 16
  34 + targetSdkVersion = 26
  35 + compileSdkVersion = 26
  36 + buildToolsVersion = '26.0.2'
  37 +
  38 + // App dependencies
  39 + supportLibraryVersion = '26.1.0'
  40 + guavaVersion = '18.0'
  41 + junitVersion = '4.12'
  42 + mockitoVersion = '1.10.19'
  43 + powerMockito = '1.6.2'
  44 + hamcrestVersion = '1.3'
  45 + runnerVersion = '0.4.1'
  46 + rulesVersion = '0.4.1'
  47 + espressoVersion = '2.2.1'
  48 + retrofitVersion = '2.2.0'
  49 + okhttploggingVersion = '3.4.1'
  50 + okhttpVersion = '3.4.1'
  51 + rxjavaVersion = '2.0.1'
  52 + rxandroidVersion = '2.0.1'
  53 + rxbindingVersion = '2.0.0'
  54 + rxPerssionsVersion = '0.9.4@aar'
  55 + glideVersion = '3.6.1'
  56 + glideokhttpVersion = '1.3.1'
  57 + photoviewVersion = '1.2.4'
  58 + butterknifeVersion = '8.4.0'
  59 + fragmentationVersion = '1.1.6'
  60 + loggerVersion = '1.15'
  61 + circleImageviewVersion = '2.1.0'
  62 + BaseRecyclerViewAdapterHelperVersion = '2.9.34'
  63 + SwtichButtonVersion = '1.4.6'
  64 + PhotoViewVersion = '1.4.1'
  65 + BottomSheetVersion = '1.3.0@aar'
  66 + glideTransformationVersion = '2.0.1'
  67 +}
mvpsdk/.gitignore 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +/build
mvpsdk/build.gradle 0 → 100644
@@ -0,0 +1,129 @@ @@ -0,0 +1,129 @@
  1 +apply plugin: 'com.android.library'
  2 +
  3 +android {
  4 + compileSdkVersion rootProject.ext.compileSdkVersion
  5 + buildToolsVersion rootProject.ext.buildToolsVersion
  6 +
  7 +
  8 + defaultConfig {
  9 + minSdkVersion rootProject.ext.minSdkVersion
  10 + targetSdkVersion rootProject.ext.targetSdkVersion
  11 + versionCode 1
  12 + versionName "1.0"
  13 +
  14 + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
  15 +
  16 + }
  17 +
  18 + buildTypes {
  19 + def BOOLEAN = "boolean"
  20 + def TRUE = "true"
  21 + def FALSE = "false"
  22 + def IS_SHOW_LOG = "IS_SHOW_LOG"
  23 +
  24 + release {
  25 + minifyEnabled false
  26 + buildConfigField BOOLEAN, IS_SHOW_LOG, FALSE
  27 + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  28 + }
  29 + }
  30 + publishNonDefault true
  31 +}
  32 +//repositories {
  33 +// flatDir {
  34 +// dirs 'libs' //this way we can find the .aar file in libs folder
  35 +// }
  36 +// google()
  37 +//}
  38 +dependencies {
  39 + implementation fileTree(dir: 'libs', include: ['*.jar'])
  40 +
  41 + implementation 'com.android.support:appcompat-v7:26.1.0'
  42 + implementation 'com.android.support.constraint:constraint-layout:1.0.2'
  43 + testImplementation 'junit:junit:4.12'
  44 + androidTestImplementation 'com.android.support.test:runner:1.0.1'
  45 + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
  46 +
  47 + // Android support
  48 + compile "com.android.support:appcompat-v7:$rootProject.supportLibraryVersion"
  49 + compile "com.android.support:cardview-v7:$rootProject.supportLibraryVersion"
  50 + compile "com.android.support:design:$rootProject.supportLibraryVersion"
  51 + compile "com.android.support:recyclerview-v7:$rootProject.supportLibraryVersion"
  52 +
  53 + //delete
  54 + compile 'com.yanzhenjie:recyclerview-swipe:1.1.4'
  55 +
  56 + // Retrofit
  57 + compile "com.squareup.retrofit2:retrofit:$rootProject.retrofitVersion"
  58 + compile "com.squareup.retrofit2:converter-gson:$rootProject.retrofitVersion"
  59 + compile "com.squareup.retrofit2:adapter-rxjava2:$rootProject.retrofitVersion"
  60 + compile "com.squareup.okhttp3:logging-interceptor:$rootProject.okhttploggingVersion"
  61 + compile "com.squareup.okhttp3:okhttp:$rootProject.okhttpVersion"
  62 +
  63 + // RxJava
  64 + compile "io.reactivex.rxjava2:rxjava:$rootProject.rxjavaVersion"
  65 + compile "io.reactivex.rxjava2:rxandroid:$rootProject.rxandroidVersion"
  66 + compile "com.jakewharton.rxbinding2:rxbinding:$rootProject.rxbindingVersion"
  67 +
  68 + // Glide
  69 + compile "com.github.bumptech.glide:glide:$rootProject.glideVersion"
  70 + compile "com.github.bumptech.glide:okhttp-integration:$rootProject.glideokhttpVersion"
  71 + compile "jp.wasabeef:glide-transformations:$rootProject.glideTransformationVersion"
  72 +
  73 + //Butterknife
  74 + compile "com.jakewharton:butterknife:$rootProject.butterknifeVersion"
  75 + annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
  76 +
  77 + //fragmentation
  78 + compile "me.yokeyword:fragmentation:$rootProject.fragmentationVersion"
  79 +
  80 + //Logger
  81 + compile "com.orhanobut:logger:$rootProject.loggerVersion"
  82 +
  83 + //circle imageview
  84 + compile "de.hdodenhof:circleimageview:$rootProject.circleImageviewVersion"
  85 +
  86 + //BaseRecyclerViewAdapterHelper
  87 + compile "com.github.CymChad:BaseRecyclerViewAdapterHelper:$rootProject.BaseRecyclerViewAdapterHelperVersion"
  88 +
  89 + //SwitchButton
  90 + compile "com.kyleduo.switchbutton:library:$rootProject.SwtichButtonVersion"
  91 +
  92 + //PhotoView
  93 + compile "com.bm.photoview:library:$rootProject.PhotoViewVersion"
  94 +
  95 + compile "com.cocosw:bottomsheet:$rootProject.BottomSheetVersion"
  96 +
  97 + //permissions
  98 + compile "com.tbruyelle.rxpermissions2:rxpermissions:$rootProject.rxPerssionsVersion"
  99 +
  100 + //timber
  101 + compile 'com.jakewharton.timber:timber:4.5.1'
  102 +
  103 + //jiaozivideoplayer
  104 + compile 'cn.jzvd:jiaozivideoplayer:6.2.7'
  105 +// compile(name: 'jiaozivideoplayer-6.2.3', ext: 'aar')
  106 +
  107 + //轮播图XBanner
  108 + compile 'com.xhb:xbanner:1.3.1'
  109 +
  110 + //省市区联动
  111 + compile 'me.leefeng:citypicker:1.0'
  112 +
  113 + //日历控件
  114 + compile 'com.github.idic779:monthweekmaterialcalendarview:1.7'
  115 +
  116 + //标签拖动排序
  117 + compile 'com.huxq17.handygridview:handygridview:1.1.0'
  118 +
  119 + //xrecyclerview
  120 + compile 'com.jcodecraeer:xrecyclerview:1.5.9'
  121 +
  122 + //悬浮窗
  123 +// compile 'com.github.yhaolpz:FloatWindow:1.0.8'
  124 +//数据库
  125 + compile 'com.j256.ormlite:ormlite-core:4.48'
  126 + compile 'com.j256.ormlite:ormlite-android:4.48'
  127 +
  128 +
  129 +}
mvpsdk/proguard-rules.pro 0 → 100644
@@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
  1 +# Add project specific ProGuard rules here.
  2 +# You can control the set of applied configuration files using the
  3 +# proguardFiles setting in build.gradle.
  4 +#
  5 +# For more details, see
  6 +# http://developer.android.com/guide/developing/tools/proguard.html
  7 +
  8 +# If your project uses WebView with JS, uncomment the following
  9 +# and specify the fully qualified class name to the JavaScript interface
  10 +# class:
  11 +#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
  12 +# public *;
  13 +#}
  14 +
  15 +# Uncomment this to preserve the line number information for
  16 +# debugging stack traces.
  17 +#-keepattributes SourceFile,LineNumberTable
  18 +
  19 +# If you keep the line number information, uncomment this to
  20 +# hide the original source file name.
  21 +#-renamesourcefileattribute SourceFile
mvpsdk/src/androidTest/java/com/share/mvpsdk/ExampleInstrumentedTest.java 0 → 100644
@@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
  1 +package com.share.mvpsdk;
  2 +
  3 +import android.content.Context;
  4 +import android.support.test.InstrumentationRegistry;
  5 +import android.support.test.runner.AndroidJUnit4;
  6 +
  7 +import org.junit.Test;
  8 +import org.junit.runner.RunWith;
  9 +
  10 +import static org.junit.Assert.*;
  11 +
  12 +/**
  13 + * Instrumented test, which will execute on an Android device.
  14 + *
  15 + * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
  16 + */
  17 +@RunWith(AndroidJUnit4.class)
  18 +public class ExampleInstrumentedTest {
  19 + @Test
  20 + public void useAppContext() throws Exception {
  21 + // Context of the app under test.
  22 + Context appContext = InstrumentationRegistry.getTargetContext();
  23 +
  24 + assertEquals("com.share.mvpsdk.test", appContext.getPackageName());
  25 + }
  26 +}
mvpsdk/src/main/AndroidManifest.xml 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3 + package="com.share.mvpsdk">
  4 +
  5 + <application></application>
  6 +
  7 +</manifest>
0 \ No newline at end of file 8 \ No newline at end of file
mvpsdk/src/main/java/com/share/mvpsdk/AppManager.java 0 → 100644
@@ -0,0 +1,111 @@ @@ -0,0 +1,111 @@
  1 +package com.share.mvpsdk;
  2 +
  3 +import android.annotation.SuppressLint;
  4 +import android.app.Activity;
  5 +import android.app.ActivityManager;
  6 +import android.content.Context;
  7 +
  8 +import java.util.Stack;
  9 +
  10 +/**
  11 + * Created by Horrarndoo on 2017/4/5.
  12 + * <p>
  13 + * AppManager 管理Activity栈
  14 + */
  15 +
  16 +public class AppManager {
  17 + private static Stack<Activity> activityStack;
  18 + private static AppManager instance;
  19 +
  20 + private AppManager() {
  21 + }
  22 +
  23 + /**
  24 + * 单一实例
  25 + */
  26 + public static AppManager getAppManager() {
  27 + if (instance == null) {
  28 + instance = new AppManager();
  29 + }
  30 + return instance;
  31 + }
  32 +
  33 + /**
  34 + * 添加Activity到堆栈
  35 + */
  36 + public void addActivity(Activity activity) {
  37 + if (activityStack == null) {
  38 + activityStack = new Stack<Activity>();
  39 + }
  40 + activityStack.add(activity);
  41 + }
  42 +
  43 + /**
  44 + * 获取当前Activity(堆栈中最后一个压入的)
  45 + */
  46 + public Activity currentActivity() {
  47 + Activity activity = activityStack.lastElement();
  48 + return activity;
  49 + }
  50 +
  51 + /**
  52 + * 结束当前Activity(堆栈中最后一个压入的)
  53 + */
  54 + public void finishActivity() {
  55 + Activity activity = activityStack.lastElement();
  56 + finishActivity(activity);
  57 + }
  58 +
  59 + /**
  60 + * 结束指定的Activity
  61 + */
  62 + public void finishActivity(Activity activity) {
  63 + if (activity != null) {
  64 + activityStack.remove(activity);
  65 + activity.finish();
  66 + activity = null;
  67 + }
  68 + }
  69 +
  70 + /**
  71 + * 结束指定类名的Activity
  72 + */
  73 + public void finishActivity(Class<?> cls) {
  74 + for (Activity activity : activityStack) {
  75 + if (activity.getClass().equals(cls)) {
  76 + finishActivity(activity);
  77 + }
  78 + }
  79 + }
  80 +
  81 + /**
  82 + * 结束所有Activity
  83 + */
  84 + public void finishAllActivity() {
  85 + for (int i = 0, size = activityStack.size(); i < size; i++) {
  86 + if (null != activityStack.get(i)) {
  87 + activityStack.get(i).finish();
  88 + }
  89 + }
  90 + activityStack.clear();
  91 + }
  92 +
  93 + /**
  94 + * 退出应用程序
  95 + */
  96 + @SuppressLint("MissingPermission")
  97 + public void AppExit(Context context) {
  98 + try {
  99 + finishAllActivity();
  100 + ActivityManager activityMgr =
  101 + (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
  102 + activityMgr.killBackgroundProcesses(context.getPackageName());
  103 + System.exit(0);
  104 + } catch (Exception e) {
  105 + }
  106 + }
  107 +
  108 + public boolean isAppExit() {
  109 + return activityStack == null || activityStack.isEmpty();
  110 + }
  111 +}
mvpsdk/src/main/java/com/share/mvpsdk/RxManager.java 0 → 100644
@@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
  1 +package com.share.mvpsdk;
  2 +
  3 +
  4 +import io.reactivex.disposables.CompositeDisposable;
  5 +import io.reactivex.disposables.Disposable;
  6 +
  7 +/**
  8 + * Created by Horrarndoo on 2017/9/12.
  9 + * <p>
  10 + * 用于管理Rxjava 注册订阅和取消订阅
  11 + */
  12 +
  13 +public class RxManager {
  14 + private CompositeDisposable mCompositeDisposable = new CompositeDisposable();// 管理订阅者者
  15 +
  16 + public void register(Disposable d) {
  17 + mCompositeDisposable.add(d);
  18 + }
  19 +
  20 + public void unSubscribe() {
  21 + mCompositeDisposable.dispose();// 取消订阅
  22 + }
  23 +}
0 \ No newline at end of file 24 \ No newline at end of file
mvpsdk/src/main/java/com/share/mvpsdk/adapter/FragmentAdapter.java 0 → 100644
@@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
  1 +package com.share.mvpsdk.adapter;
  2 +
  3 +
  4 +import android.support.v4.app.Fragment;
  5 +import android.support.v4.app.FragmentManager;
  6 +import android.support.v4.app.FragmentStatePagerAdapter;
  7 +import android.support.v4.view.PagerAdapter;
  8 +import android.view.ViewGroup;
  9 +
  10 +import java.util.List;
  11 +
  12 +/**
  13 + * Created by Horrarndoo on 2017/9/7.
  14 + * <p>
  15 + */
  16 +public class FragmentAdapter extends FragmentStatePagerAdapter {
  17 + private List<Fragment> fragments;
  18 +
  19 + public FragmentAdapter(FragmentManager fm, List<Fragment> fragments) {
  20 + super(fm);
  21 + this.fragments = fragments;
  22 + }
  23 +
  24 + @Override
  25 + public Fragment getItem(int position) {
  26 + return fragments.get(position);
  27 + }
  28 +
  29 + @Override
  30 + public int getCount() {
  31 + return fragments == null ? 0 : fragments.size();
  32 + }
  33 +
  34 + public int getItemPosition(Object object) {
  35 + return PagerAdapter.POSITION_NONE;
  36 + }
  37 +
  38 + @Override
  39 + public void destroyItem(ViewGroup container, int position, Object object) {
  40 + // super.destroyItem(container, position, object);
  41 + }
  42 +}
0 \ No newline at end of file 43 \ No newline at end of file
mvpsdk/src/main/java/com/share/mvpsdk/anim/AnimManager.java 0 → 100644
@@ -0,0 +1,75 @@ @@ -0,0 +1,75 @@
  1 +package com.share.mvpsdk.anim;
  2 +
  3 +import android.content.Context;
  4 +import android.os.Build;
  5 +import android.support.annotation.NonNull;
  6 +import android.view.View;
  7 +import android.view.animation.AnimationUtils;
  8 +
  9 +/**
  10 + * Created by Horrarndoo on 2017/9/11.
  11 + * <p>
  12 + */
  13 +
  14 +public class AnimManager {
  15 + /**
  16 + * Alpha and scaleX 动画
  17 + * Alpha 0->1
  18 + * ScaleX 0.8->1
  19 + *
  20 + * @param context context
  21 + * @param view view
  22 + * @param startDelay 动画开始前延时(ms)
  23 + * @param duration 动画持续时间(ms)
  24 + */
  25 + public static void animAlphaAndScaleX(Context context, @NonNull View view, int startDelay, int
  26 + duration) {
  27 + view.setAlpha(0f);
  28 + view.setScaleX(0.8f);
  29 +
  30 + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  31 + view.animate()
  32 + .alpha(1f)
  33 + .scaleX(1f)
  34 + .setStartDelay(startDelay)
  35 + .setDuration(duration)
  36 + .setInterpolator(AnimUtils.getFastOutSlowInInterpolator(context))
  37 + .start();
  38 + }else{
  39 + view.animate()
  40 + .alpha(1f)
  41 + .scaleX(1f)
  42 + .setStartDelay(startDelay)
  43 + .setDuration(duration)
  44 + .setInterpolator(AnimationUtils.loadInterpolator(context, android.R.interpolator.linear))
  45 + .start();
  46 + }
  47 + }
  48 +
  49 + /**
  50 + * Alpha and scale X Y 动画
  51 + * Alpha 0->1
  52 + * ScaleX 0->1
  53 + * ScaleY 0->1
  54 + *
  55 + * @param context context
  56 + * @param view view
  57 + * @param startDelay 动画开始前延时(ms)
  58 + * @param duration 动画持续时间(ms)
  59 + */
  60 + public static void animAlphaAndScale(Context context, @NonNull View view, int startDelay, int
  61 + duration) {
  62 + view.setAlpha(0f);
  63 + view.setScaleX(0f);
  64 + view.setScaleY(0f);
  65 +
  66 + view.animate()
  67 + .alpha(1f)
  68 + .scaleX(1f)
  69 + .scaleY(1f)
  70 + .setStartDelay(startDelay)
  71 + .setDuration(duration)
  72 + .setInterpolator(AnimationUtils.loadInterpolator(context,
  73 + android.R.interpolator.overshoot)).start();
  74 + }
  75 +}
mvpsdk/src/main/java/com/share/mvpsdk/anim/AnimUtils.java 0 → 100644
@@ -0,0 +1,330 @@ @@ -0,0 +1,330 @@
  1 +/*
  2 + * Copyright 2015 Google Inc.
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package com.share.mvpsdk.anim;
  18 +
  19 +import android.animation.Animator;
  20 +import android.animation.TimeInterpolator;
  21 +import android.content.Context;
  22 +import android.os.Build;
  23 +import android.support.annotation.RequiresApi;
  24 +import android.transition.Transition;
  25 +import android.util.ArrayMap;
  26 +import android.util.Property;
  27 +import android.view.animation.AnimationUtils;
  28 +import android.view.animation.Interpolator;
  29 +
  30 +import java.util.ArrayList;
  31 +
  32 +/**
  33 + * Utility methods for working with animations.
  34 + */
  35 +public class AnimUtils {
  36 +
  37 + private AnimUtils() { }
  38 +
  39 + private static Interpolator fastOutSlowIn;
  40 + private static Interpolator fastOutLinearIn;
  41 + private static Interpolator linearOutSlowIn;
  42 +
  43 + public static Interpolator getFastOutSlowInInterpolator(Context context) {
  44 + if (fastOutSlowIn == null) {
  45 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  46 + fastOutSlowIn = AnimationUtils.loadInterpolator(context,
  47 + android.R.interpolator.fast_out_slow_in);
  48 + }
  49 + }
  50 + return fastOutSlowIn;
  51 + }
  52 +
  53 + public static Interpolator getFastOutLinearInInterpolator(Context context) {
  54 + if (fastOutLinearIn == null) {
  55 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  56 + fastOutLinearIn = AnimationUtils.loadInterpolator(context,
  57 + android.R.interpolator.fast_out_linear_in);
  58 + }
  59 + }
  60 + return fastOutLinearIn;
  61 + }
  62 +
  63 + public static Interpolator getLinearOutSlowInInterpolator(Context context) {
  64 + if (linearOutSlowIn == null) {
  65 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  66 + linearOutSlowIn = AnimationUtils.loadInterpolator(context,
  67 + android.R.interpolator.linear_out_slow_in);
  68 + }
  69 + }
  70 + return linearOutSlowIn;
  71 + }
  72 +
  73 + /**
  74 + * Linear interpolate between a and b with parameter t.
  75 + */
  76 + public static float lerp(float a, float b, float t) {
  77 + return a + (b - a) * t;
  78 + }
  79 +
  80 +
  81 + /**
  82 + * An implementation of {@link Property} to be used specifically with fields of
  83 + * type
  84 + * <code>float</code>. This type-specific subclass enables performance benefit by allowing
  85 + * calls to a {@link #set(Object, Float) set()} function that takes the primitive
  86 + * <code>float</code> type and avoids autoboxing and other overhead associated with the
  87 + * <code>Float</code> class.
  88 + *
  89 + * @param <T> The class on which the Property is declared.
  90 + **/
  91 + public static abstract class FloatProperty<T> extends Property<T, Float> {
  92 + public FloatProperty(String name) {
  93 + super(Float.class, name);
  94 + }
  95 +
  96 + /**
  97 + * A type-specific override of the {@link #set(Object, Float)} that is faster when dealing
  98 + * with fields of type <code>float</code>.
  99 + */
  100 + public abstract void setValue(T object, float value);
  101 +
  102 + @Override
  103 + final public void set(T object, Float value) {
  104 + setValue(object, value);
  105 + }
  106 + }
  107 +
  108 + /**
  109 + * An implementation of {@link Property} to be used specifically with fields of
  110 + * type
  111 + * <code>int</code>. This type-specific subclass enables performance benefit by allowing
  112 + * calls to a {@link #set(Object, Integer) set()} function that takes the primitive
  113 + * <code>int</code> type and avoids autoboxing and other overhead associated with the
  114 + * <code>Integer</code> class.
  115 + *
  116 + * @param <T> The class on which the Property is declared.
  117 + */
  118 + public static abstract class IntProperty<T> extends Property<T, Integer> {
  119 +
  120 + public IntProperty(String name) {
  121 + super(Integer.class, name);
  122 + }
  123 +
  124 + /**
  125 + * A type-specific override of the {@link #set(Object, Integer)} that is faster when dealing
  126 + * with fields of type <code>int</code>.
  127 + */
  128 + public abstract void setValue(T object, int value);
  129 +
  130 + @Override
  131 + final public void set(T object, Integer value) {
  132 + setValue(object, value.intValue());
  133 + }
  134 +
  135 + }
  136 +
  137 + /**
  138 + * https://halfthought.wordpress.com/2014/11/07/reveal-transition/
  139 + * <p/>
  140 + * Interrupting Activity transitions can yield an OperationNotSupportedException when the
  141 + * transition tries to pause the animator. Yikes! We can fix this by wrapping the Animator:
  142 + */
  143 + @RequiresApi(api = Build.VERSION_CODES.KITKAT)
  144 + public static class NoPauseAnimator extends Animator {
  145 + private final Animator mAnimator;
  146 + private final ArrayMap<AnimatorListener, AnimatorListener> mListeners =
  147 + new ArrayMap<AnimatorListener, AnimatorListener>();
  148 +
  149 + public NoPauseAnimator(Animator animator) {
  150 + mAnimator = animator;
  151 + }
  152 +
  153 + @RequiresApi(api = Build.VERSION_CODES.KITKAT)
  154 + @Override
  155 + public void addListener(AnimatorListener listener) {
  156 + AnimatorListener wrapper = new AnimatorListenerWrapper(this, listener);
  157 + if (!mListeners.containsKey(listener)) {
  158 + mListeners.put(listener, wrapper);
  159 + mAnimator.addListener(wrapper);
  160 + }
  161 + }
  162 +
  163 + @Override
  164 + public void cancel() {
  165 + mAnimator.cancel();
  166 + }
  167 +
  168 + @Override
  169 + public void end() {
  170 + mAnimator.end();
  171 + }
  172 +
  173 + @Override
  174 + public long getDuration() {
  175 + return mAnimator.getDuration();
  176 + }
  177 +
  178 + @Override
  179 + public TimeInterpolator getInterpolator() {
  180 + return mAnimator.getInterpolator();
  181 + }
  182 +
  183 + @Override
  184 + public void setInterpolator(TimeInterpolator timeInterpolator) {
  185 + mAnimator.setInterpolator(timeInterpolator);
  186 + }
  187 +
  188 + @Override
  189 + public ArrayList<AnimatorListener> getListeners() {
  190 + return new ArrayList<AnimatorListener>(mListeners.keySet());
  191 + }
  192 +
  193 + @Override
  194 + public long getStartDelay() {
  195 + return mAnimator.getStartDelay();
  196 + }
  197 +
  198 + @Override
  199 + public void setStartDelay(long delayMS) {
  200 + mAnimator.setStartDelay(delayMS);
  201 + }
  202 +
  203 + @Override
  204 + public boolean isPaused() {
  205 + return mAnimator.isPaused();
  206 + }
  207 +
  208 + @Override
  209 + public boolean isRunning() {
  210 + return mAnimator.isRunning();
  211 + }
  212 +
  213 + @Override
  214 + public boolean isStarted() {
  215 + return mAnimator.isStarted();
  216 + }
  217 +
  218 + /* We don't want to override pause or resume methods because we don't want them
  219 + * to affect mAnimator.
  220 + public void pause();
  221 +
  222 + public void resume();
  223 +
  224 + public void addPauseListener(AnimatorPauseListener listener);
  225 +
  226 + public void removePauseListener(AnimatorPauseListener listener);
  227 + */
  228 +
  229 + @Override
  230 + public void removeAllListeners() {
  231 + mListeners.clear();
  232 + mAnimator.removeAllListeners();
  233 + }
  234 +
  235 + @Override
  236 + public void removeListener(AnimatorListener listener) {
  237 + AnimatorListener wrapper = mListeners.get(listener);
  238 + if (wrapper != null) {
  239 + mListeners.remove(listener);
  240 + mAnimator.removeListener(wrapper);
  241 + }
  242 + }
  243 +
  244 + @Override
  245 + public Animator setDuration(long durationMS) {
  246 + mAnimator.setDuration(durationMS);
  247 + return this;
  248 + }
  249 +
  250 + @Override
  251 + public void setTarget(Object target) {
  252 + mAnimator.setTarget(target);
  253 + }
  254 +
  255 + @Override
  256 + public void setupEndValues() {
  257 + mAnimator.setupEndValues();
  258 + }
  259 +
  260 + @Override
  261 + public void setupStartValues() {
  262 + mAnimator.setupStartValues();
  263 + }
  264 +
  265 + @Override
  266 + public void start() {
  267 + mAnimator.start();
  268 + }
  269 + }
  270 +
  271 + static class AnimatorListenerWrapper implements Animator.AnimatorListener {
  272 + private final Animator mAnimator;
  273 + private final Animator.AnimatorListener mListener;
  274 +
  275 + public AnimatorListenerWrapper(Animator animator, Animator.AnimatorListener listener) {
  276 + mAnimator = animator;
  277 + mListener = listener;
  278 + }
  279 +
  280 + @Override
  281 + public void onAnimationStart(Animator animator) {
  282 + mListener.onAnimationStart(mAnimator);
  283 + }
  284 +
  285 + @Override
  286 + public void onAnimationEnd(Animator animator) {
  287 + mListener.onAnimationEnd(mAnimator);
  288 + }
  289 +
  290 + @Override
  291 + public void onAnimationCancel(Animator animator) {
  292 + mListener.onAnimationCancel(mAnimator);
  293 + }
  294 +
  295 + @Override
  296 + public void onAnimationRepeat(Animator animator) {
  297 + mListener.onAnimationRepeat(mAnimator);
  298 + }
  299 + }
  300 +
  301 + @RequiresApi(api = Build.VERSION_CODES.KITKAT)
  302 + public static class TransitionListenerAdapter implements Transition.TransitionListener {
  303 +
  304 + @Override
  305 + public void onTransitionStart(Transition transition) {
  306 +
  307 + }
  308 +
  309 + @Override
  310 + public void onTransitionEnd(Transition transition) {
  311 +
  312 + }
  313 +
  314 + @Override
  315 + public void onTransitionCancel(Transition transition) {
  316 +
  317 + }
  318 +
  319 + @Override
  320 + public void onTransitionPause(Transition transition) {
  321 +
  322 + }
  323 +
  324 + @Override
  325 + public void onTransitionResume(Transition transition) {
  326 +
  327 + }
  328 + }
  329 +
  330 +}
mvpsdk/src/main/java/com/share/mvpsdk/anim/ToolbarAnimManager.java 0 → 100644
@@ -0,0 +1,93 @@ @@ -0,0 +1,93 @@
  1 +package com.share.mvpsdk.anim;
  2 +
  3 +import android.content.Context;
  4 +import android.support.annotation.NonNull;
  5 +import android.support.v7.widget.ActionMenuView;
  6 +import android.support.v7.widget.Toolbar;
  7 +import android.view.View;
  8 +import android.widget.ImageButton;
  9 +import android.widget.TextView;
  10 +
  11 +/**
  12 + * Created by Horrarndoo on 2017/9/11.
  13 + * <p>
  14 + * Toolbar动画Manager
  15 + */
  16 +
  17 +public class ToolbarAnimManager {
  18 + /**
  19 + * Toolbar 进场动画
  20 + * <p>
  21 + * Textview&ActionMenuView渐变动画
  22 + *
  23 + * @param context context
  24 + * @param toolbar toolbar
  25 + */
  26 + public static void animIn(Context context, @NonNull Toolbar toolbar) {
  27 + ImageButton ibIcon = null;
  28 + TextView tvTitle = null;
  29 + ActionMenuView amvTheme = null;
  30 + int childCount = toolbar.getChildCount();
  31 + for (int i = 0; i < childCount; i++) {
  32 + View child = toolbar.getChildAt(i);
  33 + if(child instanceof ImageButton) {
  34 + ibIcon = (ImageButton) child;
  35 + continue;
  36 + }
  37 +
  38 + if (child instanceof ActionMenuView) {
  39 + amvTheme = (ActionMenuView) child;
  40 + continue;
  41 + }
  42 +
  43 + if (child instanceof TextView)
  44 + tvTitle = (TextView) child;
  45 + }
  46 +
  47 + if(ibIcon != null)
  48 + animNavigationIcon(context, ibIcon);
  49 +
  50 + if(tvTitle != null)
  51 + animTitle(context, tvTitle);
  52 +
  53 + if(amvTheme != null)
  54 + animMenu(context, amvTheme);
  55 + }
  56 +
  57 + /**
  58 + * Toolbar Title动画
  59 + * <p>
  60 + * NavigationIcon渐变动画
  61 + *
  62 + * @param context context
  63 + * @param imageButton 执行动画的view
  64 + */
  65 + public static void animNavigationIcon(Context context, @NonNull ImageButton imageButton) {
  66 + AnimManager.animAlphaAndScaleX(context, imageButton, 500, 900);
  67 + }
  68 +
  69 + /**
  70 + * Toolbar Title动画
  71 + * <p>
  72 + * ActionMenuView渐变动画
  73 + *
  74 + * @param context context
  75 + * @param textView 执行动画的view
  76 + */
  77 + public static void animTitle(Context context, @NonNull TextView textView) {
  78 + AnimManager.animAlphaAndScaleX(context, textView, 500, 900);
  79 + }
  80 +
  81 + /**
  82 + * Toolbar ActionMenuView动画
  83 + * <p>
  84 + * ActionMenuView渐变动画
  85 + *
  86 + * @param context context
  87 + * @param avm 执行动画的view
  88 + */
  89 + public static void animMenu(Context context, @NonNull ActionMenuView avm) {
  90 + AnimManager.animAlphaAndScale(context, avm, 500, 200); // filter
  91 + AnimManager.animAlphaAndScale(context, avm, 700, 200); // overflow
  92 + }
  93 +}
mvpsdk/src/main/java/com/share/mvpsdk/base/BaseModel.java 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +package com.share.mvpsdk.base;
  2 +
  3 +/**
  4 + * Created by Horrarndoo on 2017/4/25.
  5 + * base model类
  6 + */
  7 +
  8 +public abstract class BaseModel {
  9 + public BaseModel() {
  10 + }
  11 +}
mvpsdk/src/main/java/com/share/mvpsdk/base/BasePresenter.java 0 → 100644
@@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
  1 +package com.share.mvpsdk.base;
  2 +
  3 +import android.support.annotation.NonNull;
  4 +
  5 +import com.share.mvpsdk.RxManager;
  6 +
  7 +
  8 +/**
  9 + * Created by Horrarndoo on 2017/4/25.
  10 + * <p>
  11 + * base presenter
  12 + */
  13 +
  14 +public abstract class BasePresenter<M, V> {
  15 + public M mIModel;
  16 + public V mIView;
  17 + protected RxManager mRxManager = new RxManager();
  18 +
  19 + /**
  20 + * 返回presenter想持有的Model引用
  21 + *
  22 + * @return presenter持有的Model引用
  23 + */
  24 + public abstract M getModel();
  25 +
  26 + /**
  27 + * 绑定IModel和IView的引用
  28 + *
  29 + * @param m model
  30 + * @param v view
  31 + */
  32 + public void attachMV(@NonNull M m, @NonNull V v) {
  33 + this.mIModel = m;
  34 + this.mIView = v;
  35 + this.onStart();
  36 + }
  37 +
  38 + /**
  39 + * 解绑IModel和IView
  40 + */
  41 + public void detachMV() {
  42 + mRxManager.unSubscribe();
  43 + mIView = null;
  44 + mIModel = null;
  45 + }
  46 +
  47 + /**
  48 + * IView和IModel绑定完成立即执行
  49 + * <p>
  50 + * 实现类实现绑定完成后的逻辑,例如数据初始化等,界面初始化, 更新等
  51 + */
  52 + public abstract void onStart();
  53 +}
mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseActivity.java 0 → 100644
@@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
  1 +package com.share.mvpsdk.base;
  2 +
  3 +import android.os.Bundle;
  4 +import android.support.annotation.NonNull;
  5 +
  6 +/**
  7 + * Created by Horrarndoo on 2017/9/6.
  8 + * <p>
  9 + * BaseActivity接口
  10 + */
  11 +
  12 +public interface IBaseActivity extends IBaseView {
  13 + /**
  14 + * 跳往新的Activity
  15 + *
  16 + * @param clz 要跳往的Activity
  17 + */
  18 + void startNewActivity(@NonNull Class<?> clz);
  19 +
  20 + /**
  21 + * 跳往新的Activity
  22 + *
  23 + * @param clz 要跳往的Activity
  24 + * @param bundle 携带的bundle数据
  25 + */
  26 + void startNewActivity(@NonNull Class<?> clz, Bundle bundle);
  27 +
  28 + /**
  29 + * 跳往新的Activity
  30 + * @param clz 要跳转的Activity
  31 + * @param bundle bundel数据
  32 + * @param requestCode requestCode
  33 + */
  34 + void startNewActivityForResult(@NonNull Class<?> clz, Bundle bundle, int requestCode);
  35 +}
mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseFragment.java 0 → 100644
@@ -0,0 +1,92 @@ @@ -0,0 +1,92 @@
  1 +package com.share.mvpsdk.base;
  2 +
  3 +import android.app.Activity;
  4 +import android.os.Bundle;
  5 +import android.support.annotation.NonNull;
  6 +
  7 +import me.yokeyword.fragmentation.SupportFragment;
  8 +
  9 +/**
  10 + * Created by Horrarndoo on 2017/9/6.
  11 + * <p>
  12 + * BaseFragment接口
  13 + */
  14 +
  15 +public interface IBaseFragment extends IBaseView {
  16 + /**
  17 + * 出栈到目标fragment
  18 + *
  19 + * @param targetFragmentClass 目标fragment
  20 + * @param includeTargetFragment 是否包含该fragment
  21 + * true 目标fragment也出栈
  22 + * <p>
  23 + * false 出栈到目标fragment,目标fragment不出栈
  24 + */
  25 + void popToFragment(Class<?> targetFragmentClass, boolean includeTargetFragment);
  26 +
  27 + /**
  28 + * 跳往新的Fragment
  29 + *
  30 + * @param supportFragment 要跳往的Fragment(继承自supportFragment)
  31 + */
  32 + void startNewFragment(@NonNull SupportFragment supportFragment);
  33 +
  34 + /**
  35 + * 跳往新的Fragment,并出栈当前fragment
  36 + *
  37 + * @param supportFragment 要跳往的Fragment(继承自supportFragment)
  38 + */
  39 + void startNewFragmentWithPop(@NonNull SupportFragment supportFragment);
  40 +
  41 + /**
  42 + * 跳往新的Fragment
  43 + *
  44 + * @param supportFragment 要跳往的Fragment(继承自supportFragment)
  45 + * @param requestCode requestCode
  46 + */
  47 + void startNewFragmentForResult(@NonNull SupportFragment supportFragment, int requestCode);
  48 +
  49 + /**
  50 + * 设置Fragment返回Result
  51 + *
  52 + * @param resultCode resultCode
  53 + * @param data result data
  54 + */
  55 + void setOnFragmentResult(int resultCode, Bundle data);
  56 +
  57 + /**
  58 + * 跳往新的Activity
  59 + *
  60 + * @param clz 要跳往的Activity
  61 + */
  62 + void startNewActivity(@NonNull Class<?> clz);
  63 +
  64 + /**
  65 + * 跳往新的Activity
  66 + *
  67 + * @param clz 要跳往的Activity
  68 + * @param bundle 携带的bundle数据
  69 + */
  70 + void startNewActivity(@NonNull Class<?> clz, Bundle bundle);
  71 +
  72 + /**
  73 + * 跳往新的Activity
  74 + *
  75 + * @param clz 要跳转的Activity
  76 + * @param bundle bundel数据
  77 + * @param requestCode requestCode
  78 + */
  79 + void startNewActivityForResult(@NonNull Class<?> clz, Bundle bundle, int requestCode);
  80 +
  81 + /**
  82 + * 返回当前fragment是否可见
  83 + * @return 当前fragment是否可见
  84 + */
  85 + boolean isVisiable();
  86 +
  87 + /**
  88 + * 返回当前fragment绑定的activity
  89 + * @return activity
  90 + */
  91 + Activity getBindActivity();
  92 +}
mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseModel.java 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +package com.share.mvpsdk.base;
  2 +
  3 +/**
  4 + * Created by Horrarndoo on 2017/4/25.
  5 + * base model接口
  6 + */
  7 +
  8 +public interface IBaseModel {
  9 +}
mvpsdk/src/main/java/com/share/mvpsdk/base/IBaseView.java 0 → 100644
@@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
  1 +package com.share.mvpsdk.base;
  2 +
  3 +import android.support.annotation.NonNull;
  4 +
  5 +/**
  6 + * Created by Horrarndoo on 2017/5/2.
  7 + * fragment base view接口
  8 + */
  9 +
  10 +public interface IBaseView {
  11 + /**
  12 + * 初始化presenter
  13 + * <p>
  14 + * 此方法返回的presenter对象不可为空
  15 + */
  16 + @NonNull
  17 + BasePresenter initPresenter();
  18 +
  19 + /**
  20 + * 显示toast消息
  21 + *
  22 + * @param msg 要显示的toast消息字符串
  23 + */
  24 + void showToast(String msg);
  25 +
  26 + /**
  27 + * 显示等待dialog
  28 + *
  29 + * @param waitMsg 等待消息字符串
  30 + */
  31 + void showWaitDialog(String waitMsg);
  32 +
  33 + /**
  34 + * 隐藏等待dialog
  35 + */
  36 + void hideWaitDialog();
  37 +
  38 + /**
  39 + * 隐藏键盘
  40 + */
  41 + void hideKeybord();
  42 +
  43 + /**
  44 + * 回退
  45 + */
  46 + void back();
  47 +}
mvpsdk/src/main/java/com/share/mvpsdk/base/activity/BaseCompatActivity.java 0 → 100644
@@ -0,0 +1,250 @@ @@ -0,0 +1,250 @@
  1 +package com.share.mvpsdk.base.activity;
  2 +
  3 +import android.content.Context;
  4 +import android.content.Intent;
  5 +import android.content.pm.ActivityInfo;
  6 +import android.os.Bundle;
  7 +import android.support.v7.app.AppCompatDelegate;
  8 +import android.support.v7.widget.Toolbar;
  9 +import android.view.View;
  10 +import android.view.inputmethod.InputMethodManager;
  11 +
  12 +
  13 +import com.share.mvpsdk.AppManager;
  14 +import com.share.mvpsdk.R;
  15 +import com.share.mvpsdk.global.GlobalApplication;
  16 +import com.share.mvpsdk.utils.AppUtils;
  17 +import com.share.mvpsdk.utils.SpUtils;
  18 +import com.share.mvpsdk.utils.StatusBarUtils;
  19 +import com.share.mvpsdk.utils.ThemeUtils;
  20 +import com.share.mvpsdk.widgets.WaitPorgressDialog;
  21 +
  22 +import butterknife.ButterKnife;
  23 +import me.yokeyword.fragmentation.SupportActivity;
  24 +import me.yokeyword.fragmentation.anim.DefaultVerticalAnimator;
  25 +import me.yokeyword.fragmentation.anim.FragmentAnimator;
  26 +
  27 +/**
  28 + * Created by Horrarndoo on 2017/9/7.
  29 + * <p>
  30 + * BaseActivity
  31 + */
  32 +
  33 +public abstract class BaseCompatActivity extends SupportActivity {
  34 + protected GlobalApplication mApplication;
  35 + protected WaitPorgressDialog mWaitPorgressDialog;
  36 + protected Context mContext;//全局上下文对象
  37 + protected boolean isTransAnim;
  38 +
  39 + static {
  40 + //5.0以下兼容vector
  41 + AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
  42 + }
  43 +
  44 + @Override
  45 + protected void onCreate(Bundle savedInstanceState) {
  46 + super.onCreate(savedInstanceState);
  47 + init(savedInstanceState);
  48 + }
  49 +
  50 + @Override
  51 + protected void onDestroy() {
  52 + super.onDestroy();
  53 + AppManager.getAppManager().finishActivity(this);
  54 + }
  55 +
  56 + @Override
  57 + public FragmentAnimator onCreateFragmentAnimator() {
  58 + //fragment切换使用默认Vertical动画
  59 + return new DefaultVerticalAnimator();
  60 + }
  61 +
  62 + private void init(Bundle savedInstanceState) {
  63 + setTheme(ThemeUtils.themeArr[SpUtils.getThemeIndex(this)][
  64 + SpUtils.getNightModel(this) ? 1 : 0]);
  65 + setContentView(getLayoutId());
  66 + ButterKnife.bind(this);
  67 +// StatusBarUtils.setTransparent(this);
  68 + StatusBarUtils.setBarColor(this,getResources().getColor(R.color.titleColor));
  69 + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
  70 + initData();
  71 + initView(savedInstanceState);
  72 + AppManager.getAppManager().addActivity(this);
  73 + }
  74 +
  75 + public void reload() {
  76 + Intent intent = getIntent();
  77 + overridePendingTransition(0, 0);
  78 + intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
  79 + finish();
  80 + overridePendingTransition(0, 0);
  81 + startActivity(intent);
  82 + }
  83 +
  84 + /**
  85 + * 初始化数据
  86 + * <p>
  87 + * 子类可以复写此方法初始化子类数据
  88 + */
  89 + protected void initData() {
  90 + mContext = AppUtils.getContext();
  91 + mApplication = GlobalApplication.getInstance();
  92 + mWaitPorgressDialog = new WaitPorgressDialog(this);
  93 + isTransAnim = true;
  94 + }
  95 +
  96 + /**
  97 + * 初始化view
  98 + * <p>
  99 + * 子类实现 控件绑定、视图初始化等内容
  100 + *
  101 + * @param savedInstanceState savedInstanceState
  102 + */
  103 + protected abstract void initView(Bundle savedInstanceState);
  104 +
  105 + /**
  106 + * 获取当前layouty的布局ID,用于设置当前布局
  107 + * <p>
  108 + * 交由子类实现
  109 + *
  110 + * @return layout Id
  111 + */
  112 + protected abstract int getLayoutId();
  113 +
  114 + /**
  115 + * 显示提示框
  116 + *
  117 + * @param msg 提示框内容字符串
  118 + */
  119 + protected void showProgressDialog(String msg) {
  120 + mWaitPorgressDialog.setMessage(msg);
  121 + mWaitPorgressDialog.show();
  122 + }
  123 +
  124 + /**
  125 + * 隐藏提示框
  126 + */
  127 + protected void hideProgressDialog() {
  128 + if (mWaitPorgressDialog != null) {
  129 + mWaitPorgressDialog.dismiss();
  130 + }
  131 + }
  132 +
  133 + /**
  134 + * [页面跳转]
  135 + *
  136 + * @param clz 要跳转的Activity
  137 + */
  138 + public void startActivity(Class<?> clz) {
  139 + startActivity(new Intent(this, clz));
  140 + if (isTransAnim)
  141 + overridePendingTransition(R.anim.activity_start_zoom_in, R.anim
  142 + .activity_start_zoom_out);
  143 + }
  144 +
  145 + /**
  146 + * [页面跳转]
  147 + *
  148 + * @param clz 要跳转的Activity
  149 + * @param intent intent
  150 + */
  151 + public void startActivity(Class<?> clz, Intent intent) {
  152 + intent.setClass(this, clz);
  153 + startActivity(intent);
  154 + if (isTransAnim)
  155 + overridePendingTransition(R.anim.activity_start_zoom_in, R.anim
  156 + .activity_start_zoom_out);
  157 + }
  158 +
  159 + /**
  160 + * [携带数据的页面跳转]
  161 + *
  162 + * @param clz 要跳转的Activity
  163 + * @param bundle bundel数据
  164 + */
  165 + public void startActivity(Class<?> clz, Bundle bundle) {
  166 + Intent intent = new Intent();
  167 + intent.setClass(this, clz);
  168 + if (bundle != null) {
  169 + intent.putExtras(bundle);
  170 + }
  171 + startActivity(intent);
  172 + if (isTransAnim)
  173 + overridePendingTransition(R.anim.activity_start_zoom_in, R.anim
  174 + .activity_start_zoom_out);
  175 + }
  176 +
  177 + /**
  178 + * [含有Bundle通过Class打开编辑界面]
  179 + *
  180 + * @param clz 要跳转的Activity
  181 + * @param bundle bundel数据
  182 + * @param requestCode requestCode
  183 + */
  184 + public void startActivityForResult(Class<?> clz, Bundle bundle,
  185 + int requestCode) {
  186 + Intent intent = new Intent();
  187 + intent.setClass(this, clz);
  188 + if (bundle != null) {
  189 + intent.putExtras(bundle);
  190 + }
  191 + startActivityForResult(intent, requestCode);
  192 + if (isTransAnim)
  193 + overridePendingTransition(R.anim.activity_start_zoom_in, R.anim
  194 + .activity_start_zoom_out);
  195 + }
  196 +
  197 + @Override
  198 + public void finish() {
  199 + super.finish();
  200 + if (isTransAnim)
  201 + overridePendingTransition(R.anim.activity_finish_trans_in, R.anim
  202 + .activity_finish_trans_out);
  203 + }
  204 +
  205 + /**
  206 + * 隐藏键盘
  207 + *
  208 + * @return 隐藏键盘结果
  209 + * <p>
  210 + * true:隐藏成功
  211 + * <p>
  212 + * false:隐藏失败
  213 + */
  214 + protected boolean hiddenKeyboard() {
  215 + //点击空白位置 隐藏软键盘
  216 + InputMethodManager mInputMethodManager = (InputMethodManager) getSystemService
  217 + (INPUT_METHOD_SERVICE);
  218 + return mInputMethodManager.hideSoftInputFromWindow(this
  219 + .getCurrentFocus().getWindowToken(), 0);
  220 + }
  221 +
  222 + protected void initTitleBar(Toolbar toolbar, String title) {
  223 + toolbar.setTitle(title);
  224 + setSupportActionBar(toolbar);
  225 + getSupportActionBar().setDisplayHomeAsUpEnabled(true);
  226 + getSupportActionBar().setDisplayShowHomeEnabled(true);
  227 + toolbar.setNavigationIcon(R.mipmap.ic_arrow_back_white);
  228 + toolbar.setNavigationOnClickListener(new View.OnClickListener() {
  229 + @Override
  230 + public void onClick(View view) {
  231 + onBackPressedSupport();
  232 + }
  233 + });
  234 + }
  235 +
  236 + /**
  237 + * 是否使用overridePendingTransition过度动画
  238 + * @return 是否使用overridePendingTransition过度动画,默认使用
  239 + */
  240 + protected boolean isTransAnim() {
  241 + return isTransAnim;
  242 + }
  243 +
  244 + /**
  245 + * 设置是否使用overridePendingTransition过度动画
  246 + */
  247 + protected void setIsTransAnim(boolean b){
  248 + isTransAnim = b;
  249 + }
  250 +}
mvpsdk/src/main/java/com/share/mvpsdk/base/activity/BaseMVPCompatActivity.java 0 → 100644
@@ -0,0 +1,94 @@ @@ -0,0 +1,94 @@
  1 +package com.share.mvpsdk.base.activity;
  2 +
  3 +import android.os.Bundle;
  4 +import android.support.annotation.NonNull;
  5 +
  6 +import com.share.mvpsdk.base.BasePresenter;
  7 +import com.share.mvpsdk.base.IBaseActivity;
  8 +import com.share.mvpsdk.base.IBaseModel;
  9 +import com.share.mvpsdk.utils.ToastUtils;
  10 +
  11 +
  12 +/**
  13 + * Created by Horrarndoo on 2017/4/6.
  14 + * <p>
  15 + * Mvp Activity基类
  16 + */
  17 +public abstract class BaseMVPCompatActivity<P extends BasePresenter, M extends IBaseModel> extends
  18 + BaseCompatActivity implements IBaseActivity {
  19 + /**
  20 + * presenter 具体的presenter由子类确定
  21 + */
  22 + protected P mPresenter;
  23 +
  24 + /**
  25 + * model 具体的model由子类确定
  26 + */
  27 + private M mIMode;
  28 +
  29 + /**
  30 + * 初始化数据
  31 + * <p>
  32 + * 子类可以复写此方法初始化子类数据
  33 + */
  34 + protected void initData() {
  35 + super.initData();
  36 + mPresenter = (P) initPresenter();
  37 + if (mPresenter != null) {
  38 + mIMode = (M) mPresenter.getModel();
  39 + if (mIMode != null) {
  40 + mPresenter.attachMV(mIMode, this);
  41 + }
  42 + //Logger.d("attach M V success.");
  43 + }
  44 + }
  45 +
  46 + @Override
  47 + protected void onDestroy() {
  48 + super.onDestroy();
  49 + if (mPresenter != null) {
  50 + mPresenter.detachMV();
  51 + //Logger.d("detach M V success.");
  52 + }
  53 + }
  54 +
  55 + @Override
  56 + public void showWaitDialog(String msg) {
  57 + showProgressDialog(msg);
  58 + }
  59 +
  60 + @Override
  61 + public void hideWaitDialog() {
  62 + hideProgressDialog();
  63 + }
  64 +
  65 + @Override
  66 + public void showToast(String msg) {
  67 + ToastUtils.showToast(msg);
  68 + }
  69 +
  70 + @Override
  71 + public void startNewActivity(@NonNull Class<?> clz) {
  72 + startActivity(clz);
  73 + }
  74 +
  75 + @Override
  76 + public void startNewActivity(@NonNull Class<?> clz, Bundle bundle) {
  77 + startActivity(clz, bundle);
  78 + }
  79 +
  80 + @Override
  81 + public void startNewActivityForResult(@NonNull Class<?> clz, Bundle bundle, int requestCode) {
  82 + startActivityForResult(clz, bundle, requestCode);
  83 + }
  84 +
  85 + @Override
  86 + public void hideKeybord() {
  87 + hiddenKeyboard();
  88 + }
  89 +
  90 + @Override
  91 + public void back() {
  92 + super.onBackPressedSupport();
  93 + }
  94 +}
mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/BaseRecyclerViewAdapter.java 0 → 100644
@@ -0,0 +1,79 @@ @@ -0,0 +1,79 @@
  1 +package com.share.mvpsdk.base.adapter;
  2 +
  3 +import android.support.v7.widget.RecyclerView;
  4 +import android.view.ViewGroup;
  5 +
  6 +
  7 +import java.util.ArrayList;
  8 +import java.util.List;
  9 +
  10 +/**
  11 + * Created by ToaHanDong on 2017/3/23.
  12 + */
  13 +
  14 +public abstract class BaseRecyclerViewAdapter<T> extends RecyclerView.Adapter<BaseRecyclerViewHolder> {
  15 +
  16 + private List<T> data = new ArrayList<>();
  17 + public OnItemClickListener onItemClickListener;
  18 + public OnItemLongClickListener onItemLongClickListener;
  19 +
  20 + @Override
  21 + public BaseRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
  22 + return null;
  23 + }
  24 +
  25 + @Override
  26 + public void onBindViewHolder(BaseRecyclerViewHolder holder, int position) {
  27 + holder.onBindViewHolder(data.get(getPosition(position)), getPosition(position));
  28 + }
  29 +
  30 +
  31 + @Override
  32 + public int getItemCount() {
  33 + return data.size();
  34 + }
  35 +
  36 + public void addAll(List<T> data) {
  37 + removeAll();
  38 + if (data!=null)
  39 + this.data.addAll(data);
  40 + notifyDataSetChanged();
  41 + }
  42 +
  43 + public void removeAll() {
  44 + data.clear();
  45 + }
  46 +
  47 + public void remove(int position) {
  48 + data.remove(position);
  49 + }
  50 +
  51 + public void notift() {
  52 + notifyDataSetChanged();
  53 + }
  54 +
  55 + public void remove(T object) {
  56 + data.remove(object);
  57 + }
  58 +
  59 + public List<T> getData() {
  60 + return data;
  61 + }
  62 +
  63 + public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
  64 + this.onItemClickListener = onItemClickListener;
  65 + }
  66 +
  67 + public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) {
  68 + this.onItemLongClickListener = onItemLongClickListener;
  69 + }
  70 +
  71 + private int getPosition(int position) {
  72 + return position;
  73 +// if (data.size() <= 9) {
  74 +// return position;
  75 +// }
  76 +// return position % (data.size());
  77 + }
  78 +
  79 +}
mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/BaseRecyclerViewHolder.java 0 → 100644
@@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
  1 +package com.share.mvpsdk.base.adapter;
  2 +
  3 +import android.support.v7.widget.RecyclerView;
  4 +import android.view.View;
  5 +
  6 +/**
  7 + * Created by ToaHanDong on 2017/3/23.
  8 + */
  9 +
  10 +public abstract class BaseRecyclerViewHolder<T> extends RecyclerView.ViewHolder {
  11 +
  12 + public BaseRecyclerViewHolder(View itemView) {
  13 + super(itemView);
  14 + }
  15 +
  16 + public abstract void onBindViewHolder(T object, final int position);
  17 +
  18 + void OnBaseBindViewHolder(T Object,int position){
  19 + onBindViewHolder(Object,position);
  20 + }
  21 +
  22 +}
mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/OnItemClickListener.java 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +package com.share.mvpsdk.base.adapter;
  2 +
  3 +/**
  4 + * Created by ToaHanDong on 2017/3/23.
  5 + */
  6 +
  7 +public interface OnItemClickListener<T> {
  8 +
  9 + void onItemClickListener(T object, int position);
  10 +}
mvpsdk/src/main/java/com/share/mvpsdk/base/adapter/OnItemLongClickListener.java 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +package com.share.mvpsdk.base.adapter;
  2 +
  3 +/**
  4 + * Created by ToaHanDong on 2017/3/23.
  5 + */
  6 +
  7 +public interface OnItemLongClickListener<T> {
  8 +
  9 + void onItemLongClickListener(T object, int position);
  10 +}
mvpsdk/src/main/java/com/share/mvpsdk/base/entity/BaseEntity.java 0 → 100644
@@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
  1 +package com.share.mvpsdk.base.entity;
  2 +
  3 +import java.io.Serializable;
  4 +
  5 +/**
  6 + * Created by ToaHanDong on 2017/4/27.
  7 + */
  8 +
  9 +public class BaseEntity<T> implements Serializable {
  10 +
  11 + private int status;
  12 + private String message;
  13 + private T data;
  14 +
  15 + public int getStatus() {
  16 + return status;
  17 + }
  18 +
  19 + public void setStatus(int status) {
  20 + this.status = status;
  21 + }
  22 +
  23 + public String getMessage() {
  24 + return message;
  25 + }
  26 +
  27 + public void setMessage(String message) {
  28 + this.message = message;
  29 + }
  30 +
  31 + public T getData() {
  32 + return data;
  33 + }
  34 +
  35 + public void setData(T data) {
  36 + this.data = data;
  37 + }
  38 +
  39 + @Override
  40 + public String toString() {
  41 + return "BaseEntity{" +
  42 + "status=" + status +
  43 + ", message='" + message + '\'' +
  44 + ", data=" + data +
  45 + '}';
  46 + }
  47 +}
mvpsdk/src/main/java/com/share/mvpsdk/base/entity/BaseListEntity.java 0 → 100644
@@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
  1 +package com.share.mvpsdk.base.entity;
  2 +
  3 +import java.io.Serializable;
  4 +import java.util.List;
  5 +
  6 +/**
  7 + * Created by ToaHanDong on 2017/6/6.
  8 + */
  9 +
  10 +public class BaseListEntity<T> implements Serializable {
  11 +
  12 + private int status;
  13 + private String message;
  14 + private List<T> data;
  15 +
  16 + public int getStatus() {
  17 + return status;
  18 + }
  19 +
  20 + public void setStatus(int status) {
  21 + this.status = status;
  22 + }
  23 +
  24 + public String getMessage() {
  25 + return message;
  26 + }
  27 +
  28 + public void setMessage(String message) {
  29 + this.message = message;
  30 + }
  31 +
  32 + public List<T> getData() {
  33 + return data;
  34 + }
  35 +
  36 + public void setData(List<T> data) {
  37 + this.data = data;
  38 + }
  39 +
  40 + @Override
  41 + public String toString() {
  42 + return "BaseListEntity{" +
  43 + "status=" + status +
  44 + ", message='" + message + '\'' +
  45 + ", data=" + data +
  46 + '}';
  47 + }
  48 +}
mvpsdk/src/main/java/com/share/mvpsdk/base/fragment/BaseCompatFragment.java 0 → 100644
@@ -0,0 +1,153 @@ @@ -0,0 +1,153 @@
  1 +package com.share.mvpsdk.base.fragment;
  2 +
  3 +import android.app.Activity;
  4 +import android.content.Context;
  5 +import android.content.pm.ActivityInfo;
  6 +import android.os.Bundle;
  7 +import android.support.annotation.LayoutRes;
  8 +import android.support.annotation.Nullable;
  9 +import android.util.Log;
  10 +import android.view.LayoutInflater;
  11 +import android.view.View;
  12 +import android.view.ViewGroup;
  13 +
  14 +
  15 +import com.share.mvpsdk.global.GlobalApplication;
  16 +import com.share.mvpsdk.utils.AppUtils;
  17 +import com.share.mvpsdk.widgets.WaitPorgressDialog;
  18 +
  19 +import butterknife.ButterKnife;
  20 +import butterknife.Unbinder;
  21 +import me.yokeyword.fragmentation.SupportFragment;
  22 +import timber.log.Timber;
  23 +
  24 +/**
  25 + * Created by Horrarndoo on 2017/9/26.
  26 + * <p>
  27 + */
  28 +
  29 +public abstract class BaseCompatFragment extends SupportFragment {
  30 +
  31 + protected String TAG;
  32 + protected Context mContext;
  33 + protected Activity mActivity;
  34 + protected GlobalApplication mApplication;
  35 + protected WaitPorgressDialog mWaitPorgressDialog;
  36 +// private Unbinder binder;
  37 +
  38 + @Override
  39 + public void onAttach(Context context) {
  40 + mActivity = (Activity) context;
  41 + mContext = context;
  42 + super.onAttach(context);
  43 + }
  44 +
  45 + @Override
  46 + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable
  47 + Bundle savedInstanceState) {
  48 + if (getLayoutView() != null) {
  49 + return getLayoutView();
  50 + } else {
  51 + // return inflater.inflate(getLayoutId(), null);
  52 + return inflater.inflate(getLayoutId(), container, false);
  53 + }
  54 + }
  55 +
  56 + @Override
  57 + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
  58 + ButterKnife.bind(this, view);
  59 + super.onViewCreated(view, savedInstanceState);
  60 + mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
  61 + TAG = getClass().getSimpleName();
  62 + getBundle(getArguments());
  63 + initData();
  64 + initUI(view, savedInstanceState);
  65 + }
  66 +
  67 +
  68 + @Override
  69 + public void onDestroyView() {
  70 + super.onDestroyView();
  71 +// if (binder != null)
  72 +// binder.unbind();
  73 + }
  74 +
  75 + @Override
  76 + public void onDetach() {
  77 + super.onDetach();
  78 + }
  79 +
  80 + @Override
  81 + public void onDestroy() {
  82 + super.onDestroy();
  83 + }
  84 +
  85 + @LayoutRes
  86 + public abstract int getLayoutId();
  87 +
  88 + public View getLayoutView() {
  89 + return null;
  90 + }
  91 +
  92 + /**
  93 + * 得到Activity传进来的值
  94 + */
  95 + public void getBundle(Bundle bundle) {
  96 + }
  97 +
  98 + /**
  99 + * 初始化UI
  100 + */
  101 + public abstract void initUI(View view, @Nullable Bundle savedInstanceState);
  102 +
  103 + /**
  104 + * 在监听器之前把数据准备好
  105 + */
  106 + public void initData() {
  107 + mWaitPorgressDialog = new WaitPorgressDialog(mActivity);
  108 + mContext = AppUtils.getContext();
  109 + mApplication = GlobalApplication.getInstance();
  110 + }
  111 +
  112 + /**
  113 + * 处理回退事件
  114 + *
  115 + * @return true 事件已消费
  116 + * <p>
  117 + * false 事件向上传递
  118 + */
  119 + @Override
  120 + public boolean onBackPressedSupport() {
  121 + if (getFragmentManager().getBackStackEntryCount() > 1) {
  122 + //如果当前存在fragment>1,当前fragment出栈
  123 + pop();
  124 + } else {
  125 + //已经退栈到root fragment,交由Activity处理回退事件
  126 + return false;
  127 + }
  128 + return true;
  129 + }
  130 +
  131 + /**
  132 + * 显示提示框
  133 + *
  134 + * @param msg 提示框内容字符串
  135 + */
  136 + protected void showProgressDialog(String msg) {
  137 + if (mWaitPorgressDialog.isShowing()) {
  138 + mWaitPorgressDialog.dismiss();
  139 + }
  140 +
  141 + mWaitPorgressDialog.setMessage(msg);
  142 + mWaitPorgressDialog.show();
  143 + }
  144 +
  145 + /**
  146 + * 隐藏提示框
  147 + */
  148 + protected void hideProgressDialog() {
  149 + if (mWaitPorgressDialog != null) {
  150 + mWaitPorgressDialog.dismiss();
  151 + }
  152 + }
  153 +}
mvpsdk/src/main/java/com/share/mvpsdk/base/fragment/BaseMVPCompatFragment.java 0 → 100644
@@ -0,0 +1,128 @@ @@ -0,0 +1,128 @@
  1 +package com.share.mvpsdk.base.fragment;
  2 +
  3 +import android.app.Activity;
  4 +import android.os.Bundle;
  5 +import android.support.annotation.NonNull;
  6 +import android.widget.Toast;
  7 +
  8 +
  9 +import com.share.mvpsdk.base.BasePresenter;
  10 +import com.share.mvpsdk.base.IBaseFragment;
  11 +import com.share.mvpsdk.base.IBaseModel;
  12 +import com.share.mvpsdk.base.activity.BaseCompatActivity;
  13 +import com.share.mvpsdk.utils.ToastUtils;
  14 +
  15 +import me.yokeyword.fragmentation.SupportFragment;
  16 +
  17 +/**
  18 + * Created by Horrarndoo on 2017/9/6.
  19 + * <p>
  20 + * Mvp Fragment基类
  21 + * <p>
  22 + * 实现IBaseView方法、绑定butterknife
  23 + */
  24 +
  25 +public abstract class BaseMVPCompatFragment<P extends BasePresenter, M extends IBaseModel> extends
  26 + BaseCompatFragment implements IBaseFragment {
  27 + public P mPresenter;
  28 + public M mIMode;
  29 +
  30 + /**
  31 + * 在监听器之前把数据准备好
  32 + */
  33 + public void initData() {
  34 + super.initData();
  35 +
  36 + mPresenter = (P) initPresenter();
  37 + if (mPresenter != null) {
  38 + mIMode = (M) mPresenter.getModel();
  39 + if (mIMode != null) {
  40 + mPresenter.attachMV(mIMode, this);
  41 + }
  42 + }
  43 + }
  44 +
  45 + @Override
  46 + public void onDestroy() {
  47 + super.onDestroy();
  48 + if (mPresenter != null) {
  49 + mPresenter.detachMV();
  50 + }
  51 + }
  52 +
  53 + @Override
  54 + public void showWaitDialog(String msg) {
  55 + showProgressDialog(msg);
  56 + }
  57 +
  58 + @Override
  59 + public void hideWaitDialog() {
  60 + hideProgressDialog();
  61 + }
  62 +
  63 + @Override
  64 + public void showToast(String msg) {
  65 + ToastUtils.showToast(mContext, msg, Toast.LENGTH_SHORT);
  66 + }
  67 +
  68 + @Override
  69 + public void back() {
  70 + this.onBackPressedSupport();
  71 + }
  72 +
  73 + @Override
  74 + public void startNewFragment(@NonNull SupportFragment supportFragment) {
  75 + start(supportFragment);
  76 + }
  77 +
  78 + @Override
  79 + public void startNewFragmentWithPop(@NonNull SupportFragment supportFragment) {
  80 + startWithPop(supportFragment);
  81 + }
  82 +
  83 + @Override
  84 + public void startNewFragmentForResult(@NonNull SupportFragment supportFragment, int
  85 + requestCode) {
  86 + startForResult(supportFragment, requestCode);
  87 + }
  88 +
  89 + @Override
  90 + public void popToFragment(Class<?> targetFragmentClass, boolean includeTargetFragment) {
  91 + popTo(targetFragmentClass, includeTargetFragment);
  92 + }
  93 +
  94 + @Override
  95 + public void hideKeybord() {
  96 + hideSoftInput();
  97 + }
  98 +
  99 + @Override
  100 + public void setOnFragmentResult(int ResultCode, Bundle data) {
  101 + setFragmentResult(ResultCode, data);
  102 + }
  103 +
  104 + @Override
  105 + public void startNewActivity(@NonNull Class<?> clz) {
  106 + ((BaseCompatActivity) mActivity).startActivity(clz);
  107 + }
  108 +
  109 + @Override
  110 + public void startNewActivity(@NonNull Class<?> clz, Bundle bundle) {
  111 + ((BaseCompatActivity) mActivity).startActivity(clz, bundle);
  112 + }
  113 +
  114 + @Override
  115 + public void startNewActivityForResult(@NonNull Class<?> clz, Bundle bundle, int requestCode) {
  116 + ((BaseCompatActivity) mActivity).startActivityForResult(clz, bundle, requestCode);
  117 + }
  118 +
  119 + @Override
  120 + public boolean isVisiable() {
  121 + return isSupportVisible();
  122 + }
  123 +
  124 + @Override
  125 + public Activity getBindActivity() {
  126 + return mActivity;
  127 + }
  128 +}
0 \ No newline at end of file 129 \ No newline at end of file
mvpsdk/src/main/java/com/share/mvpsdk/base/fragment/BaseRecycleFragment.java 0 → 100644
@@ -0,0 +1,68 @@ @@ -0,0 +1,68 @@
  1 +package com.share.mvpsdk.base.fragment;
  2 +
  3 +import android.os.Bundle;
  4 +import android.support.annotation.Nullable;
  5 +import android.view.LayoutInflater;
  6 +import android.view.View;
  7 +import android.view.ViewGroup;
  8 +
  9 +import com.share.mvpsdk.R;
  10 +import com.share.mvpsdk.base.BasePresenter;
  11 +import com.share.mvpsdk.base.IBaseModel;
  12 +
  13 +
  14 +/**
  15 + * Created by Horrarndoo on 2017/10/17.
  16 + * <p>
  17 + * 带RecycleView加载状态view的fragment,主要用于显示加载中、空界面、加载失败等状态界面显示
  18 + */
  19 +
  20 +public abstract class BaseRecycleFragment<P extends BasePresenter, M extends IBaseModel> extends
  21 + BaseMVPCompatFragment<P, M> {
  22 + /**
  23 + * 网络异常View
  24 + */
  25 + protected View errorView;
  26 + /**
  27 + * loadingView
  28 + */
  29 + protected View loadingView;
  30 + /**
  31 + * 没有内容view
  32 + */
  33 + protected View emptyView;
  34 +
  35 + @Override
  36 + public void onLazyInitView(@Nullable Bundle savedInstanceState) {
  37 + super.onLazyInitView(savedInstanceState);
  38 + showLoading();
  39 + }
  40 +
  41 + @Override
  42 + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable
  43 + Bundle savedInstanceState) {
  44 + errorView = inflater.inflate(R.layout.view_network_error, container, false);
  45 + loadingView = inflater.inflate(R.layout.view_loading, container, false);
  46 + emptyView = inflater.inflate(R.layout.view_empty, container, false);
  47 + errorView.setOnClickListener(new View.OnClickListener() {
  48 + @Override
  49 + public void onClick(View v) {
  50 + showLoading();
  51 + onErrorViewClick(v);
  52 + }
  53 + });
  54 + return super.onCreateView(inflater, container, savedInstanceState);
  55 + }
  56 +
  57 + /**
  58 + * 网络异常view被点击时触发,由子类实现
  59 + *
  60 + * @param view view
  61 + */
  62 + protected abstract void onErrorViewClick(View view);
  63 +
  64 + /**
  65 + * 显示加载中view,由子类实现
  66 + */
  67 + protected abstract void showLoading();
  68 +}
mvpsdk/src/main/java/com/share/mvpsdk/config/DBConfig.java 0 → 100644
@@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
  1 +package com.share.mvpsdk.config;
  2 +
  3 +/**
  4 + * Created by Horrarndoo on 2017/9/13.
  5 + * <p>
  6 + * 数据库全局常量
  7 + */
  8 +
  9 +public class DBConfig {
  10 + public static final String DB_NAME = "db_name_yizhi";
  11 + public static final String TABLE_ZHIHU = "table_zhihu";
  12 + public static final String TABLE_WANGYI = "table_top_news";
  13 + public static final String TABLE_WEIXIN = "table_weixin";
  14 + public static final String TABLE_GANKIO_DAY = "table_gank_io_day";
  15 + public static final String TABLE_GANKIO_CUSTOM = "table_gank_io_custom";
  16 +}
mvpsdk/src/main/java/com/share/mvpsdk/config/ItemState.java 0 → 100644
@@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
  1 +package com.share.mvpsdk.config;
  2 +
  3 +/**
  4 + * Created by Horrarndoo on 2017/9/13.
  5 + * <p>
  6 + * item状态全局常量
  7 + */
  8 +
  9 +public class ItemState {
  10 + /**
  11 + * 已读状态
  12 + */
  13 + public static final int STATE_IS_READ = 1;
  14 +
  15 + /**
  16 + * 非已读状态
  17 + */
  18 + public static final int STATE_IS_NO_READ = 0;
  19 +}
mvpsdk/src/main/java/com/share/mvpsdk/global/GlobalApplication.java 0 → 100644
@@ -0,0 +1,72 @@ @@ -0,0 +1,72 @@
  1 +package com.share.mvpsdk.global;
  2 +
  3 +import android.app.Application;
  4 +import android.content.Context;
  5 +import android.os.Handler;
  6 +
  7 +import com.orhanobut.logger.LogLevel;
  8 +import com.orhanobut.logger.Logger;
  9 +import com.share.mvpsdk.utils.ToastUtils;
  10 +
  11 +import timber.log.BuildConfig;
  12 +import timber.log.Timber;
  13 +
  14 +
  15 +/**
  16 + * Created by Horrarndoo on 2017/9/1.
  17 + * <p>
  18 + * 全局Application
  19 + */
  20 +
  21 +public class GlobalApplication extends Application {
  22 + private static final String LOG_TAG = "YZ_LOGGER";
  23 + protected static Context context;
  24 + protected static Handler handler;
  25 + protected static int mainThreadId;
  26 + private static GlobalApplication mApp;
  27 +
  28 + public static synchronized GlobalApplication getInstance() {
  29 + return mApp;
  30 + }
  31 +
  32 + @Override
  33 + public void onCreate() {
  34 + super.onCreate();
  35 + context = getApplicationContext();
  36 + handler = new Handler();
  37 + mainThreadId = android.os.Process.myTid();
  38 + mApp=this;
  39 + if (!BuildConfig.DEBUG) {
  40 + Timber.plant(new Timber.DebugTree());
  41 + }
  42 + //LogLevel.FULL : LogLevel.NONE
  43 +// Logger.init(LOG_TAG).logLevel(LogLevel.FULL);
  44 + }
  45 +
  46 + /**
  47 + * 获取上下文对象
  48 + *
  49 + * @return context
  50 + */
  51 + public static Context getContext() {
  52 + return context;
  53 + }
  54 +
  55 + /**
  56 + * 获取全局handler
  57 + *
  58 + * @return 全局handler
  59 + */
  60 + public static Handler getHandler() {
  61 + return handler;
  62 + }
  63 +
  64 + /**
  65 + * 获取主线程id
  66 + *
  67 + * @return 主线程id
  68 + */
  69 + public static int getMainThreadId() {
  70 + return mainThreadId;
  71 + }
  72 +}
mvpsdk/src/main/java/com/share/mvpsdk/helper/BottomNavigationViewHelper.java 0 → 100644
@@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
  1 +package com.share.mvpsdk.helper;
  2 +
  3 +import android.support.design.internal.BottomNavigationItemView;
  4 +import android.support.design.internal.BottomNavigationMenuView;
  5 +import android.support.design.widget.BottomNavigationView;
  6 +import android.util.Log;
  7 +
  8 +import java.lang.reflect.Field;
  9 +
  10 +/**
  11 + * Created by Horrarndoo on 2017/9/22.
  12 + * <p>
  13 + * BottomNavigationView禁止3个item以上动画切换效果
  14 + */
  15 +public class BottomNavigationViewHelper {
  16 + public static void disableShiftMode(BottomNavigationView view) {
  17 + BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
  18 + try {
  19 + Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
  20 + shiftingMode.setAccessible(true);
  21 + shiftingMode.setBoolean(menuView, false);
  22 + shiftingMode.setAccessible(false);
  23 + for (int i = 0; i < menuView.getChildCount(); i++) {
  24 + BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
  25 + //noinspection RestrictedApi
  26 + item.setShiftingMode(false);
  27 + // set once again checked value, so view will be updated
  28 + //noinspection RestrictedApi
  29 + item.setChecked(item.getItemData().isChecked());
  30 + }
  31 + } catch (NoSuchFieldException e) {
  32 + Log.e("BNVHelper", "Unable to get shift mode field", e);
  33 + } catch (IllegalAccessException e) {
  34 + Log.e("BNVHelper", "Unable to change value of shift mode", e);
  35 + }
  36 + }
  37 +}
mvpsdk/src/main/java/com/share/mvpsdk/helper/RetrofitCreateHelper.java 0 → 100644
@@ -0,0 +1,130 @@ @@ -0,0 +1,130 @@
  1 +package com.share.mvpsdk.helper;
  2 +
  3 +
  4 +import com.share.mvpsdk.helper.okhttp.CacheInterceptor;
  5 +import com.share.mvpsdk.utils.StringUtils;
  6 +
  7 +import java.io.IOException;
  8 +import java.util.concurrent.TimeUnit;
  9 +
  10 +import okhttp3.Interceptor;
  11 +import okhttp3.OkHttpClient;
  12 +import okhttp3.Request;
  13 +import okhttp3.Response;
  14 +import okhttp3.logging.HttpLoggingInterceptor;
  15 +import retrofit2.Retrofit;
  16 +import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
  17 +import retrofit2.converter.gson.GsonConverterFactory;
  18 +
  19 +/**
  20 + * Created by Horrarndoo on 2017/9/7.
  21 + * <p>
  22 + */
  23 +
  24 +public class RetrofitCreateHelper {
  25 + private static final int TIMEOUT_READ = 20;
  26 + private static final int TIMEOUT_CONNECTION = 10;
  27 + private static String Authorization = "", token = "";
  28 + private static RetrofitCreateHelper retrofitCreateHelper = null;
  29 + private static final HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor()
  30 + .setLevel(HttpLoggingInterceptor.Level.BODY);
  31 + private static CacheInterceptor cacheInterceptor = new CacheInterceptor();
  32 + private static OkHttpClient.Builder okhttpClientBuilder = null;
  33 +
  34 + /*private static OkHttpClient okHttpClient = new OkHttpClient.Builder()
  35 + //SSL证书
  36 + .sslSocketFactory(TrustManager.getUnsafeOkHttpClient())
  37 + .hostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
  38 + //打印日志
  39 + .addInterceptor(interceptor)
  40 + //设置Cache拦截器
  41 + .addNetworkInterceptor(cacheInterceptor)
  42 + .addInterceptor(cacheInterceptor)
  43 + .cache(HttpCache.getCache())
  44 + //time out
  45 + .connectTimeout(TIMEOUT_CONNECTION, TimeUnit.SECONDS)
  46 + .readTimeout(TIMEOUT_READ, TimeUnit.SECONDS)
  47 + .writeTimeout(TIMEOUT_READ, TimeUnit.SECONDS)
  48 + //失败重连
  49 + .retryOnConnectionFailure(true)
  50 + .build();*/
  51 + public static RetrofitCreateHelper getInstance() {
  52 + if (null == retrofitCreateHelper) {
  53 + synchronized (RetrofitCreateHelper.class) {
  54 + if (null == retrofitCreateHelper) retrofitCreateHelper = new RetrofitCreateHelper();
  55 + }
  56 + }
  57 + return retrofitCreateHelper;
  58 + }
  59 +
  60 + public RetrofitCreateHelper() {
  61 + try {
  62 + if (null == okhttpClientBuilder) {
  63 + okhttpClientBuilder = new OkHttpClient.Builder();
  64 + okhttpClientBuilder.connectTimeout(10000, TimeUnit.SECONDS);
  65 + okhttpClientBuilder.addInterceptor(new Interceptor() {
  66 + @Override
  67 + public Response intercept(Chain chain) throws IOException {
  68 + Request original = chain.request();
  69 + Request.Builder requestBuilder = original.newBuilder().header("Authorization", Authorization);
  70 + Request request = requestBuilder.build();
  71 + return chain.proceed(request);
  72 + }
  73 + });
  74 + okhttpClientBuilder.addNetworkInterceptor(cacheInterceptor);
  75 + okhttpClientBuilder.addInterceptor(interceptor);
  76 + }
  77 + } catch (Exception e) {
  78 + e.printStackTrace();
  79 + }
  80 + }
  81 +
  82 + public <T> T createApi(Class<T> clazz, String url) {
  83 + Authorization = token;
  84 + Retrofit retrofit = new Retrofit.Builder()
  85 + .baseUrl(url)
  86 + .client(okhttpClientBuilder.build())
  87 + .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
  88 + .addConverterFactory(GsonConverterFactory.create())
  89 + .build();
  90 + return retrofit.create(clazz);
  91 + }
  92 +
  93 + // public static <T> T loginApi(Class<T> clazz, String url) {
  94 +// Authorization= StringUtils.getSign();
  95 +// okHttpClient.newBuilder().addInterceptor(new Interceptor() {
  96 +// @Override
  97 +// public Response intercept(Chain chain) throws IOException {
  98 +// Request original = chain.request();
  99 +// Request.Builder requestBuilder = original.newBuilder().header("Authorization", Authorization);
  100 +// Request request = requestBuilder.build();
  101 +// return chain.proceed(request);
  102 +// }
  103 +// });
  104 +// Log.d("77777","Authorization="+Authorization);
  105 +// Retrofit retrofit = new Retrofit.Builder()
  106 +// .baseUrl(url)
  107 +// .client(okHttpClient)
  108 +// .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
  109 +// .addConverterFactory(GsonConverterFactory.create())
  110 +// .build();
  111 +// return retrofit.create(clazz);
  112 +// }
  113 + public void setAuthorization(String Authorization) {
  114 + this.token ="Bearer " + Authorization;
  115 + }
  116 +
  117 + public <T> T login(Class<T> clazz, String url) {
  118 + Authorization = StringUtils.getSign();
  119 + Retrofit retrofit = new Retrofit.Builder()
  120 + .client(okhttpClientBuilder.build())
  121 + .baseUrl(url)
  122 + .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
  123 + .addConverterFactory(GsonConverterFactory.create())
  124 + .build();
  125 + return retrofit.create(clazz);
  126 + }
  127 +
  128 +
  129 +}
  130 +
mvpsdk/src/main/java/com/share/mvpsdk/helper/RxHelper.java 0 → 100644
@@ -0,0 +1,76 @@ @@ -0,0 +1,76 @@
  1 +package com.share.mvpsdk.helper;
  2 +
  3 +
  4 +import io.reactivex.BackpressureStrategy;
  5 +import io.reactivex.Flowable;
  6 +import io.reactivex.FlowableEmitter;
  7 +import io.reactivex.FlowableOnSubscribe;
  8 +import io.reactivex.Observable;
  9 +import io.reactivex.ObservableEmitter;
  10 +import io.reactivex.ObservableOnSubscribe;
  11 +import io.reactivex.ObservableSource;
  12 +import io.reactivex.ObservableTransformer;
  13 +import io.reactivex.android.schedulers.AndroidSchedulers;
  14 +import io.reactivex.schedulers.Schedulers;
  15 +
  16 +/**
  17 + * Created by Horrarndoo on 2017/9/12.
  18 + * <p>
  19 + */
  20 +public class RxHelper {
  21 + /**
  22 + * 统一线程处理
  23 + * <p>
  24 + * 发布事件io线程,接收事件主线程
  25 + */
  26 + public static <T> ObservableTransformer<T, T> rxSchedulerHelper() {//compose处理线程
  27 + return new ObservableTransformer<T, T>() {
  28 +
  29 + @Override
  30 + public ObservableSource<T> apply(Observable<T> upstream) {
  31 + return upstream.subscribeOn(Schedulers.io())
  32 + .observeOn(AndroidSchedulers.mainThread());
  33 + }
  34 + };
  35 + }
  36 +
  37 + /**
  38 + * 生成Flowable
  39 + *
  40 + * @param t
  41 + * @return Flowable
  42 + */
  43 + public static <T> Flowable<T> createFlowable(final T t) {
  44 + return Flowable.create(new FlowableOnSubscribe<T>() {
  45 + @Override
  46 + public void subscribe(FlowableEmitter<T> emitter) throws Exception {
  47 + try {
  48 + emitter.onNext(t);
  49 + emitter.onComplete();
  50 + } catch (Exception e) {
  51 + emitter.onError(e);
  52 + }
  53 + }
  54 + }, BackpressureStrategy.BUFFER);
  55 + }
  56 +
  57 + /**
  58 + * 生成Observable
  59 + *
  60 + * @param t
  61 + * @return Flowable
  62 + */
  63 + public static <T> Observable<T> createObservable(final T t) {
  64 + return Observable.create(new ObservableOnSubscribe<T>() {
  65 + @Override
  66 + public void subscribe(ObservableEmitter<T> emitter) throws Exception {
  67 + try {
  68 + emitter.onNext(t);
  69 + emitter.onComplete();
  70 + } catch (Exception e) {
  71 + emitter.onError(e);
  72 + }
  73 + }
  74 + });
  75 + }
  76 +}
mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/CacheInterceptor.java 0 → 100644
@@ -0,0 +1,84 @@ @@ -0,0 +1,84 @@
  1 +package com.share.mvpsdk.helper.okhttp;
  2 +
  3 +
  4 +
  5 +import com.share.mvpsdk.utils.AppUtils;
  6 +import com.share.mvpsdk.utils.NetworkConnectionUtils;
  7 +
  8 +import java.io.IOException;
  9 +
  10 +import okhttp3.CacheControl;
  11 +import okhttp3.Interceptor;
  12 +import okhttp3.Request;
  13 +import okhttp3.Response;
  14 +
  15 +import static com.share.mvpsdk.utils.HttpUtils.getUserAgent;
  16 +
  17 +
  18 +/**
  19 + * Created by Horrarndoo on 2017/9/12.
  20 + * <p>
  21 + * CacheInterceptor
  22 + */
  23 +public class CacheInterceptor implements Interceptor {
  24 +
  25 + @Override
  26 + public Response intercept(Chain chain) throws IOException {
  27 +
  28 + Request request = chain.request();
  29 + Response response = chain.proceed(request);
  30 + if (NetworkConnectionUtils.isNetworkConnected(AppUtils.getContext())) {
  31 + // 有网络时, 缓存1小时
  32 + int maxAge = 60 * 60;
  33 + request = request.newBuilder()
  34 + .removeHeader("User-Agent")
  35 + .header("User-Agent", getUserAgent())
  36 + .build();
  37 +
  38 +// Response response = chain.proceed(request);
  39 + return response.newBuilder()
  40 + .removeHeader("Pragma")
  41 + .removeHeader("Cache-Control")
  42 + .header("Cache-Control", "public, max-age=" + maxAge)
  43 + .build();
  44 + } else {
  45 + // 无网络时,缓存为4周
  46 + int maxStale = 60 * 60 * 24 * 28;
  47 + request = request.newBuilder()
  48 + .cacheControl(CacheControl.FORCE_CACHE)
  49 + .removeHeader("User-Agent")
  50 + .header("User-Agent", getUserAgent())
  51 + .build();
  52 +
  53 + return response.newBuilder()
  54 + .removeHeader("Pragma")
  55 + .removeHeader("Cache-Control")
  56 + .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
  57 + .build();
  58 + }
  59 + // Request request = chain.request();
  60 + // if (!NetworkConnectionUtils.isConnected(AppUtils.getContext())) {
  61 + // request = request.newBuilder()
  62 + // .cacheControl(CacheControl.FORCE_CACHE)
  63 + // .build();
  64 + // }
  65 + // Response response = chain.proceed(request);
  66 + // if (NetworkConnectionUtils.isConnected(AppUtils.getContext())) {
  67 + // int maxAge = 0;
  68 + // // 有网络时, 不缓存, 最大保存时长为0
  69 + // response.newBuilder()
  70 + // .header("Cache-Control", "public, max-age=" + maxAge)
  71 + // .removeHeader("Pragma")
  72 + // .build();
  73 + // } else {
  74 + // // 无网络时,设置超时为4周
  75 + // int maxStale = 60 * 60 * 24 * 28;
  76 + // response.newBuilder()
  77 + // .header("Cache-Control", "public, only-if-cached, max-stale=" +
  78 + // maxStale)
  79 + // .removeHeader("Pragma")
  80 + // .build();
  81 + // }
  82 + // return response;
  83 + }
  84 +}
mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/HttpCache.java 0 → 100644
@@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
  1 +package com.share.mvpsdk.helper.okhttp;
  2 +
  3 +
  4 +import android.os.Environment;
  5 +
  6 +import com.share.mvpsdk.utils.AppUtils;
  7 +
  8 +import java.io.File;
  9 +
  10 +import okhttp3.Cache;
  11 +
  12 +/**
  13 + * Created by Horrarndoo on 2017/9/12.
  14 + * <p>
  15 + */
  16 +public class HttpCache {
  17 +
  18 + private static final int HTTP_RESPONSE_DISK_CACHE_MAX_SIZE = 50 * 1024 * 1024;
  19 +
  20 + public static Cache getCache() {
  21 + File file=new File(Environment.getExternalStorageDirectory() + File
  22 + .separator + "data/NetCache");
  23 + if (!file.getParentFile().exists())file.getParentFile().mkdirs();
  24 + if (!file.exists())file.mkdirs();
  25 + return new Cache(file,
  26 + HTTP_RESPONSE_DISK_CACHE_MAX_SIZE);
  27 + }
  28 +}
mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/NetInterceptor.java 0 → 100644
@@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
  1 +package com.share.mvpsdk.helper.okhttp;
  2 +
  3 +
  4 +import com.share.mvpsdk.utils.AppUtils;
  5 +import com.share.mvpsdk.utils.NetworkConnectionUtils;
  6 +
  7 +import java.io.IOException;
  8 +
  9 +import okhttp3.Interceptor;
  10 +import okhttp3.Request;
  11 +import okhttp3.Response;
  12 +
  13 +import static com.share.mvpsdk.utils.HttpUtils.getUserAgent;
  14 +
  15 +
  16 +/**
  17 + * Created by Horrarndoo on 2017/9/18.
  18 + * <p>
  19 + * 有网络时的缓存拦截器
  20 + */
  21 +
  22 +public class NetInterceptor implements Interceptor{
  23 + @Override
  24 + public Response intercept(Chain chain) throws IOException {
  25 + // 有网络时, 缓存1分钟, 最大保存时长为60s
  26 + int maxAge = 60;
  27 + Request request = chain.request();
  28 +
  29 + if (NetworkConnectionUtils.isNetworkConnected(AppUtils.getContext())) {
  30 + request = request.newBuilder()
  31 + .removeHeader("User-Agent")
  32 + .header("User-Agent", getUserAgent())
  33 + // .header("User-Agent", "Mozilla/5.0 (Windows NT 6.1;
  34 + // WOW64) AppleWebKit/537.36" +
  35 + // " (KHTML, like Gecko) Chrome/50.0.2661.102
  36 + // Safari/537.36")
  37 + .build();
  38 +
  39 + Response response = chain.proceed(request);
  40 + return response.newBuilder()
  41 + .removeHeader("Pragma")
  42 + .removeHeader("Cache-Control")
  43 + .header("Cache-Control", "public, max-age=" + maxAge)
  44 + .build();
  45 + }
  46 +
  47 + return chain.proceed(request);
  48 + }
  49 +}
mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/NoNetInterceptor.java 0 → 100644
@@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
  1 +package com.share.mvpsdk.helper.okhttp;
  2 +
  3 +
  4 +import com.share.mvpsdk.utils.AppUtils;
  5 +import com.share.mvpsdk.utils.NetworkConnectionUtils;
  6 +
  7 +import java.io.IOException;
  8 +
  9 +import okhttp3.CacheControl;
  10 +import okhttp3.Interceptor;
  11 +import okhttp3.Request;
  12 +import okhttp3.Response;
  13 +
  14 +import static com.share.mvpsdk.utils.HttpUtils.getUserAgent;
  15 +
  16 +/**
  17 + * Created by Horrarndoo on 2017/9/18.
  18 + * <p>
  19 + * 无网络时的缓存拦截器
  20 + */
  21 +
  22 +public class NoNetInterceptor implements Interceptor {
  23 + @Override
  24 + public Response intercept(Chain chain) throws IOException {
  25 + // 无网络时,设置超时为4周
  26 + int maxStale = 60 * 60 * 24 * 28;
  27 + Request request = chain.request();
  28 +
  29 + if (!NetworkConnectionUtils.isNetworkConnected(AppUtils.getContext())) {
  30 + request = request.newBuilder()
  31 + .cacheControl(CacheControl.FORCE_CACHE)
  32 + .removeHeader("User-Agent")
  33 + .header("User-Agent", getUserAgent())
  34 + // .header("User-Agent", "Mozilla/5.0 (Windows NT 6.1;
  35 + // WOW64) AppleWebKit/537.36" +
  36 + // " (KHTML, like Gecko) Chrome/50.0.2661.102
  37 + // Safari/537.36")
  38 + .build();
  39 +
  40 + Response response = chain.proceed(request);
  41 + return response.newBuilder()
  42 + .removeHeader("Pragma")
  43 + .removeHeader("Cache-Control")
  44 + .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
  45 + .build();
  46 + }
  47 +
  48 + return chain.proceed(request);
  49 + }
  50 +}
mvpsdk/src/main/java/com/share/mvpsdk/helper/okhttp/TrustManager.java 0 → 100644
@@ -0,0 +1,54 @@ @@ -0,0 +1,54 @@
  1 +package com.share.mvpsdk.helper.okhttp;
  2 +
  3 +import java.security.cert.CertificateException;
  4 +import java.security.cert.X509Certificate;
  5 +
  6 +import javax.net.ssl.SSLContext;
  7 +import javax.net.ssl.SSLSocketFactory;
  8 +import javax.net.ssl.X509TrustManager;
  9 +
  10 +/**
  11 + * Created by Horrarndoo on 2017/9/12.
  12 + * <p>
  13 + */
  14 +public class TrustManager {
  15 +
  16 + public static SSLSocketFactory getUnsafeOkHttpClient() {
  17 + try {
  18 + // Create a trust manager that does not validate certificate chains
  19 + final X509TrustManager[] trustAllCerts = new X509TrustManager[]{new X509TrustManager() {
  20 + @Override
  21 + public void checkClientTrusted(
  22 + X509Certificate[] chain,
  23 + String authType) throws CertificateException {
  24 + }
  25 +
  26 + @Override
  27 + public void checkServerTrusted(
  28 + X509Certificate[] chain,
  29 + String authType) throws CertificateException {
  30 + }
  31 +
  32 + @Override
  33 + public X509Certificate[] getAcceptedIssuers() {
  34 + return new X509Certificate[0];
  35 + }
  36 + }};
  37 +
  38 + // Install the all-trusting trust manager
  39 + final SSLContext sslContext = SSLContext.getInstance("TLS");
  40 + sslContext.init(null, trustAllCerts,
  41 + new java.security.SecureRandom());
  42 + // Create an ssl socket factory with our all-trusting manager
  43 + final SSLSocketFactory sslSocketFactory = sslContext
  44 + .getSocketFactory();
  45 +
  46 +
  47 + return sslSocketFactory;
  48 + } catch (Exception e) {
  49 + throw new RuntimeException(e);
  50 + }
  51 +
  52 + }
  53 +}
  54 +
mvpsdk/src/main/java/com/share/mvpsdk/rxbus/BusData.java 0 → 100644
@@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
  1 +package com.share.mvpsdk.rxbus;
  2 +
  3 +/**
  4 + * RxBus data
  5 + * Created by gorden on 2016/7/8.
  6 + */
  7 +public class BusData {
  8 + String id;
  9 + String status;
  10 +
  11 + public BusData() {
  12 + }
  13 +
  14 + public BusData(String id, String status) {
  15 + this.id = id;
  16 + this.status = status;
  17 + }
  18 +
  19 + public String getId() {
  20 + return id;
  21 + }
  22 +
  23 + public void setId(String id) {
  24 + this.id = id;
  25 + }
  26 +
  27 + public String getStatus() {
  28 + return status;
  29 + }
  30 +
  31 + public void setStatus(String status) {
  32 + this.status = status;
  33 + }
  34 +}
0 \ No newline at end of file 35 \ No newline at end of file
mvpsdk/src/main/java/com/share/mvpsdk/rxbus/RxBus.java 0 → 100644
@@ -0,0 +1,355 @@ @@ -0,0 +1,355 @@
  1 +package com.share.mvpsdk.rxbus;
  2 +
  3 +import java.lang.reflect.Method;
  4 +import java.util.ArrayList;
  5 +import java.util.HashMap;
  6 +import java.util.Iterator;
  7 +import java.util.List;
  8 +import java.util.Map;
  9 +
  10 +import io.reactivex.BackpressureStrategy;
  11 +import io.reactivex.Flowable;
  12 +import io.reactivex.Scheduler;
  13 +import io.reactivex.android.schedulers.AndroidSchedulers;
  14 +import io.reactivex.disposables.Disposable;
  15 +import io.reactivex.functions.Consumer;
  16 +import io.reactivex.functions.Function;
  17 +import io.reactivex.functions.Predicate;
  18 +import io.reactivex.schedulers.Schedulers;
  19 +import io.reactivex.subjects.PublishSubject;
  20 +import io.reactivex.subjects.Subject;
  21 +
  22 +/**
  23 + * RxBus
  24 + * Created by gorden on 2016/5/12.
  25 + * update 2017/3/1
  26 + */
  27 +@SuppressWarnings("unused")
  28 +public class RxBus {
  29 + public static final String LOG_BUS = "RXBUS_LOG";
  30 + private static volatile RxBus defaultInstance;
  31 +
  32 + private Map<Class, List<Disposable>> subscriptionsByEventType = new HashMap<>();
  33 +
  34 + private Map<Object, List<Class>> eventTypesBySubscriber = new HashMap<>();
  35 +
  36 + private Map<Class, List<SubscriberMethod>> subscriberMethodByEventType = new HashMap<>();
  37 +
  38 + private final Subject<Object> bus;
  39 +
  40 + private RxBus() {
  41 + this.bus = PublishSubject.create().toSerialized();
  42 + }
  43 +
  44 + public static RxBus get() {
  45 + RxBus rxBus = defaultInstance;
  46 + if (defaultInstance == null) {
  47 + synchronized (RxBus.class) {
  48 + rxBus = defaultInstance;
  49 + if (defaultInstance == null) {
  50 + rxBus = new RxBus();
  51 + defaultInstance = rxBus;
  52 + }
  53 + }
  54 + }
  55 + return rxBus;
  56 + }
  57 +
  58 + /**
  59 + * 根据传递的 eventType 类型返回特定类型(eventType)的 被观察者
  60 + *
  61 + * @param eventType 事件类型
  62 + * @return return
  63 + */
  64 + private <T> Flowable<T> toObservable(Class<T> eventType) {
  65 + return bus.toFlowable(BackpressureStrategy.BUFFER).ofType(eventType);
  66 + }
  67 +
  68 + /**
  69 + * 根据传递的code和 eventType 类型返回特定类型(eventType)的 被观察者
  70 + *
  71 + * @param code 事件code
  72 + * @param eventType 事件类型
  73 + */
  74 + private <T> Flowable<T> toObservable(final int code, final Class<T> eventType) {
  75 + return bus.toFlowable(BackpressureStrategy.BUFFER).ofType(Message.class)
  76 + .filter(new Predicate<Message>() {
  77 + @Override
  78 + public boolean test(Message o) throws Exception {
  79 + return o.getCode() == code && eventType.isInstance(o.getObject());
  80 + }
  81 + }).map(new Function<Message, Object>() {
  82 + @Override
  83 + public Object apply(Message o) throws Exception {
  84 + return o.getObject();
  85 + }
  86 + }).cast(eventType);
  87 + }
  88 +
  89 + /**
  90 + * 注册
  91 + *
  92 + * @param subscriber 订阅者
  93 + */
  94 + public void register(Object subscriber) {
  95 + Class<?> subClass = subscriber.getClass();
  96 + Method[] methods = subClass.getDeclaredMethods();
  97 + for (Method method : methods) {
  98 + if (method.isAnnotationPresent(Subscribe.class)) {
  99 + //获得参数类型
  100 + Class[] parameterType = method.getParameterTypes();
  101 + //参数不为空 且参数个数为1
  102 + if (parameterType != null && parameterType.length == 1) {
  103 +
  104 + Class eventType = parameterType[0];
  105 +
  106 + addEventTypeToMap(subscriber, eventType);
  107 + Subscribe sub = method.getAnnotation(Subscribe.class);
  108 + int code = sub.code();
  109 + ThreadMode threadMode = sub.threadMode();
  110 +
  111 + SubscriberMethod subscriberMethod = new SubscriberMethod(subscriber, method, eventType, code, threadMode);
  112 + addSubscriberToMap(eventType, subscriberMethod);
  113 +
  114 + addSubscriber(subscriberMethod);
  115 + } else if (parameterType == null || parameterType.length == 0) {
  116 +
  117 + Class eventType = BusData.class;
  118 +
  119 + addEventTypeToMap(subscriber, eventType);
  120 + Subscribe sub = method.getAnnotation(Subscribe.class);
  121 + int code = sub.code();
  122 + ThreadMode threadMode = sub.threadMode();
  123 +
  124 + SubscriberMethod subscriberMethod = new SubscriberMethod(subscriber, method, eventType, code, threadMode);
  125 + addSubscriberToMap(eventType, subscriberMethod);
  126 +
  127 + addSubscriber(subscriberMethod);
  128 +
  129 + }
  130 + }
  131 + }
  132 + }
  133 +
  134 +
  135 + /**
  136 + * 将event的类型以订阅中subscriber为key保存到map里
  137 + *
  138 + * @param subscriber 订阅者
  139 + * @param eventType event类型
  140 + */
  141 + private void addEventTypeToMap(Object subscriber, Class eventType) {
  142 + List<Class> eventTypes = eventTypesBySubscriber.get(subscriber);
  143 + if (eventTypes == null) {
  144 + eventTypes = new ArrayList<>();
  145 + eventTypesBySubscriber.put(subscriber, eventTypes);
  146 + }
  147 +
  148 + if (!eventTypes.contains(eventType)) {
  149 + eventTypes.add(eventType);
  150 + }
  151 + }
  152 +
  153 + /**
  154 + * 将注解方法信息以event类型为key保存到map中
  155 + *
  156 + * @param eventType event类型
  157 + * @param subscriberMethod 注解方法信息
  158 + */
  159 + private void addSubscriberToMap(Class eventType, SubscriberMethod subscriberMethod) {
  160 + List<SubscriberMethod> subscriberMethods = subscriberMethodByEventType.get(eventType);
  161 + if (subscriberMethods == null) {
  162 + subscriberMethods = new ArrayList<>();
  163 + subscriberMethodByEventType.put(eventType, subscriberMethods);
  164 + }
  165 +
  166 + if (!subscriberMethods.contains(subscriberMethod)) {
  167 + subscriberMethods.add(subscriberMethod);
  168 + }
  169 + }
  170 +
  171 + /**
  172 + * 将订阅事件以event类型为key保存到map,用于取消订阅时用
  173 + *
  174 + * @param eventType event类型
  175 + * @param disposable 订阅事件
  176 + */
  177 + private void addSubscriptionToMap(Class eventType, Disposable disposable) {
  178 + List<Disposable> disposables = subscriptionsByEventType.get(eventType);
  179 + if (disposables == null) {
  180 + disposables = new ArrayList<>();
  181 + subscriptionsByEventType.put(eventType, disposables);
  182 + }
  183 +
  184 + if (!disposables.contains(disposable)) {
  185 + disposables.add(disposable);
  186 + }
  187 + }
  188 +
  189 + /**
  190 + * 用RxJava添加订阅者
  191 + *
  192 + * @param subscriberMethod d
  193 + */
  194 + @SuppressWarnings("unchecked")
  195 + private void addSubscriber(final SubscriberMethod subscriberMethod) {
  196 + Flowable flowable;
  197 + if (subscriberMethod.code == -1) {
  198 + flowable = toObservable(subscriberMethod.eventType);
  199 + } else {
  200 + flowable = toObservable(subscriberMethod.code, subscriberMethod.eventType);
  201 + }
  202 + Disposable subscription = postToObservable(flowable, subscriberMethod)
  203 + .subscribe(new Consumer<Object>() {
  204 + @Override
  205 + public void accept(Object o) throws Exception {
  206 + callEvent(subscriberMethod, o);
  207 + }
  208 + });
  209 +
  210 + addSubscriptionToMap(subscriberMethod.subscriber.getClass(), subscription);
  211 + }
  212 +
  213 + /**
  214 + * 用于处理订阅事件在那个线程中执行
  215 + *
  216 + * @param observable d
  217 + * @param subscriberMethod d
  218 + * @return Observable
  219 + */
  220 + private Flowable postToObservable(Flowable observable, SubscriberMethod subscriberMethod) {
  221 + Scheduler scheduler;
  222 + switch (subscriberMethod.threadMode) {
  223 + case MAIN:
  224 + scheduler = AndroidSchedulers.mainThread();
  225 + break;
  226 +
  227 + case NEW_THREAD:
  228 + scheduler = Schedulers.newThread();
  229 + break;
  230 +
  231 + case CURRENT_THREAD:
  232 + scheduler = Schedulers.trampoline();
  233 + break;
  234 + default:
  235 + throw new IllegalStateException("Unknown thread mode: " + subscriberMethod.threadMode);
  236 + }
  237 + return observable.observeOn(scheduler);
  238 + }
  239 +
  240 + /**
  241 + * 回调到订阅者的方法中
  242 + *
  243 + * @param method code
  244 + * @param object obj
  245 + */
  246 + private void callEvent(SubscriberMethod method, Object object) {
  247 + Class eventClass = object.getClass();
  248 + List<SubscriberMethod> methods = subscriberMethodByEventType.get(eventClass);
  249 + if (methods != null && methods.size() > 0) {
  250 + for (SubscriberMethod subscriberMethod : methods) {
  251 + Subscribe sub = subscriberMethod.method.getAnnotation(Subscribe.class);
  252 + int c = sub.code();
  253 + if (c == method.code && method.subscriber.equals(subscriberMethod.subscriber) && method.method.equals(subscriberMethod.method)) {
  254 + subscriberMethod.invoke(object);
  255 + }
  256 +
  257 + }
  258 + }
  259 + }
  260 +
  261 + /**
  262 + * 取消注册
  263 + *
  264 + * @param subscriber object
  265 + */
  266 + public void unRegister(Object subscriber) {
  267 + List<Class> subscribedTypes = eventTypesBySubscriber.get(subscriber);
  268 + if (subscribedTypes != null) {
  269 + for (Class<?> eventType : subscribedTypes) {
  270 + unSubscribeByEventType(subscriber.getClass());
  271 + unSubscribeMethodByEventType(subscriber, eventType);
  272 + }
  273 + eventTypesBySubscriber.remove(subscriber);
  274 + }
  275 + }
  276 +
  277 + /**
  278 + * subscriptions unsubscribe
  279 + *
  280 + * @param eventType eventType
  281 + */
  282 + private void unSubscribeByEventType(Class eventType) {
  283 + List<Disposable> disposables = subscriptionsByEventType.get(eventType);
  284 + if (disposables != null) {
  285 + Iterator<Disposable> iterator = disposables.iterator();
  286 + while (iterator.hasNext()) {
  287 + Disposable disposable = iterator.next();
  288 + if (disposable != null && !disposable.isDisposed()) {
  289 + disposable.dispose();
  290 + iterator.remove();
  291 + }
  292 + }
  293 + }
  294 + }
  295 +
  296 + /**
  297 + * 移除subscriber对应的subscriberMethods
  298 + *
  299 + * @param subscriber subscriber
  300 + * @param eventType eventType
  301 + */
  302 + private void unSubscribeMethodByEventType(Object subscriber, Class eventType) {
  303 + List<SubscriberMethod> subscriberMethods = subscriberMethodByEventType.get(eventType);
  304 + if (subscriberMethods != null) {
  305 + Iterator<SubscriberMethod> iterator = subscriberMethods.iterator();
  306 + while (iterator.hasNext()) {
  307 + SubscriberMethod subscriberMethod = iterator.next();
  308 + if (subscriberMethod.subscriber.equals(subscriber)) {
  309 + iterator.remove();
  310 + }
  311 + }
  312 + }
  313 + }
  314 +
  315 + public void send(int code, Object o) {
  316 + bus.onNext(new Message(code, o));
  317 + }
  318 +
  319 + public void send(Object o) {
  320 + bus.onNext(o);
  321 + }
  322 +
  323 + public void send(int code) {
  324 + bus.onNext(new Message(code, new BusData()));
  325 + }
  326 +
  327 + private class Message {
  328 + private int code;
  329 + private Object object;
  330 +
  331 + public Message() {
  332 + }
  333 +
  334 + private Message(int code, Object o) {
  335 + this.code = code;
  336 + this.object = o;
  337 + }
  338 +
  339 + private int getCode() {
  340 + return code;
  341 + }
  342 +
  343 + public void setCode(int code) {
  344 + this.code = code;
  345 + }
  346 +
  347 + private Object getObject() {
  348 + return object;
  349 + }
  350 +
  351 + public void setObject(Object object) {
  352 + this.object = object;
  353 + }
  354 + }
  355 +}
0 \ No newline at end of file 356 \ No newline at end of file
mvpsdk/src/main/java/com/share/mvpsdk/rxbus/Subscribe.java 0 → 100644
@@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
  1 +package com.share.mvpsdk.rxbus;
  2 +
  3 +import java.lang.annotation.Documented;
  4 +import java.lang.annotation.ElementType;
  5 +import java.lang.annotation.Retention;
  6 +import java.lang.annotation.RetentionPolicy;
  7 +import java.lang.annotation.Target;
  8 +
  9 +
  10 +/**
  11 + * Rxbus
  12 + * Created by gorden on 2016/7/23.
  13 + */
  14 +@Documented
  15 +@Target(ElementType.METHOD)
  16 +@Retention(RetentionPolicy.RUNTIME)
  17 +public @interface Subscribe {
  18 + int code() default -1;
  19 +
  20 + ThreadMode threadMode() default ThreadMode.CURRENT_THREAD;
  21 +}
0 \ No newline at end of file 22 \ No newline at end of file
mvpsdk/src/main/java/com/share/mvpsdk/rxbus/SubscriberMethod.java 0 → 100644
@@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
  1 +package com.share.mvpsdk.rxbus;
  2 +
  3 +import java.lang.reflect.InvocationTargetException;
  4 +import java.lang.reflect.Method;
  5 +
  6 +/**
  7 + *
  8 + * Created by gorden on 2016/7/23.
  9 + */
  10 +public class SubscriberMethod {
  11 + public Method method;
  12 + public ThreadMode threadMode;
  13 + public Class<?> eventType;
  14 + public Object subscriber;
  15 + public int code;
  16 +
  17 + public SubscriberMethod(Object subscriber, Method method, Class<?> eventType, int code,ThreadMode threadMode) {
  18 + this.method = method;
  19 + this.threadMode = threadMode;
  20 + this.eventType = eventType;
  21 + this.subscriber = subscriber;
  22 + this.code = code;
  23 + }
  24 +
  25 +
  26 + /**
  27 + * 调用方法
  28 + * @param o 参数
  29 + */
  30 + public void invoke(Object o){
  31 + try {
  32 + Class[] parameterType = method.getParameterTypes();
  33 + if(parameterType != null && parameterType.length == 1){
  34 + method.invoke(subscriber, o);
  35 + }else if(parameterType == null || parameterType.length == 0){
  36 + method.invoke(subscriber);
  37 + }
  38 + } catch (IllegalAccessException e) {
  39 + e.printStackTrace();
  40 + } catch (InvocationTargetException e) {
  41 + e.printStackTrace();
  42 + }
  43 + }
  44 +}
0 \ No newline at end of file 45 \ No newline at end of file
mvpsdk/src/main/java/com/share/mvpsdk/rxbus/ThreadMode.java 0 → 100644
@@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
  1 +package com.share.mvpsdk.rxbus;
  2 +
  3 +/**
  4 + *
  5 + * Created by gorden on 2016/7/23.
  6 + */
  7 +public enum ThreadMode {
  8 + /**
  9 + * current thread
  10 + */
  11 + CURRENT_THREAD,
  12 +
  13 + /**
  14 + * android main thread
  15 + */
  16 + MAIN,
  17 +
  18 +
  19 + /**
  20 + * new thread
  21 + */
  22 + NEW_THREAD
  23 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/AppUtils.java 0 → 100644
@@ -0,0 +1,185 @@ @@ -0,0 +1,185 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.annotation.SuppressLint;
  4 +import android.content.ClipData;
  5 +import android.content.ClipboardManager;
  6 +import android.content.Context;
  7 +import android.content.Intent;
  8 +import android.content.pm.PackageInfo;
  9 +import android.content.pm.PackageManager;
  10 +import android.net.Uri;
  11 +import android.os.Environment;
  12 +import android.os.Handler;
  13 +import android.telephony.TelephonyManager;
  14 +import android.util.Log;
  15 +import android.view.inputmethod.InputMethodManager;
  16 +import android.widget.EditText;
  17 +
  18 +
  19 +import com.share.mvpsdk.global.GlobalApplication;
  20 +
  21 +import java.io.File;
  22 +
  23 +import timber.log.Timber;
  24 +
  25 +/**
  26 + * Created by Horrarndoo on 2017/8/31.
  27 + * <p>
  28 + * App工具类
  29 + */
  30 +public class AppUtils {
  31 +
  32 + /**
  33 + * 获取上下文对象
  34 + *
  35 + * @return 上下文对象
  36 + */
  37 + public static Context getContext() {
  38 + return GlobalApplication.getContext();
  39 + }
  40 +
  41 + /**
  42 + * 获取全局handler
  43 + *
  44 + * @return 全局handler
  45 + */
  46 + public static Handler getHandler() {
  47 + return GlobalApplication.getHandler();
  48 + }
  49 +
  50 + /**
  51 + * 获取主线程id
  52 + *
  53 + * @return 主线程id
  54 + */
  55 + public static int getMainThreadId() {
  56 + return GlobalApplication.getMainThreadId();
  57 + }
  58 +
  59 + /**
  60 + * 获取版本名称
  61 + */
  62 + public static String getAppVersionName(Context context) {
  63 + String versionName = "";
  64 + try {
  65 + // ---get the package info---
  66 + PackageManager pm = context.getPackageManager();
  67 + PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
  68 + versionName = pi.versionName;
  69 + if (versionName == null || versionName.length() <= 0) {
  70 + return "";
  71 + }
  72 + } catch (Exception e) {
  73 + Log.e("VersionInfo", "Exception", e);
  74 + }
  75 + return versionName;
  76 + }
  77 +
  78 + /**
  79 + * 获取版本号
  80 + */
  81 + public static int getAppVersionCode(Context context) {
  82 + int versioncode = -1;
  83 + try {
  84 + // ---get the package info---
  85 + PackageManager pm = context.getPackageManager();
  86 + PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
  87 + versioncode = pi.versionCode;
  88 + } catch (Exception e) {
  89 + Log.e("VersionInfo", "Exception", e);
  90 + }
  91 + return versioncode;
  92 + }
  93 +
  94 + @SuppressLint("MissingPermission")
  95 + public static String getIMEI(Context context) {
  96 + TelephonyManager tm = (TelephonyManager) context.getSystemService(Context
  97 + .TELEPHONY_SERVICE);
  98 + return tm.getDeviceId();
  99 + }
  100 +
  101 + /**
  102 + * 显示软键盘
  103 + */
  104 + public static void openSoftInput(EditText et) {
  105 + InputMethodManager inputMethodManager = (InputMethodManager) et.getContext()
  106 + .getSystemService(Context.INPUT_METHOD_SERVICE);
  107 + inputMethodManager.showSoftInput(et, InputMethodManager.HIDE_NOT_ALWAYS);
  108 + }
  109 +
  110 + /**
  111 + * 隐藏软键盘
  112 + */
  113 + public static void hideSoftInput(EditText et) {
  114 + InputMethodManager inputMethodManager = (InputMethodManager) et.getContext()
  115 + .getSystemService(Context.INPUT_METHOD_SERVICE);
  116 + inputMethodManager.hideSoftInputFromWindow(et.getWindowToken(), InputMethodManager
  117 + .HIDE_NOT_ALWAYS);
  118 + }
  119 +
  120 + /**
  121 + * 获取SD卡路径
  122 + *
  123 + * @return 如果sd卡不存在则返回null
  124 + */
  125 + public static File getSDPath() {
  126 + File sdDir = null;
  127 + boolean sdCardExist = Environment.getExternalStorageState().equals(Environment
  128 + .MEDIA_MOUNTED); //判断sd卡是否存在
  129 + if (sdCardExist) {
  130 + sdDir = Environment.getExternalStorageDirectory();//获取跟目录
  131 + }
  132 + return sdDir;
  133 + }
  134 +
  135 + /**
  136 + * 安装文件
  137 + *
  138 + * @param data
  139 + */
  140 + public static void promptInstall(Context context, Uri data) {
  141 + Intent promptInstall = new Intent(Intent.ACTION_VIEW)
  142 + .setDataAndType(data, "application/vnd.android.package-archive");
  143 + // FLAG_ACTIVITY_NEW_TASK 可以保证安装成功时可以正常打开 app
  144 + promptInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  145 + context.startActivity(promptInstall);
  146 + }
  147 +
  148 + public static void copy2clipboard(Context context, String text) {
  149 + ClipboardManager cm = (ClipboardManager) context.getSystemService(Context
  150 + .CLIPBOARD_SERVICE);
  151 + ClipData clip = ClipData.newPlainText("clip", text);
  152 + cm.setPrimaryClip(clip);
  153 + }
  154 +
  155 + /**
  156 + * 判断是否运行在主线程
  157 + *
  158 + * @return true:当前线程运行在主线程
  159 + * fasle:当前线程没有运行在主线程
  160 + */
  161 + public static boolean isRunOnUIThread() {
  162 + // 获取当前线程id, 如果当前线程id和主线程id相同, 那么当前就是主线程
  163 + int myTid = android.os.Process.myTid();
  164 + if (myTid == getMainThreadId()) {
  165 + return true;
  166 + }
  167 + return false;
  168 + }
  169 +
  170 + /**
  171 + * 运行在主线程
  172 + *
  173 + * @param r 运行的Runnable对象
  174 + */
  175 + public static void runOnUIThread(Runnable r) {
  176 + if (isRunOnUIThread()) {
  177 + // 已经是主线程, 直接运行
  178 + r.run();
  179 + } else {
  180 + // 如果是子线程, 借助handler让其运行在主线程
  181 + Log.d("66666","getHander="+getHandler()+"r="+r);
  182 + getHandler().post(r);
  183 + }
  184 + }
  185 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/CacheUtils.java 0 → 100644
@@ -0,0 +1,168 @@ @@ -0,0 +1,168 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.content.Context;
  4 +import android.os.Environment;
  5 +
  6 +import java.io.File;
  7 +import java.math.BigDecimal;
  8 +
  9 +/**
  10 + * Created by ToaHanDong on 2018/3/15.
  11 + */
  12 +
  13 +public class CacheUtils {
  14 +
  15 + /** * 清除本应用内部缓存(/data/data/com.xxx.xxx/cache) * * @param context */
  16 + public static void cleanInternalCache(Context context) {
  17 + deleteFilesByDirectory(context.getCacheDir());
  18 + }
  19 +
  20 + /** * 清除本应用所有数据库(/data/data/com.xxx.xxx/databases) * * @param context */
  21 + public static void cleanDatabases(Context context) {
  22 + deleteFilesByDirectory(new File("/data/data/"
  23 + + context.getPackageName() + "/databases"));
  24 + }
  25 +
  26 + /**
  27 + * * 清除本应用SharedPreference(/data/data/com.xxx.xxx/shared_prefs) * * @param
  28 + * context
  29 + */
  30 + public static void cleanSharedPreference(Context context) {
  31 + deleteFilesByDirectory(new File("/data/data/"+ context.getPackageName() + "/shared_prefs"));
  32 + }
  33 +
  34 + /** * 按名字清除本应用数据库 * * @param context * @param dbName */
  35 + public static void cleanDatabaseByName(Context context, String dbName) {
  36 + context.deleteDatabase(dbName);
  37 + }
  38 +
  39 + /** * 清除/data/data/com.xxx.xxx/files下的内容 * * @param context */
  40 + public static void cleanFiles(Context context) {
  41 + deleteFilesByDirectory(context.getFilesDir());
  42 + }
  43 +
  44 + /**
  45 + * * 清除外部cache下的内容(/mnt/sdcard/android/data/com.xxx.xxx/cache) * * @param
  46 + * context
  47 + */
  48 + public static void cleanExternalCache(Context context) {
  49 + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
  50 + deleteFilesByDirectory(context.getExternalCacheDir());
  51 + }
  52 + }
  53 +
  54 + /** * 清除自定义路径下的文件,使用需小心,请不要误删。而且只支持目录下的文件删除 * * @param filePath */
  55 + public static void cleanCustomCache(String filePath) {
  56 + deleteFilesByDirectory1(new File(filePath));
  57 + }
  58 +
  59 + /** * 清除本应用所有的数据 * * @param context * @param filepath */
  60 + public static void cleanApplicationData(Context context, String filepath) {
  61 +// cleanInternalCache(context);
  62 +// cleanExternalCache(context);
  63 +// cleanDatabases(context);
  64 + cleanSharedPreference(context);
  65 +// cleanFiles(context);
  66 +// cleanCustomCache(filepath);
  67 + }
  68 +
  69 + /** * 删除方法 这里只会删除某个文件夹下的文件,如果传入的directory是个文件,将不做处理 * * @param directory */
  70 + public static void deleteFilesByDirectory(File directory) {
  71 + if (directory != null && directory.exists() && directory.isDirectory()) {
  72 + for (File item : directory.listFiles()) {
  73 + item.delete();
  74 + }
  75 + }
  76 + }
  77 + private static void deleteFilesByDirectory1(File dir){
  78 + if (dir!=null && dir.isDirectory()) {
  79 + String[] children = dir.list();
  80 + //递归删除目录中的子目录下
  81 + for (int i = 0; i < children.length; i++) {
  82 + StorageUtils.DeleteDirAndFile(new File(dir, children[i]));
  83 + }
  84 + }
  85 + }
  86 +
  87 + /**
  88 + * 清理缓存
  89 + * @param context
  90 + * @param filepath
  91 + */
  92 + public static void cleanEboardCache(Context context, String filepath) {
  93 + cleanInternalCache(context);
  94 + cleanExternalCache(context);
  95 + cleanFiles(context);
  96 + cleanCustomCache(filepath);
  97 + }
  98 +
  99 + public static void clearCache(Context context)throws Exception{
  100 + File file=new File("/data/data/"+ context.getPackageName());
  101 + cleanCustomCache(file.toString());
  102 + }
  103 +
  104 + public static String getCacheSize(Context context) throws Exception {
  105 + File file=new File("/data/data/"+ context.getPackageName());
  106 + return getFormatSize(getFolderSize(file));
  107 + }
  108 +
  109 + // 获取文件
  110 + //Context.getExternalFilesDir() --> SDCard/Android/data/你的应用的包名/files/ 目录,一般放一些长时间保存的数据
  111 + //Context.getExternalCacheDir() --> SDCard/Android/data/你的应用包名/cache/目录,一般存放临时缓存数据
  112 + public static long getFolderSize(File file) throws Exception {
  113 + long size = 0;
  114 + try {
  115 + File[] fileList = file.listFiles();
  116 + for (int i = 0; i < fileList.length; i++) {
  117 + // 如果下面还有文件
  118 + if (fileList[i].isDirectory()) {
  119 + size = size + getFolderSize(fileList[i]);
  120 + } else {
  121 + size = size + fileList[i].length();
  122 + }
  123 + }
  124 + } catch (Exception e) {
  125 + e.printStackTrace();
  126 + }
  127 + return size;
  128 + }
  129 +
  130 +
  131 + /**
  132 + * 格式化单位
  133 + *
  134 + * @param size
  135 + * @return
  136 + */
  137 + public static String getFormatSize(double size) {
  138 + double kiloByte = size / 1024;
  139 + if (kiloByte < 1) {
  140 + return size + "Byte";
  141 + }
  142 +
  143 + double megaByte = kiloByte / 1024;
  144 + if (megaByte < 1) {
  145 + BigDecimal result1 = new BigDecimal(Double.toString(kiloByte));
  146 + return result1.setScale(2, BigDecimal.ROUND_HALF_UP)
  147 + .toPlainString() + "KB";
  148 + }
  149 +
  150 + double gigaByte = megaByte / 1024;
  151 + if (gigaByte < 1) {
  152 + BigDecimal result2 = new BigDecimal(Double.toString(megaByte));
  153 + return result2.setScale(2, BigDecimal.ROUND_HALF_UP)
  154 + .toPlainString() + "MB";
  155 + }
  156 +
  157 + double teraBytes = gigaByte / 1024;
  158 + if (teraBytes < 1) {
  159 + BigDecimal result3 = new BigDecimal(Double.toString(gigaByte));
  160 + return result3.setScale(2, BigDecimal.ROUND_HALF_UP)
  161 + .toPlainString() + "GB";
  162 + }
  163 + BigDecimal result4 = new BigDecimal(teraBytes);
  164 + return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString()
  165 + + "TB";
  166 + }
  167 +
  168 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/DBUtils.java 0 → 100644
@@ -0,0 +1,114 @@ @@ -0,0 +1,114 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.content.ContentValues;
  4 +import android.content.Context;
  5 +import android.content.SharedPreferences;
  6 +import android.database.Cursor;
  7 +import android.database.sqlite.SQLiteDatabase;
  8 +import android.database.sqlite.SQLiteOpenHelper;
  9 +
  10 +import com.share.mvpsdk.config.DBConfig;
  11 +
  12 +
  13 +/**
  14 + * Created by Horrarndoo on 2017/8/31.
  15 + * <p>
  16 + * 数据库工具类
  17 + */
  18 +public class DBUtils {
  19 + public static final String CREATE_TABLE_IF_NOT_EXISTS = "create table if not exists %s " +
  20 + "(id integer primary key autoincrement,title text unique,image text)";
  21 +
  22 +
  23 + private static DBUtils sDBUtis;
  24 + private SQLiteDatabase mSQLiteDatabase;
  25 +
  26 + private DBUtils(Context context) {
  27 + mSQLiteDatabase = new DBHelper(context, DBConfig.DB_NAME + ".db")
  28 + .getWritableDatabase();
  29 + }
  30 +
  31 + public static synchronized DBUtils getDB(Context context) {
  32 + if (sDBUtis == null) {
  33 + synchronized (DBUtils.class) {
  34 + if (sDBUtis == null)
  35 + sDBUtis = new DBUtils(context);
  36 + }
  37 + }
  38 + return sDBUtis;
  39 + }
  40 +
  41 + /**
  42 + * 插入一个item已读状态到数据表
  43 + *
  44 + * @param table 数据表名
  45 + * @param key key值
  46 + * @param value 数据值
  47 + * @return 插入结果
  48 + */
  49 + public boolean insertRead(final String table, String key, int value) {
  50 + Cursor cursor = mSQLiteDatabase.query(table, null, null, null, null, null, "id asc");
  51 + //最多缓存200条
  52 + if (cursor.getCount() > 200 && cursor.moveToNext()) {
  53 + mSQLiteDatabase.delete(table, "id=?", new String[]{String.valueOf(cursor.getInt
  54 + (cursor.getColumnIndex("id")))});
  55 + }
  56 + cursor.close();
  57 + final ContentValues contentValues = new ContentValues();
  58 + contentValues.put("key", key);
  59 + contentValues.put("is_read", value);
  60 + return (mSQLiteDatabase.insertWithOnConflict(table, null, contentValues, SQLiteDatabase
  61 + .CONFLICT_REPLACE) > 0);
  62 + }
  63 +
  64 + /**
  65 + * 判断item是否已经阅读过
  66 + *
  67 + * @param table 数据表名
  68 + * @param key key值
  69 + * @param value
  70 + * @return
  71 + */
  72 + public boolean isRead(String table, String key, int value) {
  73 + boolean isRead = false;
  74 + Cursor cursor = mSQLiteDatabase.query(table, null, "key=?", new String[]{key}, null,
  75 + null, null);
  76 + if (cursor.moveToNext() && (cursor.getInt(cursor.getColumnIndex("is_read")) == value)) {
  77 + isRead = true;
  78 + }
  79 + cursor.close();
  80 + return isRead;
  81 + }
  82 +
  83 + public void insert(String table,String key,String value){
  84 +
  85 + }
  86 +
  87 + public class DBHelper extends SQLiteOpenHelper {
  88 +
  89 + public DBHelper(Context context, String name) {
  90 + super(context, name, null, 1);
  91 + }
  92 +
  93 + @Override
  94 + public void onCreate(SQLiteDatabase db) {
  95 + //onCreate()方法只有数据库第一次被创建时才会调用,若数据库已存在,此方法不会被调用
  96 + }
  97 +
  98 + @Override
  99 + public void onOpen(SQLiteDatabase db) {
  100 + super.onOpen(db);
  101 + //数据库打开时就会被调用,将插入新表的操作方到onOpen中
  102 + db.execSQL(String.format(CREATE_TABLE_IF_NOT_EXISTS, DBConfig.TABLE_ZHIHU));
  103 + db.execSQL(String.format(CREATE_TABLE_IF_NOT_EXISTS, DBConfig.TABLE_WANGYI));
  104 + db.execSQL(String.format(CREATE_TABLE_IF_NOT_EXISTS, DBConfig.TABLE_WEIXIN));
  105 + db.execSQL(String.format(CREATE_TABLE_IF_NOT_EXISTS, DBConfig.TABLE_GANKIO_DAY));
  106 + db.execSQL(String.format(CREATE_TABLE_IF_NOT_EXISTS, DBConfig.TABLE_GANKIO_CUSTOM));
  107 + }
  108 +
  109 + @Override
  110 + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  111 + //只有数据库进行版本升级时被调用
  112 + }
  113 + }
  114 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/DateUtils.java 0 → 100644
@@ -0,0 +1,259 @@ @@ -0,0 +1,259 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.text.TextUtils;
  4 +import android.text.format.DateFormat;
  5 +
  6 +import java.text.ParseException;
  7 +import java.text.SimpleDateFormat;
  8 +import java.util.Calendar;
  9 +import java.util.Date;
  10 +import java.util.Locale;
  11 +
  12 +/**
  13 + * Created by Horrarndoo on 2017/8/31.
  14 + * <p>
  15 + * 日期时间工具类
  16 + */
  17 +public class DateUtils {
  18 +
  19 + public static final long ONE_SECOND_MILLIONS = 1000;
  20 + public static final long ONE_MINUTE_MILLIONS = 60 * ONE_SECOND_MILLIONS;
  21 + public static final long ONE_HOUR_MILLIONS = 60 * ONE_MINUTE_MILLIONS;
  22 + public static final long ONE_DAY_MILLIONS = 24 * ONE_HOUR_MILLIONS;
  23 + public static final int DAY_OF_YEAR = 365;
  24 +
  25 + // 日期格式为 2016-02-03 17:04:58
  26 + public static final String PATTERN_DATE = "yyyy年MM月dd日";
  27 + public static final String PATTERN_TIME = "HH:mm:ss";
  28 + public static final String PATTERN_SPLIT = " ";
  29 + public static final String PATTERN = PATTERN_DATE + PATTERN_SPLIT + PATTERN_TIME;
  30 +
  31 + public static String getShortTime(String dateStr) {
  32 + String str;
  33 +
  34 + Date date = str2date(dateStr);
  35 + Date curDate = new Date();
  36 +
  37 + long durTime = curDate.getTime() - date.getTime();
  38 + int dayDiff = calculateDayDiff(date, curDate);
  39 +
  40 + if (durTime <= 10 * ONE_MINUTE_MILLIONS) {
  41 + str = "刚刚";
  42 + } else if (durTime < ONE_HOUR_MILLIONS) {
  43 + str = durTime / ONE_MINUTE_MILLIONS + "分钟前";
  44 + } else if (dayDiff == 0) {
  45 + str = durTime / ONE_HOUR_MILLIONS + "小时前";
  46 + } else if (dayDiff == -1) {
  47 + str = "昨天" + DateFormat.format("HH:mm", date);
  48 + } else if (isSameYear(date, curDate) && dayDiff < -1) {
  49 + str = DateFormat.format("MM-dd", date).toString();
  50 + } else {
  51 + str = DateFormat.format("yyyy-MM", date).toString();
  52 + }
  53 +
  54 + return str;
  55 + }
  56 +
  57 + public static String format(long millis){
  58 + SimpleDateFormat format = new SimpleDateFormat("MM/dd", Locale.getDefault());
  59 + return format.format(millis);
  60 + }
  61 +
  62 + /**
  63 + * 获取日期 PATTERN_DATE 部分
  64 + */
  65 + public static String getDate(String date) {
  66 + if (TextUtils.isEmpty(date) || !date.contains(PATTERN_SPLIT)) {
  67 + return "";
  68 + }
  69 + return date.split(PATTERN_SPLIT)[0];
  70 + }
  71 +
  72 + public static String dateFormat(Date date,String fomart){
  73 + SimpleDateFormat simpleDateFormat=new SimpleDateFormat(fomart);
  74 + return simpleDateFormat.format(date);
  75 + }
  76 +
  77 + /**
  78 + * 原有日期上累加月
  79 + *
  80 + * @return 累加后的日期 PATTERN_DATE 部分
  81 + */
  82 + public static String addMonth(String date, int moonCount) {
  83 + //如果date为空 就用当前时间
  84 + if (TextUtils.isEmpty(date)) {
  85 + SimpleDateFormat df = new SimpleDateFormat(PATTERN_DATE + PATTERN_SPLIT + PATTERN_TIME);
  86 + date = df.format(new Date());
  87 + }
  88 + Calendar calendar = str2calendar(date);
  89 + calendar.add(Calendar.MONTH, moonCount);
  90 + return getDate(calendar2str(calendar));
  91 + }
  92 +
  93 + /**
  94 + * 计算天数差
  95 + */
  96 + public static int calculateDayDiff(Date targetTime, Date compareTime) {
  97 + boolean sameYear = isSameYear(targetTime, compareTime);
  98 + if (sameYear) {
  99 + return calculateDayDiffOfSameYear(targetTime, compareTime);
  100 + } else {
  101 + int dayDiff = 0;
  102 +
  103 + // 累计年数差的整年天数
  104 + int yearDiff = calculateYearDiff(targetTime, compareTime);
  105 + dayDiff += yearDiff * DAY_OF_YEAR;
  106 +
  107 + // 累计同一年内的天数
  108 + dayDiff += calculateDayDiffOfSameYear(targetTime, compareTime);
  109 +
  110 + return dayDiff;
  111 + }
  112 + }
  113 +
  114 + /**
  115 + * 计算同一年内的天数差
  116 + */
  117 + public static int calculateDayDiffOfSameYear(Date targetTime, Date compareTime) {
  118 + if (targetTime == null || compareTime == null) {
  119 + return 0;
  120 + }
  121 +
  122 + Calendar tarCalendar = Calendar.getInstance();
  123 + tarCalendar.setTime(targetTime);
  124 + int tarDayOfYear = tarCalendar.get(Calendar.DAY_OF_YEAR);
  125 +
  126 + Calendar compareCalendar = Calendar.getInstance();
  127 + compareCalendar.setTime(compareTime);
  128 + int comDayOfYear = compareCalendar.get(Calendar.DAY_OF_YEAR);
  129 +
  130 + return tarDayOfYear - comDayOfYear;
  131 + }
  132 +
  133 + /**
  134 + * 计算年数差
  135 + */
  136 + public static int calculateYearDiff(Date targetTime, Date compareTime) {
  137 + if (targetTime == null || compareTime == null) {
  138 + return 0;
  139 + }
  140 +
  141 + Calendar tarCalendar = Calendar.getInstance();
  142 + tarCalendar.setTime(targetTime);
  143 + int tarYear = tarCalendar.get(Calendar.YEAR);
  144 +
  145 + Calendar compareCalendar = Calendar.getInstance();
  146 + compareCalendar.setTime(compareTime);
  147 + int comYear = compareCalendar.get(Calendar.YEAR);
  148 +
  149 + return tarYear - comYear;
  150 + }
  151 +
  152 + /**
  153 + * 计算月数差
  154 + *
  155 + * @param targetTime
  156 + * @param compareTime
  157 + * @return
  158 + */
  159 + public static int calculateMonthDiff(String targetTime, String compareTime) {
  160 + return calculateMonthDiff(str2date(targetTime, PATTERN_DATE),
  161 + str2date(compareTime, PATTERN_DATE));
  162 + }
  163 +
  164 + /**
  165 + * 计算月数差
  166 + *
  167 + * @param targetTime
  168 + * @param compareTime
  169 + * @return
  170 + */
  171 + public static int calculateMonthDiff(Date targetTime, Date compareTime) {
  172 + Calendar tarCalendar = Calendar.getInstance();
  173 + tarCalendar.setTime(targetTime);
  174 + int tarYear = tarCalendar.get(Calendar.YEAR);
  175 + int tarMonth = tarCalendar.get(Calendar.MONTH);
  176 +
  177 + Calendar compareCalendar = Calendar.getInstance();
  178 + compareCalendar.setTime(compareTime);
  179 + int comYear = compareCalendar.get(Calendar.YEAR);
  180 + int comMonth = compareCalendar.get(Calendar.MONTH);
  181 + return ((tarYear - comYear) * 12 + tarMonth - comMonth);
  182 +
  183 + }
  184 +
  185 + /**
  186 + * 是否为同一年
  187 + */
  188 + public static boolean isSameYear(Date targetTime, Date compareTime) {
  189 + if (targetTime == null || compareTime == null) {
  190 + return false;
  191 + }
  192 +
  193 + Calendar tarCalendar = Calendar.getInstance();
  194 + tarCalendar.setTime(targetTime);
  195 + int tarYear = tarCalendar.get(Calendar.YEAR);
  196 +
  197 + Calendar compareCalendar = Calendar.getInstance();
  198 + compareCalendar.setTime(compareTime);
  199 + int comYear = compareCalendar.get(Calendar.YEAR);
  200 +
  201 + return tarYear == comYear;
  202 + }
  203 +
  204 + public static Date str2date(String str, String format) {
  205 + Date date = null;
  206 + try {
  207 + if (str != null) {
  208 + SimpleDateFormat sdf = new SimpleDateFormat(format);
  209 + date = sdf.parse(str);
  210 + }
  211 + } catch (ParseException e) {
  212 + e.printStackTrace();
  213 + }
  214 + return date;
  215 + }
  216 +
  217 + public static Date str2date(String str) {
  218 + return str2date(str, PATTERN);
  219 + }
  220 +
  221 + public static String date2str(Date date) {
  222 + return date2str(date, PATTERN);
  223 + }
  224 +
  225 + public static String date2str(Date date, String format) {
  226 + SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.CHINA);
  227 + return sdf.format(date);
  228 + }
  229 +
  230 + public static Calendar str2calendar(String str) {
  231 + Calendar calendar = null;
  232 + Date date = str2date(str);
  233 + if (date != null) {
  234 + calendar = Calendar.getInstance();
  235 + calendar.setTime(date);
  236 + }
  237 + return calendar;
  238 + }
  239 +
  240 +
  241 + public static Calendar str2calendar(String str, String format) {
  242 + Calendar calendar = null;
  243 + Date date = str2date(str, format);
  244 + if (date != null) {
  245 + calendar = Calendar.getInstance();
  246 + calendar.setTime(date);
  247 + }
  248 + return calendar;
  249 + }
  250 +
  251 + public static String calendar2str(Calendar calendar) {
  252 + return date2str(calendar.getTime());
  253 + }
  254 +
  255 + public static String calendar2str(Calendar calendar, String format) {
  256 + return date2str(calendar.getTime(), format);
  257 + }
  258 +
  259 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/DialogUtils.java 0 → 100644
@@ -0,0 +1,60 @@ @@ -0,0 +1,60 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.app.Dialog;
  4 +import android.app.ProgressDialog;
  5 +import android.content.Context;
  6 +import android.content.DialogInterface;
  7 +import android.support.v7.app.AlertDialog;
  8 +
  9 +import com.share.mvpsdk.R;
  10 +
  11 +
  12 +/**
  13 + * Created by Horrarndoo on 2017/8/31.
  14 + * <p>
  15 + * 对话框工具类, 提供常用对话框显示, 使用support.v7包内的AlertDialog样式
  16 + */
  17 +public class DialogUtils {
  18 +
  19 + public static Dialog createProgressDialog(Context context) {
  20 + return createProgressDialog(context, true);
  21 + }
  22 +
  23 + public static Dialog createProgressDialog(Context context, boolean needCancle) {
  24 + ProgressDialog dialog = new ProgressDialog(context);
  25 + dialog.setMessage("Loading ...");
  26 + dialog.setCancelable(needCancle);
  27 + dialog.setCanceledOnTouchOutside(false);
  28 + return dialog;
  29 + }
  30 +
  31 + public static Dialog showCommonDialog(Context context, String message,
  32 + DialogInterface.OnClickListener listener) {
  33 + return showCommonDialog(context, message, context.getString(R.string.dialog_positive),
  34 + context.getString(R.string.dialog_negative), listener);
  35 + }
  36 +
  37 + public static Dialog showCommonDialog(Context context, String message, String positiveText,
  38 + String negativeText, DialogInterface.OnClickListener
  39 + listener) {
  40 + return new AlertDialog.Builder(context)
  41 + .setMessage(message)
  42 + .setPositiveButton(positiveText, listener)
  43 + .setNegativeButton(negativeText, null)
  44 + .show();
  45 + }
  46 +
  47 + public static Dialog showConfirmDialog(Context context, String message,
  48 + DialogInterface.OnClickListener listener) {
  49 + return showConfirmDialog(context, message, context.getString(R.string.dialog_positive),
  50 + listener);
  51 + }
  52 +
  53 + public static Dialog showConfirmDialog(Context context, String message, String positiveText,
  54 + DialogInterface.OnClickListener listener) {
  55 + return new AlertDialog.Builder(context)
  56 + .setMessage(message)
  57 + .setPositiveButton(positiveText, listener)
  58 + .show();
  59 + }
  60 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/DisplayUtils.java 0 → 100644
@@ -0,0 +1,195 @@ @@ -0,0 +1,195 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.app.Activity;
  4 +import android.content.Context;
  5 +import android.graphics.Bitmap;
  6 +import android.graphics.Canvas;
  7 +import android.os.Build;
  8 +import android.renderscript.Allocation;
  9 +import android.renderscript.Element;
  10 +import android.renderscript.RenderScript;
  11 +import android.renderscript.ScriptIntrinsicBlur;
  12 +import android.util.DisplayMetrics;
  13 +import android.view.View;
  14 +import android.widget.ImageView;
  15 +
  16 +import com.bumptech.glide.Glide;
  17 +import com.share.mvpsdk.R;
  18 +
  19 +import java.io.File;
  20 +
  21 +import jp.wasabeef.glide.transformations.BlurTransformation;
  22 +
  23 +/**
  24 + * Created by Horrarndoo on 2017/8/31.
  25 + * <p>
  26 + * 显示相关工具类
  27 + */
  28 +public class DisplayUtils {
  29 + /**
  30 + * 将px值转换为dp值
  31 + */
  32 + public static int px2dp(float pxValue) {
  33 + final float scale = AppUtils.getContext().getResources().getDisplayMetrics().density;
  34 + return (int) (pxValue / scale + 0.5f);
  35 + }
  36 +
  37 + /**
  38 + * 将dp值转换为px值
  39 + */
  40 + public static int dp2px(float dpValue) {
  41 + final float scale = AppUtils.getContext().getResources().getDisplayMetrics().density;
  42 + return (int) (dpValue * scale + 0.5f);
  43 + }
  44 +
  45 + /**
  46 + * 将px值转换为sp值
  47 + */
  48 + public static int px2sp(float pxValue) {
  49 + final float scale = AppUtils.getContext().getResources().getDisplayMetrics().scaledDensity;
  50 + return (int) (pxValue / scale + 0.5f);
  51 + }
  52 +
  53 + /**
  54 + * 将sp值转换为px值
  55 + */
  56 + public static int sp2px(float dpValue) {
  57 + final float scale = AppUtils.getContext().getResources().getDisplayMetrics().scaledDensity;
  58 + return (int) (dpValue * scale + 0.5f);
  59 + }
  60 +
  61 + /**
  62 + * 获取屏幕宽度
  63 + */
  64 + public static int getScreenWidthPixels(Activity context) {
  65 + DisplayMetrics metric = new DisplayMetrics();
  66 + context.getWindowManager().getDefaultDisplay().getMetrics(metric);
  67 + return metric.widthPixels;
  68 + }
  69 +
  70 + /**
  71 + * 获取屏幕高度
  72 + */
  73 + public static int getScreenHeightPixels(Activity context) {
  74 + DisplayMetrics metric = new DisplayMetrics();
  75 + context.getWindowManager().getDefaultDisplay().getMetrics(metric);
  76 + return metric.heightPixels;
  77 + }
  78 +
  79 + /**
  80 + * 将一个view转换成bitmap位图
  81 + *
  82 + * @param view 要转换的View
  83 + * @return view转换的bitmap
  84 + */
  85 + public static Bitmap viewToBitmap(View view) {
  86 + Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(),
  87 + Bitmap.Config.ARGB_8888);
  88 + view.draw(new Canvas(bitmap));
  89 + return bitmap;
  90 + }
  91 +
  92 + /**
  93 + * 获取模糊虚化的bitmap
  94 + *
  95 + * @param context
  96 + * @param bitmap 要模糊的图片
  97 + * @param radius 模糊等级 >=0 && <=25
  98 + * @return
  99 + */
  100 + public static Bitmap getBlurBitmap(Context context, Bitmap bitmap, int radius) {
  101 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
  102 + return blurBitmap(context, bitmap, radius);
  103 + }
  104 + return bitmap;
  105 + }
  106 +
  107 + /**
  108 + * android系统的模糊方法
  109 + *
  110 + * @param bitmap 要模糊的图片
  111 + * @param radius 模糊等级 >=0 && <=25
  112 + */
  113 + public static Bitmap blurBitmap(Context context, Bitmap bitmap, int radius) {
  114 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
  115 + //Let's create an empty bitmap with the same size of the bitmap we want to blur
  116 + Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap
  117 + .Config.ARGB_8888);
  118 + //Instantiate a new Renderscript
  119 + RenderScript rs = RenderScript.create(context);
  120 + //Create an Intrinsic Blur Script using the Renderscript
  121 + ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
  122 + //Create the Allocations (in/out) with the Renderscript and the in/out bitmaps
  123 + Allocation allIn = Allocation.createFromBitmap(rs, bitmap);
  124 + Allocation allOut = Allocation.createFromBitmap(rs, outBitmap);
  125 + //Set the radius of the blur
  126 + blurScript.setRadius(radius);
  127 + //Perform the Renderscript
  128 + blurScript.setInput(allIn);
  129 + blurScript.forEach(allOut);
  130 + //Copy the final bitmap created by the out Allocation to the outBitmap
  131 + allOut.copyTo(outBitmap);
  132 + //recycle the original bitmap
  133 + bitmap.recycle();
  134 + //After finishing everything, we destroy the Renderscript.
  135 + rs.destroy();
  136 + return outBitmap;
  137 + } else {
  138 + return bitmap;
  139 + }
  140 + }
  141 +
  142 + /**
  143 + * 显示网络虚化图片
  144 + *
  145 + * @param context context
  146 + * @param imgUrl 图片url
  147 + * @param imageView 要显示的imageview
  148 + */
  149 + public static void displayBlurImg(Context context, final String imgUrl, ImageView imageView) {
  150 + // "23":模糊度;"4":图片缩放4倍后再进行模糊
  151 + Glide.with(context)
  152 + .load(imgUrl)
  153 + .error(R.drawable.stackblur_default)
  154 + .placeholder(R.drawable.stackblur_default)
  155 + .crossFade(300)
  156 + .bitmapTransform(new BlurTransformation(context, 23, 4))
  157 + .into(imageView);
  158 + }
  159 +
  160 + /**
  161 + * 显示本地虚化图片
  162 + *
  163 + * @param context context
  164 + * @param file 本地图片file
  165 + * @param imageView 要显示的imageview
  166 + */
  167 + public static void displayBlurImg(Context context, File file, ImageView imageView) {
  168 + // "23":模糊度;"4":图片缩放4倍后再进行模糊
  169 + Glide.with(context)
  170 + .load(file)
  171 + .error(R.drawable.stackblur_default)
  172 + .placeholder(R.drawable.stackblur_default)
  173 + .crossFade(300)
  174 + .bitmapTransform(new BlurTransformation(context, 23, 4))
  175 + .into(imageView);
  176 + }
  177 +
  178 + /**
  179 + * 显示资源虚化图片
  180 + *
  181 + * @param context context
  182 + * @param resourceId 图片资源id
  183 + * @param imageView 要显示的imageview
  184 + */
  185 + public static void displayBlurImg(Context context, Integer resourceId, ImageView imageView) {
  186 + // "23":模糊度;"4":图片缩放4倍后再进行模糊
  187 + Glide.with(context)
  188 + .load(resourceId)
  189 + .error(R.drawable.stackblur_default)
  190 + .placeholder(R.drawable.stackblur_default)
  191 + .crossFade(300)
  192 + .bitmapTransform(new BlurTransformation(context, 23, 4))
  193 + .into(imageView);
  194 + }
  195 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/FileUtils.java 0 → 100644
@@ -0,0 +1,291 @@ @@ -0,0 +1,291 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.content.ContentResolver;
  4 +import android.content.Context;
  5 +import android.content.Intent;
  6 +import android.database.Cursor;
  7 +import android.graphics.Bitmap;
  8 +import android.net.Uri;
  9 +import android.os.Environment;
  10 +import android.provider.MediaStore;
  11 +import android.text.TextUtils;
  12 +
  13 +import java.io.BufferedInputStream;
  14 +import java.io.BufferedOutputStream;
  15 +import java.io.File;
  16 +import java.io.FileInputStream;
  17 +import java.io.FileNotFoundException;
  18 +import java.io.FileOutputStream;
  19 +import java.io.IOException;
  20 +import java.io.InputStream;
  21 +
  22 +/**
  23 + * Created by Horrarndoo on 2017/8/31.
  24 + * <p>
  25 + * 读取文件工具类
  26 + */
  27 +public class FileUtils {
  28 + private static final String TAG = "FileUtils";
  29 +
  30 + /**
  31 + * Convert byte[] to hex string.将byte转换成int,
  32 + * 然后利用Integer.toHexString(int)来转换成16进制字符串。
  33 + *
  34 + * @param src byte[] data
  35 + * @return hex string
  36 + */
  37 + public static String bytesToHexString(byte[] src) {
  38 + StringBuilder stringBuilder = new StringBuilder("");
  39 + if (src == null || src.length <= 0) {
  40 + return null;
  41 + }
  42 + for (int i = 0; i < src.length; i++) {
  43 + int v = src[i] & 0xFF;
  44 + String hv = Integer.toHexString(v);
  45 + if (hv.length() < 2) {
  46 + stringBuilder.append(0);
  47 + }
  48 + stringBuilder.append(hv);
  49 + }
  50 + return stringBuilder.toString();
  51 + }
  52 +
  53 + /**
  54 + * 根据文件名称和路径,获取sd卡中的文件,以File形式返回byte
  55 + */
  56 + public static File getFile(String fileName, String folder)
  57 + throws IOException {
  58 + String state = Environment.getExternalStorageState();
  59 + if (state.equals(Environment.MEDIA_MOUNTED)) {
  60 + File pathFile = new File(Environment.getExternalStorageDirectory()
  61 + + folder);
  62 + // && !pathFile .isDirectory()
  63 + if (!pathFile.exists()) {
  64 + pathFile.mkdirs();
  65 + }
  66 + File file = new File(pathFile, fileName);
  67 + return file;
  68 + }
  69 + return null;
  70 + }
  71 +
  72 + /**
  73 + * 根据文件名称和路径,获取sd卡中的文件,判断文件是否存在,存在返回true
  74 + */
  75 + public static Boolean checkFile(String fileName, String folder)
  76 + throws IOException {
  77 +
  78 + File targetFile = getFile(fileName, folder);
  79 +
  80 + if (!targetFile.exists()) {
  81 + return false;
  82 + } else {
  83 + return true;
  84 + }
  85 + }
  86 +
  87 + /**
  88 + * 根据Uri返回文件绝对路径
  89 + * 兼容了file:///开头的 和 content://开头的情况
  90 + */
  91 + public static String getRealFilePathFromUri(final Context context, final Uri uri) {
  92 + if (null == uri)
  93 + return null;
  94 + final String scheme = uri.getScheme();
  95 + String data = null;
  96 + if (scheme == null) {
  97 + data = uri.getPath();
  98 + } else if (ContentResolver.SCHEME_FILE.equalsIgnoreCase(scheme)) {
  99 + data = uri.getPath();
  100 + } else if (ContentResolver.SCHEME_CONTENT.equalsIgnoreCase(scheme)) {
  101 + Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore
  102 + .Images.ImageColumns.DATA}, null, null, null);
  103 + if (null != cursor) {
  104 + if (cursor.moveToFirst()) {
  105 + int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
  106 + if (index > -1) {
  107 + data = cursor.getString(index);
  108 + }
  109 + }
  110 + cursor.close();
  111 + }
  112 + }
  113 + return data;
  114 + }
  115 +
  116 + /**
  117 + * 检查文件是否存在
  118 + */
  119 + public static String checkDirPath(String dirPath) {
  120 + if (TextUtils.isEmpty(dirPath)) {
  121 + return "";
  122 + }
  123 + File dir = new File(dirPath);
  124 + if (!dir.exists()) {
  125 + dir.mkdirs();
  126 + }
  127 + return dirPath;
  128 + }
  129 +
  130 + public static void copyFile(File sourcefile, File targetFile) {
  131 + FileInputStream input = null;
  132 + BufferedInputStream inbuff = null;
  133 + FileOutputStream out = null;
  134 + BufferedOutputStream outbuff = null;
  135 +
  136 + try {
  137 +
  138 + input = new FileInputStream(sourcefile);
  139 + inbuff = new BufferedInputStream(input);
  140 +
  141 + out = new FileOutputStream(targetFile);
  142 + outbuff = new BufferedOutputStream(out);
  143 +
  144 + byte[] b = new byte[1024 * 5];
  145 + int len = 0;
  146 + while ((len = inbuff.read(b)) != -1) {
  147 + outbuff.write(b, 0, len);
  148 + }
  149 + outbuff.flush();
  150 + } catch (Exception ex) {
  151 + } finally {
  152 + try {
  153 + if (inbuff != null)
  154 + inbuff.close();
  155 + if (outbuff != null)
  156 + outbuff.close();
  157 + if (out != null)
  158 + out.close();
  159 + if (input != null)
  160 + input.close();
  161 + } catch (Exception ex) {
  162 +
  163 + }
  164 + }
  165 + }
  166 +
  167 + /**
  168 + * 保存图片到本机
  169 + *
  170 + * @param context context
  171 + * @param fileName 文件名
  172 + * @param file file
  173 + * @param saveResultCallback 保存结果callback
  174 + */
  175 + public static void saveImage(final Context context, final String fileName, final File file,
  176 + final SaveResultCallback saveResultCallback) {
  177 + new Thread(new Runnable() {
  178 + @Override
  179 + public void run() {
  180 + File appDir = new File(Environment.getExternalStorageDirectory(), "yizhi");
  181 + if (!appDir.exists()) {
  182 + appDir.mkdir();
  183 + }
  184 + String saveFileName = "yizhi_pic";
  185 + if (fileName.contains(".png") || fileName.contains(".gif")) {
  186 + String fileFormat = fileName.substring(fileName.lastIndexOf("."));
  187 + saveFileName = MD5Utils.getMD5("yizhi_pic" + fileName) + fileFormat;
  188 + } else {
  189 + saveFileName = MD5Utils.getMD5("yizhi_pic" + fileName) + ".png";
  190 + }
  191 + saveFileName = saveFileName.substring(20);//取前20位作为SaveName
  192 + File savefile = new File(appDir, saveFileName);
  193 + try {
  194 + InputStream is = new FileInputStream(file);
  195 + FileOutputStream fos = new FileOutputStream(savefile);
  196 + byte[] buffer = new byte[1024 * 1024];//1M缓冲区
  197 + int count = 0;
  198 + while ((count = is.read(buffer)) > 0) {
  199 + fos.write(buffer, 0, count);
  200 + }
  201 + fos.close();
  202 + is.close();
  203 + saveResultCallback.onSavedSuccess();
  204 + } catch (FileNotFoundException e) {
  205 + saveResultCallback.onSavedFailed();
  206 + e.printStackTrace();
  207 + } catch (IOException e) {
  208 + saveResultCallback.onSavedFailed();
  209 + e.printStackTrace();
  210 + }
  211 + //保存图片后发送广播通知更新数据库
  212 + Uri uri = Uri.fromFile(savefile);
  213 + context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
  214 + }
  215 + }).start();
  216 + }
  217 +
  218 + /**
  219 + * 保存Bitmap到本机
  220 + *
  221 + * @param context context
  222 + * @param fileName bitmap文件名
  223 + * @param bmp bitmap
  224 + * @param saveResultCallback 保存结果callback
  225 + */
  226 + public static void saveBitmap(final Context context, final String fileName, final Bitmap bmp,
  227 + final SaveResultCallback
  228 + saveResultCallback) {
  229 + new Thread(new Runnable() {
  230 + @Override
  231 + public void run() {
  232 + File appDir = new File(Environment.getExternalStorageDirectory(), "yizhi");
  233 + if (!appDir.exists()) {
  234 + appDir.mkdir();
  235 + }
  236 + // SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
  237 + // 设置以当前时间格式为图片名称
  238 + String saveFileName = MD5Utils.getMD5("yizhi_pic" + fileName) + ".png";
  239 + saveFileName = saveFileName.substring(20);//取前20位作为SaveName
  240 + File file = new File(appDir, saveFileName);
  241 + try {
  242 + FileOutputStream fos = new FileOutputStream(file);
  243 + bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
  244 + fos.flush();
  245 + fos.close();
  246 + saveResultCallback.onSavedSuccess();
  247 + } catch (FileNotFoundException e) {
  248 + saveResultCallback.onSavedFailed();
  249 + e.printStackTrace();
  250 + } catch (IOException e) {
  251 + saveResultCallback.onSavedFailed();
  252 + e.printStackTrace();
  253 + }
  254 + //保存图片后发送广播通知更新数据库
  255 + Uri uri = Uri.fromFile(file);
  256 + context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
  257 + }
  258 + }).start();
  259 + }
  260 +
  261 + //保存webview缓存的
  262 + public static String getCache() {
  263 + String cacheFilePath=Environment.getExternalStorageDirectory()+File.separator+"Cache";
  264 + File cacheFile=new File(cacheFilePath);
  265 + if (!cacheFile.exists())cacheFile.mkdirs();
  266 + return cacheFile.toString();
  267 + }
  268 +
  269 + public static boolean webViewCacheIsExit(){
  270 + File file=new File(getCache());
  271 + FileInputStream fileInputStream=null;
  272 + try {
  273 + fileInputStream=new FileInputStream(file);
  274 + if (fileInputStream.available()>0)
  275 + return true;
  276 + } catch (FileNotFoundException e) {
  277 + e.printStackTrace();
  278 + } catch (IOException e) {
  279 + e.printStackTrace();
  280 + }
  281 + return false;
  282 + }
  283 +
  284 + public interface SaveResultCallback {
  285 + void onSavedSuccess();
  286 +
  287 + void onSavedFailed();
  288 + }
  289 +}
  290 +
  291 +
mvpsdk/src/main/java/com/share/mvpsdk/utils/HtmlUtils.java 0 → 100644
@@ -0,0 +1,93 @@ @@ -0,0 +1,93 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import java.util.List;
  4 +
  5 +/**
  6 + * Created by Horrarndoo on 2017/8/31.
  7 + * <p>
  8 + * Html工具类
  9 + */
  10 +public class HtmlUtils {
  11 +
  12 + //css样式,隐藏header
  13 + private static final String HIDE_HEADER_STYLE = "<style>div.headline{display:none;}</style>";
  14 +
  15 + //css style tag,需要格式化
  16 + private static final String NEEDED_FORMAT_CSS_TAG = "<link rel=\"stylesheet\" " +
  17 + "type=\"text/css\" href=\"%s\"/>";
  18 +
  19 + // js script tag,需要格式化
  20 + private static final String NEEDED_FORMAT_JS_TAG = "<script src=\"%s\"></script>";
  21 +
  22 + public static final String MIME_TYPE = "text/html; charset=utf-8";
  23 +
  24 + public static final String ENCODING = "utf-8";
  25 +
  26 + private HtmlUtils() {
  27 +
  28 + }
  29 +
  30 + /**
  31 + * 根据css链接生成Link标签
  32 + *
  33 + * @param url String
  34 + * @return String
  35 + */
  36 + public static String createCssTag(String url) {
  37 +
  38 + return String.format(NEEDED_FORMAT_CSS_TAG, url);
  39 + }
  40 +
  41 + /**
  42 + * 根据多个css链接生成Link标签
  43 + *
  44 + * @param urls List<String>
  45 + * @return String
  46 + */
  47 + public static String createCssTag(List<String> urls) {
  48 +
  49 + final StringBuilder sb = new StringBuilder();
  50 + for (String url : urls) {
  51 + sb.append(createCssTag(url));
  52 + }
  53 + return sb.toString();
  54 + }
  55 +
  56 + /**
  57 + * 根据js链接生成Script标签
  58 + *
  59 + * @param url String
  60 + * @return String
  61 + */
  62 + public static String createJsTag(String url) {
  63 +
  64 + return String.format(NEEDED_FORMAT_JS_TAG, url);
  65 + }
  66 +
  67 + /**
  68 + * 根据多个js链接生成Script标签
  69 + *
  70 + * @param urls List<String>
  71 + * @return String
  72 + */
  73 + public static String createJsTag(List<String> urls) {
  74 +
  75 + final StringBuilder sb = new StringBuilder();
  76 + for (String url : urls) {
  77 + sb.append(createJsTag(url));
  78 + }
  79 + return sb.toString();
  80 + }
  81 +
  82 + /**
  83 + * 根据样式标签,html字符串,js标签
  84 + * 生成完整的HTML文档
  85 + */
  86 +
  87 + public static String createHtmlData(String html, List<String> cssList, List<String> jsList) {
  88 + final String css = HtmlUtils.createCssTag(cssList);
  89 + final String js = HtmlUtils.createJsTag(jsList);
  90 + return css.concat(HIDE_HEADER_STYLE).concat(html).concat(js);
  91 + }
  92 +}
  93 +
mvpsdk/src/main/java/com/share/mvpsdk/utils/HttpUtils.java 0 → 100644
@@ -0,0 +1,76 @@ @@ -0,0 +1,76 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.os.Build;
  4 +import android.support.annotation.NonNull;
  5 +import android.webkit.WebSettings;
  6 +
  7 +import com.orhanobut.logger.Logger;
  8 +
  9 +import java.util.ArrayList;
  10 +import java.util.List;
  11 +import java.util.regex.Matcher;
  12 +import java.util.regex.Pattern;
  13 +
  14 +/**
  15 + * Created by Horrarndoo on 2017/9/18.
  16 + * <p>
  17 + * HttpUtils 主要用于获取UserAgent
  18 + */
  19 +
  20 +public class HttpUtils {
  21 + /**
  22 + * 获取UserAgent
  23 + *
  24 + * @return UserAgent
  25 + */
  26 + @NonNull
  27 + public static String getUserAgent() {
  28 + String userAgent = "";
  29 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
  30 + try {
  31 + userAgent = WebSettings.getDefaultUserAgent(AppUtils.getContext());
  32 + } catch (Exception e) {
  33 + userAgent = System.getProperty("http.agent");
  34 + }
  35 + } else {
  36 + userAgent = System.getProperty("http.agent");
  37 + }
  38 + StringBuffer sb = new StringBuffer();
  39 + for (int i = 0, length = userAgent.length(); i < length; i++) {
  40 + char c = userAgent.charAt(i);
  41 + if (c <= '\u001f' || c >= '\u007f') {
  42 + sb.append(String.format("\\u%04x", (int) c));
  43 + } else {
  44 + sb.append(c);
  45 + }
  46 + }
  47 + return sb.toString();
  48 + }
  49 +
  50 + public static String makeUA() {
  51 + final String ua = Build.BRAND + "/" + Build.MODEL + "/" + Build.VERSION.RELEASE;
  52 + return ua;
  53 + }
  54 +
  55 + public static String[] returnImageUrlsFromHtml(String html) {
  56 + List<String> imageSrcList = new ArrayList<String>();
  57 + Pattern p = Pattern.compile("<img\\b[^>]*\\bsrc\\b\\s*=\\s*('|\")?([^'\"\n\r\f>]+(\\" +
  58 + ".jpg|\\.bmp|\\.eps|\\.gif|\\.mif|\\.miff|\\.png|\\.tif|\\.tiff|\\.svg|\\.wmf|\\" +
  59 + ".jpe|\\.jpeg|\\.dib|\\.ico|\\.tga|\\.cut|\\.pic|\\b)\\b)[^>]*>", Pattern
  60 + .CASE_INSENSITIVE);
  61 + Matcher m = p.matcher(html);
  62 + String quote = null;
  63 + String src = null;
  64 + while (m.find()) {
  65 + quote = m.group(1);
  66 + src = (quote == null || quote.trim().length() == 0) ? m.group(2).split("//s+")[0] : m
  67 + .group(2);
  68 + imageSrcList.add(src);
  69 + }
  70 + if (imageSrcList.size() == 0) {
  71 + Logger.e("资讯中未匹配到图片链接");
  72 + return null;
  73 + }
  74 + return imageSrcList.toArray(new String[imageSrcList.size()]);
  75 + }
  76 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/IOUtils.java 0 → 100644
@@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import java.io.Closeable;
  4 +import java.io.IOException;
  5 +
  6 +/**
  7 + * Created by Horrarndoo on 2017/8/31.
  8 + * <p>
  9 + * IO流工具类
  10 + */
  11 +public class IOUtils {
  12 + /**
  13 + * 关闭流
  14 + */
  15 + public static boolean close(Closeable io) {
  16 + if (io != null) {
  17 + try {
  18 + io.close();
  19 + } catch (IOException e) {
  20 + LogUtils.e(e);
  21 + }
  22 + }
  23 + return true;
  24 + }
  25 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/ImageUtils.java 0 → 100644
@@ -0,0 +1,339 @@ @@ -0,0 +1,339 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.annotation.TargetApi;
  4 +import android.app.Activity;
  5 +import android.content.ContentUris;
  6 +import android.content.ContentValues;
  7 +import android.content.Context;
  8 +import android.content.DialogInterface;
  9 +import android.content.Intent;
  10 +import android.database.Cursor;
  11 +import android.net.Uri;
  12 +import android.os.Build;
  13 +import android.os.Environment;
  14 +import android.provider.DocumentsContract;
  15 +import android.provider.MediaStore;
  16 +import android.support.v7.app.AlertDialog;
  17 +
  18 +import com.bumptech.glide.Glide;
  19 +import com.bumptech.glide.request.FutureTarget;
  20 +
  21 +import io.reactivex.Observable;
  22 +import io.reactivex.ObservableSource;
  23 +import io.reactivex.functions.Function;
  24 +
  25 +/**
  26 + * 图片工具类
  27 + */
  28 +public class ImageUtils {
  29 +
  30 + /**
  31 + * 拍照
  32 + */
  33 + public static final int REQUEST_CODE_FROM_CAMERA = 1 << 10;
  34 +
  35 + /**
  36 + * 相册
  37 + */
  38 + public static final int REQUEST_CODE_FROM_ALBUM = 1 << 12;
  39 +
  40 + /**
  41 + * 裁剪
  42 + */
  43 + public static final int REQUEST_CODE_CROP_IMAGE = 1 << 14;
  44 +
  45 + /**
  46 + * 存放拍照图片的uri地址
  47 + */
  48 + public static Uri imageUriFromCamera;
  49 +
  50 + /**
  51 + * 存放裁剪图片的uri地址
  52 + */
  53 + public static Uri cropImageUri;
  54 +
  55 + /**
  56 + * 显示获取照片不同方式对话框
  57 + */
  58 + public static void showImagePickDialog(final Activity activity) {
  59 + showImagePickDialog(activity, 0);
  60 + }
  61 +
  62 + /**
  63 + * 显示获取照片不同方式对话框
  64 + */
  65 + public static void showImagePickDialog(final Activity activity, final int addRequest) {
  66 + String title = "选择获取图片方式";
  67 + String[] items = new String[]{"拍照", "相册"};
  68 + new AlertDialog.Builder(activity)
  69 + .setTitle(title)
  70 + .setItems(items, new DialogInterface.OnClickListener() {
  71 + @Override
  72 + public void onClick(DialogInterface dialog, int which) {
  73 + dialog.dismiss();
  74 + switch (which) {
  75 + case 0:
  76 + pickImageFromCamera(activity, addRequest);
  77 + break;
  78 + case 1:
  79 + pickImageFromAlbum(activity, addRequest);
  80 + break;
  81 + default:
  82 + break;
  83 + }
  84 + }
  85 + })
  86 + .setNegativeButton("取消", null)
  87 + .show();
  88 + }
  89 +
  90 + /**
  91 + * 打开相机拍照获取图片
  92 + */
  93 + @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
  94 + public static void pickImageFromCamera(final Activity activity, int addRequest) {
  95 + // 先生成一个uri地址用于存放拍照获取的图片
  96 + imageUriFromCamera = createImageUri(activity);
  97 +
  98 + Intent intent = new Intent();
  99 + intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
  100 + intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUriFromCamera);
  101 + activity.startActivityForResult(intent, REQUEST_CODE_FROM_CAMERA + addRequest);
  102 + }
  103 +
  104 + /**
  105 + * 打开相机拍照获取图片
  106 + */
  107 + public static void pickImageFromCamera(final Activity activity) {
  108 + pickImageFromCamera(activity, 0);
  109 + }
  110 +
  111 + /**
  112 + * 打开本地相册选取图片
  113 + */
  114 + @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
  115 + public static void pickImageFromAlbum(final Activity activity, int addRequest) {
  116 + Intent intent = new Intent();
  117 + intent.setAction(Intent.ACTION_GET_CONTENT);
  118 + intent.setType("image/*");
  119 + activity.startActivityForResult(intent, REQUEST_CODE_FROM_ALBUM + addRequest);
  120 + }
  121 +
  122 + /**
  123 + * 打开本地相册选取图片
  124 + */
  125 + public static void pickImageFromAlbum(final Activity activity) {
  126 + pickImageFromAlbum(activity, 0);
  127 + }
  128 +
  129 + /**
  130 + * 压缩图片
  131 + *
  132 + * @param context context
  133 + * @param uri 图片uri
  134 + * @param reqW 上传图片需要压缩的宽度
  135 + * @param reqH 上传图片需要压缩的高度
  136 + * @return 上传成功回调
  137 + */
  138 + public static Observable<byte[]> compressImage(final Context context,
  139 + Uri uri,
  140 + final int reqW,
  141 + final int reqH) {
  142 + // 先从本地获取图片,利用Glide压缩图片后获取byte[]
  143 + return Observable.just(uri)
  144 + .flatMap(new Function<Uri, ObservableSource<byte[]>>() {
  145 + @Override
  146 + public ObservableSource<byte[]> apply(Uri uri) throws Exception {
  147 + // 在work线程中,同步压缩图片,然后Observable返回
  148 + // 即将Glide的回调封装成RxJava的Observable
  149 + FutureTarget<byte[]> future = Glide.with(context)
  150 + .load(uri)
  151 + .asBitmap()
  152 + .toBytes()
  153 + .into(reqW, reqH);
  154 +
  155 + byte[] bytes;
  156 + try {
  157 + bytes = future.get();
  158 + } catch (Exception e) {
  159 + // 获取失败时,抛出runtime异常
  160 + // 该异常会被Subscriber捕捉,进onError
  161 + throw new RuntimeException(e);
  162 + }
  163 + return Observable.just(bytes);
  164 + }
  165 + });
  166 + }
  167 +
  168 + /**
  169 + * 图片裁剪
  170 + */
  171 + public static void cropImage(Activity activity, Uri srcUri) {
  172 + cropImageUri = createImageUri(activity);
  173 +
  174 + Intent intent = new Intent("com.android.camera.action.CROP");
  175 + intent.setDataAndType(srcUri, "image/*");
  176 + intent.putExtra("crop", "true");
  177 +
  178 + ////////////////////////////////////////////////////////////////
  179 + // 1.宽高和比例都不设置时,裁剪框可以自行调整(比例和大小都可以随意调整)
  180 + ////////////////////////////////////////////////////////////////
  181 + // 2.只设置裁剪框宽高比(aspect)后,裁剪框比例固定不可调整,只能调整大小
  182 + /////////////////////////////////
  183 + // 3.裁剪后生成图片宽高(output)的设置和裁剪框无关,只决定最终生成图片大小
  184 + ////////////////////////////////////////////////////////////////
  185 + // 4.裁剪框宽高比例(aspect)可以和裁剪后生成图片比例(output)不同,此时,
  186 + // 会以裁剪框的宽为准,按照裁剪宽高比例生成一个图片,该图和框选部分可能不同,
  187 + // 不同的情况可能是截取框选的一部分,也可能超出框选部分,向下延伸补足
  188 + ////////////////////////////////////////////////////////////////
  189 +
  190 + // aspectX aspectY 是裁剪框宽高的比例
  191 + intent.putExtra("aspectX", 1);
  192 + intent.putExtra("aspectY", 1);
  193 + // outputX outputY 是裁剪后生成图片的宽高
  194 + // intent.putExtra("outputX", 300);
  195 + // intent.putExtra("outputY", 100);
  196 +
  197 + // return-data为true时,会直接返回bitmap数据,但是大图裁剪时会出现OOM,推荐下面为false时的方式
  198 + // return-data为false时,不会返回bitmap,但需要指定一个MediaStore.EXTRA_OUTPUT保存图片uri
  199 + intent.putExtra("return-data", false);
  200 + intent.putExtra(MediaStore.EXTRA_OUTPUT, cropImageUri);
  201 +
  202 + activity.startActivityForResult(intent, REQUEST_CODE_CROP_IMAGE);
  203 + }
  204 +
  205 + /**
  206 + * 创建一条图片uri,用于保存拍照后的照片
  207 + */
  208 + private static Uri createImageUri(Context context) {
  209 + String name = "boreImg" + System.currentTimeMillis();
  210 + ContentValues values = new ContentValues();
  211 + values.put(MediaStore.Images.Media.TITLE, name);
  212 + values.put(MediaStore.Images.Media.DISPLAY_NAME, name + ".jpeg");
  213 + values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
  214 + Uri uri = context.getContentResolver().insert(MediaStore.Images.Media
  215 + .EXTERNAL_CONTENT_URI, values);
  216 + return uri;
  217 + }
  218 +
  219 + /**
  220 + * 删除一条图片
  221 + */
  222 + public static void deleteImageUri(Context context, Uri uri) {
  223 + context.getContentResolver().delete(uri, null, null);
  224 + }
  225 +
  226 + /**
  227 + * 用第三方应用app打开图片
  228 + */
  229 + public static void openImageByOtherApp(Context context, Uri imageUri) {
  230 + Intent intent = new Intent();
  231 + intent.setAction(Intent.ACTION_VIEW);
  232 + intent.setDataAndType(imageUri, "image/*");
  233 + context.startActivity(intent);
  234 + }
  235 +
  236 + /**
  237 + * 根据Uri获取图片绝对路径,解决Android4.4以上版本Uri转换
  238 + */
  239 + public static String getImageAbsolutePath19(Context context, Uri imageUri) {
  240 + if (context == null || imageUri == null)
  241 + return null;
  242 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
  243 + && DocumentsContract.isDocumentUri(context, imageUri)) {
  244 + if (isExternalStorageDocument(imageUri)) {
  245 + String docId = DocumentsContract.getDocumentId(imageUri);
  246 + String[] split = docId.split(":");
  247 + String type = split[0];
  248 + if ("primary".equalsIgnoreCase(type)) {
  249 + return Environment.getExternalStorageDirectory() + "/" + split[1];
  250 + }
  251 + } else if (isDownloadsDocument(imageUri)) {
  252 + String id = DocumentsContract.getDocumentId(imageUri);
  253 + Uri contentUri = ContentUris.withAppendedId(Uri.parse
  254 + ("content://downloads/public_downloads"), Long.valueOf(id));
  255 + return getDataColumn(context, contentUri, null, null);
  256 + } else if (isMediaDocument(imageUri)) {
  257 + String docId = DocumentsContract.getDocumentId(imageUri);
  258 + String[] split = docId.split(":");
  259 + String type = split[0];
  260 + Uri contentUri = null;
  261 + if ("image".equals(type)) {
  262 + contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
  263 + } else if ("video".equals(type)) {
  264 + contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
  265 + } else if ("audio".equals(type)) {
  266 + contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
  267 + }
  268 + String selection = MediaStore.Images.Media._ID + "=?";
  269 + String[] selectionArgs = new String[]{split[1]};
  270 + return getDataColumn(context, contentUri, selection, selectionArgs);
  271 + }
  272 + }
  273 +
  274 + // MediaStore (and general)
  275 + if ("content".equalsIgnoreCase(imageUri.getScheme())) {
  276 + // Return the remote address
  277 + if (isGooglePhotosUri(imageUri))
  278 + return imageUri.getLastPathSegment();
  279 + return getDataColumn(context, imageUri, null, null);
  280 + }
  281 + // File
  282 + else if ("file".equalsIgnoreCase(imageUri.getScheme())) {
  283 + return imageUri.getPath();
  284 + }
  285 + return null;
  286 + }
  287 +
  288 + private static String getDataColumn(Context context, Uri uri, String selection, String[]
  289 + selectionArgs) {
  290 + Cursor cursor = null;
  291 + String column = MediaStore.Images.Media.DATA;
  292 + String[] projection = {column};
  293 + try {
  294 + cursor = context.getContentResolver().query(uri, projection, selection,
  295 + selectionArgs, null);
  296 + if (cursor != null && cursor.moveToFirst()) {
  297 + int index = cursor.getColumnIndexOrThrow(column);
  298 + return cursor.getString(index);
  299 + }
  300 + } finally {
  301 + if (cursor != null)
  302 + cursor.close();
  303 + }
  304 + return null;
  305 + }
  306 +
  307 + /**
  308 + * @param uri The Uri to check.
  309 + * @return Whether the Uri authority is ExternalStorageProvider.
  310 + */
  311 + private static boolean isExternalStorageDocument(Uri uri) {
  312 + return "com.android.externalstorage.documents".equals(uri.getAuthority());
  313 + }
  314 +
  315 + /**
  316 + * @param uri The Uri to check.
  317 + * @return Whether the Uri authority is DownloadsProvider.
  318 + */
  319 + private static boolean isDownloadsDocument(Uri uri) {
  320 + return "com.android.providers.downloads.documents".equals(uri.getAuthority());
  321 + }
  322 +
  323 + /**
  324 + * @param uri The Uri to check.
  325 + * @return Whether the Uri authority is MediaProvider.
  326 + */
  327 + private static boolean isMediaDocument(Uri uri) {
  328 + return "com.android.providers.media.documents".equals(uri.getAuthority());
  329 + }
  330 +
  331 + /**
  332 + * @param uri The Uri to check.
  333 + * @return Whether the Uri authority is Google Photos.
  334 + */
  335 + private static boolean isGooglePhotosUri(Uri uri) {
  336 + return "com.google.android.apps.photos.content".equals(uri.getAuthority());
  337 + }
  338 +
  339 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/JsonUtils.java 0 → 100644
@@ -0,0 +1,65 @@ @@ -0,0 +1,65 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import com.google.gson.Gson;
  4 +import com.google.gson.JsonObject;
  5 +import com.google.gson.JsonSyntaxException;
  6 +
  7 +import java.lang.reflect.Type;
  8 +
  9 +/**
  10 + * Created by Horrarndoo on 2017/9/20.
  11 + * <p>
  12 + * Json转换工具类
  13 + */
  14 +public class JsonUtils {
  15 +
  16 + private static Gson mGson = new Gson();
  17 +
  18 + /**
  19 + * 将对象准换为json字符串
  20 + *
  21 + * @param object
  22 + * @param <T>
  23 + * @return
  24 + */
  25 + public static <T> String serialize(T object) {
  26 + return mGson.toJson(object);
  27 + }
  28 +
  29 + /**
  30 + * 将json字符串转换为对象
  31 + *
  32 + * @param json
  33 + * @param clz
  34 + * @param <T>
  35 + * @return
  36 + */
  37 + public static <T> T deserialize(String json, Class<T> clz) throws JsonSyntaxException {
  38 + return mGson.fromJson(json, clz);
  39 + }
  40 +
  41 + /**
  42 + * 将json对象转换为实体对象
  43 + *
  44 + * @param json
  45 + * @param clz
  46 + * @param <T>
  47 + * @return
  48 + * @throws JsonSyntaxException
  49 + */
  50 + public static <T> T deserialize(JsonObject json, Class<T> clz) throws JsonSyntaxException {
  51 + return mGson.fromJson(json, clz);
  52 + }
  53 +
  54 + /**
  55 + * 将json字符串转换为对象
  56 + *
  57 + * @param json
  58 + * @param type
  59 + * @param <T>
  60 + * @return
  61 + */
  62 + public static <T> T deserialize(String json, Type type) throws JsonSyntaxException {
  63 + return mGson.fromJson(json, type);
  64 + }
  65 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/LogUtils.java 0 → 100644
@@ -0,0 +1,168 @@ @@ -0,0 +1,168 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.util.Log;
  4 +
  5 +
  6 +/**
  7 + * Created by Horrarndoo on 2017/4/5.
  8 + * <p>
  9 + * Log工具类
  10 + */
  11 +public class LogUtils {
  12 + /**
  13 + * 日志输出级别NONE
  14 + */
  15 + public static final int LEVEL_NONE = 0;
  16 + /**
  17 + * 日志输出级别E
  18 + */
  19 + public static final int LEVEL_ERROR = 1;
  20 + /**
  21 + * 日志输出级别W
  22 + */
  23 + public static final int LEVEL_WARN = 2;
  24 + /**
  25 + * 日志输出级别I
  26 + */
  27 + public static final int LEVEL_INFO = 3;
  28 + /**
  29 + * 日志输出级别D
  30 + */
  31 + public static final int LEVEL_DEBUG = 4;
  32 + /**
  33 + * 日志输出级别V
  34 + */
  35 + public static final int LEVEL_VERBOSE = 5;
  36 +
  37 + /**
  38 + * 日志输出时的TAG
  39 + */
  40 + private static String mTag = "LogUtils";
  41 +
  42 + /**
  43 + * 是否允许输出log
  44 + */
  45 + private static int mDebuggable = LEVEL_VERBOSE;
  46 +
  47 + /**
  48 + * 设置调试Log开关
  49 + *
  50 + * @param isEnable 是否允许log
  51 + */
  52 + public static void setDebuggable(boolean isEnable) {
  53 + mDebuggable = isEnable ? LEVEL_VERBOSE : LEVEL_NONE;
  54 + }
  55 +
  56 + /**
  57 + * 以级别为 d 的形式输出LOG
  58 + */
  59 + public static void v(String msg) {
  60 + if (mDebuggable >= LEVEL_VERBOSE) {
  61 + Log.v(mTag, msg);
  62 + }
  63 + }
  64 +
  65 + /**
  66 + * 以级别为 d 的形式输出LOG
  67 + */
  68 + public static void d(String msg) {
  69 + if (mDebuggable >= LEVEL_DEBUG) {
  70 + Log.d(mTag, msg);
  71 + }
  72 + }
  73 +
  74 + /**
  75 + * 以级别为 i 的形式输出LOG
  76 + */
  77 + public static void i(String msg) {
  78 + if (mDebuggable >= LEVEL_INFO) {
  79 + Log.i(mTag, msg);
  80 + }
  81 + }
  82 +
  83 + /**
  84 + * 以级别为 w 的形式输出LOG
  85 + */
  86 + public static void w(String msg) {
  87 + if (mDebuggable >= LEVEL_WARN) {
  88 + Log.w(mTag, msg);
  89 + }
  90 + }
  91 +
  92 + /**
  93 + * 以级别为 e 的形式输出LOG
  94 + */
  95 + public static void e(String msg) {
  96 + if (mDebuggable >= LEVEL_ERROR) {
  97 + Log.e(mTag, msg);
  98 + }
  99 + }
  100 +
  101 + /**
  102 + * 以级别为 w 的形式输出Throwable
  103 + */
  104 + public static void w(Throwable tr) {
  105 + w("", tr);
  106 + }
  107 +
  108 + /**
  109 + * 以级别为 w 的形式输出LOG信息和Throwable
  110 + */
  111 + public static void w(String msg, Throwable tr) {
  112 + Log.w(mTag, msg, tr);
  113 + }
  114 +
  115 + /**
  116 + * 以级别为 e 的形式输出Throwable
  117 + */
  118 + public static void e(Throwable tr) {
  119 + e("", tr);
  120 + }
  121 +
  122 + /**
  123 + * 以级别为 e 的形式输出LOG信息和Throwable
  124 + */
  125 + public static void e(String msg, Throwable tr) {
  126 + if (mDebuggable >= LEVEL_ERROR && null != msg) {
  127 + Log.e(mTag, msg, tr);
  128 + }
  129 + }
  130 +
  131 + private static int originStackIndex = 2;
  132 +
  133 + /**
  134 + * 获取当前方法所在的文件名
  135 + *
  136 + * @return 当前方法所在的文件名
  137 + */
  138 + public static String getFileName() {
  139 + return Thread.currentThread().getStackTrace()[originStackIndex].getFileName();
  140 + }
  141 +
  142 + /**
  143 + * 获取当前方法所在的Class名
  144 + *
  145 + * @return 当前方法所在的Class名
  146 + */
  147 + public static String getClassName() {
  148 + return Thread.currentThread().getStackTrace()[originStackIndex].getClassName();
  149 + }
  150 +
  151 + /**
  152 + * 获取当前方法名
  153 + *
  154 + * @return 当前方法名
  155 + */
  156 + public static String getMethodName() {
  157 + return Thread.currentThread().getStackTrace()[originStackIndex].getMethodName();
  158 + }
  159 +
  160 + /**
  161 + * 获取当前代码执行处行数
  162 + *
  163 + * @return 当前代码执行处行数
  164 + */
  165 + public static int getLineNumber() {
  166 + return Thread.currentThread().getStackTrace()[originStackIndex].getLineNumber();
  167 + }
  168 +}
0 \ No newline at end of file 169 \ No newline at end of file
mvpsdk/src/main/java/com/share/mvpsdk/utils/MD5Utils.java 0 → 100644
@@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import java.security.MessageDigest;
  4 +
  5 +/**
  6 + * Created by Horrarndoo on 2017/4/5.
  7 + * <p>
  8 + * MD5加密工具类
  9 + */
  10 +public class MD5Utils {
  11 + /*
  12 + * MD5加密,32位
  13 + */
  14 + public static String getMD5(String str) {
  15 + MessageDigest md5 = null;
  16 + try {
  17 + md5 = MessageDigest.getInstance("MD5");
  18 + } catch (Exception e) {
  19 + e.printStackTrace();
  20 + return "";
  21 + }
  22 + char[] charArray = str.toCharArray();
  23 + byte[] byteArray = new byte[charArray.length];
  24 + for (int i = 0; i < charArray.length; i++) {
  25 + byteArray[i] = (byte) charArray[i];
  26 + }
  27 + byte[] md5Bytes = md5.digest(byteArray);
  28 + StringBuffer hexValue = new StringBuffer();
  29 + for (int i = 0; i < md5Bytes.length; i++) {
  30 + int val = ((int) md5Bytes[i]) & 0xff;
  31 + if (val < 16) {
  32 + hexValue.append("0");
  33 + }
  34 + hexValue.append(Integer.toHexString(val));
  35 + }
  36 + return hexValue.toString();
  37 + }
  38 +}
0 \ No newline at end of file 39 \ No newline at end of file
mvpsdk/src/main/java/com/share/mvpsdk/utils/NavigationUtils.java 0 → 100644
@@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.support.design.internal.NavigationMenuView;
  4 +import android.support.design.widget.NavigationView;
  5 +
  6 +/**
  7 + * Created by Horrarndoo on 2017/12/12.
  8 + * <p>
  9 + * NavigationView utils
  10 + */
  11 +
  12 +public class NavigationUtils {
  13 +
  14 + public static void disableNavigationViewScrollbars(NavigationView navigationView) {
  15 + if (navigationView != null) {
  16 + NavigationMenuView navigationMenuView = (NavigationMenuView) navigationView
  17 + .getChildAt(0);
  18 + if (navigationMenuView != null) {
  19 + navigationMenuView.setVerticalScrollBarEnabled(false);
  20 + }
  21 + }
  22 + }
  23 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/NetworkConnectionUtils.java 0 → 100644
@@ -0,0 +1,236 @@ @@ -0,0 +1,236 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.app.Activity;
  4 +import android.content.ComponentName;
  5 +import android.content.Context;
  6 +import android.content.Intent;
  7 +import android.net.ConnectivityManager;
  8 +import android.net.NetworkInfo;
  9 +import android.net.wifi.ScanResult;
  10 +import android.net.wifi.WifiConfiguration;
  11 +import android.net.wifi.WifiConfiguration.KeyMgmt;
  12 +import android.net.wifi.WifiManager;
  13 +import android.os.Build;
  14 +
  15 +import java.io.IOException;
  16 +import java.util.List;
  17 +
  18 +import static com.share.mvpsdk.utils.LogUtils.e;
  19 +
  20 +/**
  21 + * Created by Horrarndoo on 2017/8/31.
  22 + * <p>
  23 + * Wifi连接工具类
  24 + */
  25 +public class NetworkConnectionUtils {
  26 + private final static String TAG = "NetworkConnectionUtils";
  27 +
  28 + public NetworkConnectionUtils() {
  29 + }
  30 +
  31 + /**
  32 + * 连接指定
  33 + *
  34 + * @param manager
  35 + * @param wifiSSID
  36 + * @return
  37 + */
  38 + public static boolean connectToSocketWifi(WifiManager manager, String wifiSSID) {
  39 + LogUtils.i("要连接的socket wifi====>" + wifiSSID);
  40 + WifiConfiguration wifiConfiguration = new WifiConfiguration();
  41 + wifiConfiguration.SSID = "\"" + wifiSSID + "\"";
  42 + wifiConfiguration.allowedKeyManagement.set(KeyMgmt.NONE);
  43 + wifiConfiguration.wepKeys[0] = "\"" + "\""; //小米手机MIUI7/华为EMUI4.1 需要webKey
  44 +
  45 + int networkId = manager.addNetwork(wifiConfiguration);
  46 +
  47 + if (networkId != -1) {
  48 + manager.enableNetwork(networkId, true);
  49 + e("连接设备成功");
  50 + return true;
  51 + } else {
  52 + e("第一次连接失败,尝试第二次。");
  53 + WifiConfiguration wifiConfiguration2 = new WifiConfiguration();
  54 + wifiConfiguration2.SSID = "\"" + wifiSSID + "\"";
  55 + //wifiConfiguration.wepKeys[0] = "\"" + "\"";//去掉webKey //小米手机MIUI8不能有webKey
  56 + wifiConfiguration2.allowedKeyManagement.set(KeyMgmt.NONE);
  57 + networkId = manager.addNetwork(wifiConfiguration2);
  58 + if (networkId != -1) {
  59 + manager.enableNetwork(networkId, true);
  60 + e("连接设备成功");
  61 + return true;
  62 + }
  63 + e("连接设备失败");
  64 + }
  65 + return false;
  66 + }
  67 +
  68 + /**
  69 + * 获取要连接的wifi节点各个配置选项的加密类型
  70 + *
  71 + * @param ssid
  72 + * @return wifiConfiguration
  73 + */
  74 + public static WifiConfiguration getWifiConfiguration(WifiManager manager, String ssid, String
  75 + password) {
  76 + WifiConfiguration wifiConfiguration = new WifiConfiguration();
  77 + wifiConfiguration.SSID = "\"" + ssid + "\"";
  78 +
  79 + List<ScanResult> list = manager.getScanResults();
  80 + for (ScanResult scResult : list) {
  81 + if (ssid.equals(scResult.SSID)) {
  82 + String capabilities = scResult.capabilities;
  83 + LogUtils.i("capabilities=" + capabilities);
  84 + if (capabilities.contains("WEP") || capabilities.contains("wep")) {
  85 + wifiConfiguration.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
  86 + wifiConfiguration.preSharedKey = "\"" + password + "\"";
  87 + LogUtils.i("wep");
  88 + } else if (capabilities.contains("WPA") || capabilities.contains("wpa")) {
  89 + wifiConfiguration.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
  90 + wifiConfiguration.preSharedKey = "\"" + password + "\"";
  91 + LogUtils.i("wpa");
  92 + } else {
  93 + wifiConfiguration.allowedKeyManagement.set(KeyMgmt.NONE);
  94 + LogUtils.i("none");
  95 + }
  96 + }
  97 + }
  98 + return wifiConfiguration;
  99 + }
  100 +
  101 + /**
  102 + * 给温控器成功发送联网命令后,连接温控器连接的wifi节点
  103 + *
  104 + * @param context 上下文对象
  105 + * @param ssid ssid
  106 + * @param password 密码
  107 + */
  108 + public static void connectWifiSSID(Context context, WifiManager manager, String ssid, String
  109 + password) {
  110 + e("reSetNetwork----------连接设备连入的路由---" + ssid);
  111 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  112 + e("当前手机系统>=Android6.0,采取兼容模式");
  113 + new WifiAutoConnectManager(manager).connect(ssid, password, WifiAutoConnectManager
  114 + .getCipherType(context, ssid));
  115 + } else {
  116 + int networkId = manager.addNetwork(getWifiConfiguration(manager, ssid, password));
  117 + if (networkId != -1) {
  118 + manager.enableNetwork(networkId, true);
  119 + }
  120 + }
  121 + }
  122 +
  123 + /**
  124 + * 格式化RouterSSID
  125 + *
  126 + * @param strRouterSSID 要格式化的当前连接的路由ssid
  127 + * @return 去除"\"后的RouterSSID字符串
  128 + */
  129 + public static String formatRouterSSID(String strRouterSSID) {
  130 + //e("formate routerSSID before---" + strRouterSSID);
  131 + if (strRouterSSID.contains("\"")) {
  132 + strRouterSSID = strRouterSSID.replaceAll("\"", "");
  133 + //e("formate routerSSID after---" + strRouterSSID);
  134 + }
  135 + return strRouterSSID;
  136 + }
  137 +
  138 + /**
  139 + * Ping
  140 + * 用于确定手机是否已经连接上指定设备ip地址
  141 + */
  142 + public static boolean pingTest(String IPOrDomainName) {
  143 +
  144 + boolean isSuccess = false;
  145 + int status;
  146 + String result = "failed";
  147 + Process p;
  148 + try {
  149 + p = Runtime.getRuntime().exec("ping -c 1 " + IPOrDomainName);//
  150 + // m_strForNetAddress是输入的网址或者Ip地址
  151 + status = p.waitFor();// status 只能获取是否成功,无法获取更多的信息
  152 +
  153 + if (status == 0) {
  154 + result = "success";
  155 + isSuccess = true;
  156 + }
  157 +
  158 + } catch (IOException | InterruptedException e) {
  159 + e(e);
  160 + }
  161 + LogUtils.d("Ping result = " + result);
  162 + return isSuccess;
  163 + }
  164 +
  165 + /**
  166 + * 判断网络是否连接
  167 + */
  168 + public static boolean isConnected(Context context) {
  169 + ConnectivityManager cm = (ConnectivityManager)
  170 + context.getSystemService(Context.CONNECTIVITY_SERVICE);
  171 +
  172 + if (null == cm) {
  173 + return false;
  174 + }
  175 +
  176 + NetworkInfo info = cm.getActiveNetworkInfo();
  177 + if (null != info && info.isConnected()) {
  178 + if (info.getState() == NetworkInfo.State.CONNECTED) {
  179 + return true;
  180 + }
  181 + }
  182 + return false;
  183 + }
  184 +
  185 + /**
  186 + * 判断是否有网络
  187 + *
  188 + * @return 返回值
  189 + */
  190 + public static boolean isNetworkConnected(Context context) {
  191 + if (context != null) {
  192 + ConnectivityManager mConnectivityManager = (ConnectivityManager) context
  193 + .getSystemService(Context.CONNECTIVITY_SERVICE);
  194 + NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
  195 +
  196 + if (mNetworkInfo != null) {
  197 + return mNetworkInfo.isAvailable();
  198 + }
  199 + }
  200 + return false;
  201 + }
  202 +
  203 + /**
  204 + * 判断是否是wifi连接
  205 + */
  206 + public static boolean isWifi(Context context) {
  207 + ConnectivityManager cm = (ConnectivityManager)
  208 + context.getSystemService(Context.CONNECTIVITY_SERVICE);
  209 +
  210 + if (null == cm) {
  211 + return false;
  212 + }
  213 +
  214 + NetworkInfo info = cm.getActiveNetworkInfo();
  215 + if (null != info) {
  216 + if (info.getType() == ConnectivityManager.TYPE_WIFI) {
  217 + return true;
  218 + }
  219 + }
  220 + return false;
  221 +
  222 + }
  223 +
  224 +
  225 + /**
  226 + * 打开网络设置界面
  227 + */
  228 + public static void openSetting(Activity activity, int requestCode) {
  229 + Intent intent = new Intent("/");
  230 + ComponentName cm = new ComponentName("com.android.settings",
  231 + "com.android.settings.WirelessSettings");
  232 + intent.setComponent(cm);
  233 + intent.setAction(Intent.ACTION_VIEW);
  234 + activity.startActivityForResult(intent, requestCode);
  235 + }
  236 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/OkHttpExceptionUtil.java 0 → 100644
@@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.support.annotation.NonNull;
  4 +
  5 +import org.json.JSONObject;
  6 +
  7 +import okhttp3.ResponseBody;
  8 +import retrofit2.HttpException;
  9 +import retrofit2.Response;
  10 +
  11 +/**
  12 + * Created by 10501 on 2017/7/18.
  13 + */
  14 +
  15 +public class OkHttpExceptionUtil {
  16 + public static void handOkHttpException(@NonNull HttpException e){
  17 + Response response = e.response();
  18 + if (response==null)return;
  19 + ResponseBody responseBody = response.errorBody();
  20 + if (responseBody==null)return;
  21 + try {
  22 + JSONObject json = new JSONObject(responseBody.string());
  23 + ToastUtils.showToast(json.optString("message")+"json="+json);
  24 + } catch (Exception e1) {
  25 + e1.printStackTrace();
  26 + }
  27 + }
  28 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/PermissionUtils.java 0 → 100644
@@ -0,0 +1,323 @@ @@ -0,0 +1,323 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.Manifest;
  4 +import android.app.Activity;
  5 +import android.app.AlertDialog;
  6 +import android.content.DialogInterface;
  7 +import android.content.Intent;
  8 +import android.content.pm.PackageManager;
  9 +import android.net.Uri;
  10 +import android.provider.Settings;
  11 +import android.support.annotation.NonNull;
  12 +import android.support.v4.app.ActivityCompat;
  13 +import android.util.Log;
  14 +import android.widget.Toast;
  15 +
  16 +
  17 +import com.share.mvpsdk.R;
  18 +
  19 +import java.util.ArrayList;
  20 +import java.util.HashMap;
  21 +import java.util.List;
  22 +import java.util.Map;
  23 +
  24 +/**
  25 + * Created by ToaHanDong on 2017/11/3.
  26 + */
  27 +
  28 +public class PermissionUtils {
  29 + private static final String TAG = PermissionUtils.class.getSimpleName();
  30 + public static final int CODE_RECORD_AUDIO = 0;
  31 + public static final int CODE_GET_ACCOUNTS = 1;
  32 + public static final int CODE_READ_PHONE_STATE = 2;
  33 + public static final int CODE_CALL_PHONE = 3;
  34 + public static final int CODE_CAMERA = 4;
  35 + public static final int CODE_ACCESS_FINE_LOCATION = 5;
  36 + public static final int CODE_ACCESS_COARSE_LOCATION = 6;
  37 + public static final int CODE_READ_EXTERNAL_STORAGE = 7;
  38 + public static final int CODE_WRITE_EXTERNAL_STORAGE = 8;
  39 + public static final int CODE_MULTI_PERMISSION = 100;
  40 +
  41 + //com.huawei.permission.sec.PERMISSION_MDM_SDCARD
  42 +// public static final String PERMISSION_MDM_SDCARD = "PERMISSION_MDM_SDCARD";
  43 + public static final String PERMISSION_RECORD_AUDIO = Manifest.permission.RECORD_AUDIO;
  44 + public static final String PERMISSION_GET_ACCOUNTS = Manifest.permission.GET_ACCOUNTS;
  45 + public static final String PERMISSION_READ_PHONE_STATE = Manifest.permission.READ_PHONE_STATE;
  46 + public static final String PERMISSION_CALL_PHONE = Manifest.permission.CALL_PHONE;
  47 + public static final String PERMISSION_CAMERA = Manifest.permission.CAMERA;
  48 + public static final String PERMISSION_ACCESS_FINE_LOCATION = Manifest.permission.ACCESS_FINE_LOCATION;
  49 + public static final String PERMISSION_ACCESS_COARSE_LOCATION = Manifest.permission.ACCESS_COARSE_LOCATION;
  50 + public static final String PERMISSION_READ_EXTERNAL_STORAGE = Manifest.permission.READ_EXTERNAL_STORAGE;
  51 + public static final String PERMISSION_WRITE_EXTERNAL_STORAGE = Manifest.permission.WRITE_EXTERNAL_STORAGE;
  52 +
  53 + private static final String[] requestPermissions = {
  54 + PERMISSION_RECORD_AUDIO,
  55 + PERMISSION_GET_ACCOUNTS,
  56 + PERMISSION_READ_PHONE_STATE,
  57 + PERMISSION_CALL_PHONE,
  58 + PERMISSION_CAMERA,
  59 + PERMISSION_ACCESS_FINE_LOCATION,
  60 + PERMISSION_ACCESS_COARSE_LOCATION,
  61 + PERMISSION_READ_EXTERNAL_STORAGE,
  62 + PERMISSION_WRITE_EXTERNAL_STORAGE
  63 +// PERMISSION_MDM_SDCARD
  64 + };
  65 +
  66 + public interface PermissionGrant {
  67 + void onPermissionGranted(int requestCode);
  68 + }
  69 +
  70 + /**
  71 + * Requests permission.
  72 + *
  73 + * @param activity
  74 + * @param requestCode request code, e.g. if you need request CAMERA permission,parameters is PermissionUtils.CODE_CAMERA
  75 + */
  76 + public static void requestPermission(final Activity activity, final int requestCode, PermissionGrant permissionGrant) {
  77 + if (activity == null) {
  78 + return;
  79 + }
  80 +
  81 + Log.i(TAG, "requestPermission requestCode:" + requestCode);
  82 + if (requestCode < 0 || requestCode >= requestPermissions.length) {
  83 + Log.w(TAG, "requestPermission illegal requestCode:" + requestCode);
  84 + return;
  85 + }
  86 +
  87 + final String requestPermission = requestPermissions[requestCode];
  88 +
  89 + //如果是6.0以下的手机,ActivityCompat.checkSelfPermission()会始终等于PERMISSION_GRANTED,
  90 + // 但是,如果用户关闭了你申请的权限,ActivityCompat.checkSelfPermission(),会导致程序崩溃(java.lang.RuntimeException: Unknown exception code: 1 msg null),
  91 + // 你可以使用try{}catch(){},处理异常,也可以在这个地方,低于23就什么都不做,
  92 + // 个人建议try{}catch(){}单独处理,提示用户开启权限。
  93 +// if (Build.VERSION.SDK_INT < 23) {
  94 +// return;
  95 +// }
  96 +
  97 + int checkSelfPermission;
  98 + try {
  99 + checkSelfPermission = ActivityCompat.checkSelfPermission(activity, requestPermission);
  100 + } catch (RuntimeException e) {
  101 +// Toast.makeText(activity, "please open this permission", Toast.LENGTH_SHORT)
  102 +// .show();
  103 + Log.e(TAG, "RuntimeException:" + e.getMessage());
  104 + return;
  105 + }
  106 +
  107 + if (checkSelfPermission != PackageManager.PERMISSION_GRANTED) {
  108 + Log.i(TAG, "ActivityCompat.checkSelfPermission != PackageManager.PERMISSION_GRANTED");
  109 +
  110 +
  111 + if (ActivityCompat.shouldShowRequestPermissionRationale(activity, requestPermission)) {
  112 + Log.i(TAG, "requestPermission shouldShowRequestPermissionRationale");
  113 + shouldShowRationale(activity, requestCode, requestPermission);
  114 +
  115 + } else {
  116 + Log.d(TAG, "requestCameraPermission else");
  117 + ActivityCompat.requestPermissions(activity, new String[]{requestPermission}, requestCode);
  118 + }
  119 +
  120 + } else {
  121 + Log.d(TAG, "ActivityCompat.checkSelfPermission ==== PackageManager.PERMISSION_GRANTED");
  122 +// Toast.makeText(activity, "opened:" + requestPermissions[requestCode], Toast.LENGTH_SHORT).show();
  123 + permissionGrant.onPermissionGranted(requestCode);
  124 + }
  125 + }
  126 +
  127 + private static void requestMultiResult(Activity activity, String[] permissions, int[] grantResults, PermissionGrant permissionGrant) {
  128 +
  129 + if (activity == null) {
  130 + return;
  131 + }
  132 +
  133 + //TODO
  134 + Log.d(TAG, "onRequestPermissionsResult permissions length:" + permissions.length);
  135 + Map<String, Integer> perms = new HashMap<>();
  136 +
  137 + ArrayList<String> notGranted = new ArrayList<>();
  138 + for (int i = 0; i < permissions.length; i++) {
  139 + Log.d(TAG, "permissions: [i]:" + i + ", permissions[i]" + permissions[i] + ",grantResults[i]:" + grantResults[i]);
  140 + perms.put(permissions[i], grantResults[i]);
  141 + if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
  142 + notGranted.add(permissions[i]);
  143 + }
  144 + }
  145 +
  146 + if (notGranted.size() == 0) {
  147 +// Toast.makeText(activity, "all permission success" + notGranted, Toast.LENGTH_SHORT)
  148 +// .show();
  149 + permissionGrant.onPermissionGranted(CODE_MULTI_PERMISSION);
  150 + } else {
  151 + openSettingActivity(activity, "those permission need granted!");
  152 + }
  153 +
  154 + }
  155 +
  156 +
  157 + /**
  158 + * 一次申请多个权限
  159 + */
  160 + public static void requestMultiPermissions(final Activity activity, PermissionGrant grant) {
  161 +
  162 + final List<String> permissionsList = getNoGrantedPermission(activity, false);
  163 + final List<String> shouldRationalePermissionsList = getNoGrantedPermission(activity, true);
  164 +
  165 + //TODO checkSelfPermission
  166 + if (permissionsList == null || shouldRationalePermissionsList == null) {
  167 + return;
  168 + }
  169 + Log.d(TAG, "requestMultiPermissions permissionsList:" + permissionsList.size() + ",shouldRationalePermissionsList:" + shouldRationalePermissionsList.size());
  170 +
  171 + if (permissionsList.size() > 0) {
  172 + ActivityCompat.requestPermissions(activity, permissionsList.toArray(new String[permissionsList.size()]),
  173 + CODE_MULTI_PERMISSION);
  174 + Log.d(TAG, "showMessageOKCancel requestPermissions");
  175 +
  176 + } else if (shouldRationalePermissionsList.size() > 0) {
  177 + showMessageOKCancel(activity, "should open those permission",
  178 + new DialogInterface.OnClickListener() {
  179 + @Override
  180 + public void onClick(DialogInterface dialog, int which) {
  181 + ActivityCompat.requestPermissions(activity, shouldRationalePermissionsList.toArray(new String[shouldRationalePermissionsList.size()]),
  182 + CODE_MULTI_PERMISSION);
  183 + Log.d(TAG, "showMessageOKCancel requestPermissions");
  184 + }
  185 + });
  186 + } else {
  187 + grant.onPermissionGranted(CODE_MULTI_PERMISSION);
  188 + }
  189 +
  190 + }
  191 +
  192 +
  193 + private static void shouldShowRationale(final Activity activity, final int requestCode, final String requestPermission) {
  194 + //TODO
  195 + String[] permissionsHint = activity.getResources().getStringArray(R.array.permissions);
  196 + showMessageOKCancel(activity, "Rationale: " + permissionsHint[requestCode], new DialogInterface.OnClickListener() {
  197 + @Override
  198 + public void onClick(DialogInterface dialog, int which) {
  199 + ActivityCompat.requestPermissions(activity,
  200 + new String[]{requestPermission},
  201 + requestCode);
  202 + Log.d(TAG, "showMessageOKCancel requestPermissions:" + requestPermission);
  203 + }
  204 + });
  205 + }
  206 +
  207 + private static void showMessageOKCancel(final Activity context, String message, DialogInterface.OnClickListener okListener) {
  208 + new AlertDialog.Builder(context)
  209 + .setMessage(message)
  210 + .setPositiveButton("OK", okListener)
  211 + .setNegativeButton("Cancel", null)
  212 + .create()
  213 + .show();
  214 +
  215 + }
  216 +
  217 + /**
  218 + * @param activity
  219 + * @param requestCode Need consistent with requestPermission
  220 + * @param permissions
  221 + * @param grantResults
  222 + */
  223 + public static void requestPermissionsResult(final Activity activity, final int requestCode, @NonNull String[] permissions,
  224 + @NonNull int[] grantResults, PermissionGrant permissionGrant) {
  225 +
  226 + if (activity == null) {
  227 + return;
  228 + }
  229 + Log.d(TAG, "requestPermissionsResult requestCode:" + requestCode);
  230 +
  231 + if (requestCode == CODE_MULTI_PERMISSION) {
  232 + requestMultiResult(activity, permissions, grantResults, permissionGrant);
  233 + return;
  234 + }
  235 +
  236 + if (requestCode < 0 || requestCode >= requestPermissions.length) {
  237 + Log.w(TAG, "requestPermissionsResult illegal requestCode:" + requestCode);
  238 +// Toast.makeText(activity, "illegal requestCode:" + requestCode, Toast.LENGTH_SHORT).show();
  239 + return;
  240 + }
  241 +
  242 + Log.i(TAG, "onRequestPermissionsResult requestCode:" + requestCode + ",permissions:" + permissions.toString()
  243 + + ",grantResults:" + grantResults.toString() + ",length:" + grantResults.length);
  244 +
  245 + if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
  246 + Log.i(TAG, "onRequestPermissionsResult PERMISSION_GRANTED");
  247 + //TODO success, do something, can use callback
  248 + permissionGrant.onPermissionGranted(requestCode);
  249 +
  250 + } else {
  251 + //TODO hint user this permission function
  252 + Log.i(TAG, "onRequestPermissionsResult PERMISSION NOT GRANTED");
  253 + //TODO
  254 + String[] permissionsHint = activity.getResources().getStringArray(R.array.permissions);
  255 + openSettingActivity(activity, "Result" + permissionsHint[requestCode]);
  256 + }
  257 +
  258 + }
  259 +
  260 + private static void openSettingActivity(final Activity activity, String message) {
  261 +
  262 + showMessageOKCancel(activity, message, new DialogInterface.OnClickListener() {
  263 + @Override
  264 + public void onClick(DialogInterface dialog, int which) {
  265 + Intent intent = new Intent();
  266 + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
  267 + Log.d(TAG, "getPackageName(): " + activity.getPackageName());
  268 + Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
  269 + intent.setData(uri);
  270 + activity.startActivity(intent);
  271 + }
  272 + });
  273 + }
  274 +
  275 +
  276 + /**
  277 + * @param activity
  278 + * @param isShouldRationale true: return no granted and shouldShowRequestPermissionRationale permissions, false:return no granted and !shouldShowRequestPermissionRationale
  279 + * @return
  280 + */
  281 + public static ArrayList<String> getNoGrantedPermission(Activity activity, boolean isShouldRationale) {
  282 +
  283 + ArrayList<String> permissions = new ArrayList<>();
  284 +
  285 + for (int i = 0; i < requestPermissions.length; i++) {
  286 + String requestPermission = requestPermissions[i];
  287 +
  288 +
  289 + //TODO checkSelfPermission
  290 + int checkSelfPermission = -1;
  291 + try {
  292 + checkSelfPermission = ActivityCompat.checkSelfPermission(activity, requestPermission);
  293 + } catch (RuntimeException e) {
  294 + Toast.makeText(activity, "please open those permission", Toast.LENGTH_SHORT)
  295 + .show();
  296 + Log.e(TAG, "RuntimeException:" + e.getMessage());
  297 + return null;
  298 + }
  299 +
  300 + if (checkSelfPermission != PackageManager.PERMISSION_GRANTED) {
  301 + Log.i(TAG, "getNoGrantedPermission ActivityCompat.checkSelfPermission != PackageManager.PERMISSION_GRANTED:" + requestPermission);
  302 +
  303 + if (ActivityCompat.shouldShowRequestPermissionRationale(activity, requestPermission)) {
  304 + Log.d(TAG, "shouldShowRequestPermissionRationale if");
  305 + if (isShouldRationale) {
  306 + permissions.add(requestPermission);
  307 + }
  308 +
  309 + } else {
  310 +
  311 + if (!isShouldRationale) {
  312 + permissions.add(requestPermission);
  313 + }
  314 + Log.d(TAG, "shouldShowRequestPermissionRationale else");
  315 + }
  316 +
  317 + }
  318 + }
  319 +
  320 + return permissions;
  321 + }
  322 +
  323 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/ResourcesUtils.java 0 → 100644
@@ -0,0 +1,83 @@ @@ -0,0 +1,83 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.content.res.ColorStateList;
  4 +import android.graphics.drawable.Drawable;
  5 +import android.view.View;
  6 +
  7 +/**
  8 + * Created by Horrarndoo on 2017/9/1.
  9 + * <p>
  10 + * 资源工具类-加载资源文件
  11 + */
  12 +
  13 +public class ResourcesUtils {
  14 + /**
  15 + * 获取strings.xml资源文件字符串
  16 + *
  17 + * @param id 资源文件id
  18 + * @return 资源文件对应字符串
  19 + */
  20 + public static String getString(int id) {
  21 + return AppUtils.getContext().getResources().getString(id);
  22 + }
  23 +
  24 + /**
  25 + * 获取strings.xml资源文件字符串数组
  26 + *
  27 + * @param id 资源文件id
  28 + * @return 资源文件对应字符串数组
  29 + */
  30 + public static String[] getStringArray(int id) {
  31 + return AppUtils.getContext().getResources().getStringArray(id);
  32 + }
  33 +
  34 + /**
  35 + * 获取drawable资源文件图片
  36 + *
  37 + * @param id 资源文件id
  38 + * @return 资源文件对应图片
  39 + */
  40 + public static Drawable getDrawable(int id) {
  41 + return AppUtils.getContext().getResources().getDrawable(id);
  42 + }
  43 +
  44 + /**
  45 + * 获取colors.xml资源文件颜色
  46 + *
  47 + * @param id 资源文件id
  48 + * @return 资源文件对应颜色值
  49 + */
  50 + public static int getColor(int id) {
  51 + return AppUtils.getContext().getResources().getColor(id);
  52 + }
  53 +
  54 + /**
  55 + * 获取颜色的状态选择器
  56 + *
  57 + * @param id 资源文件id
  58 + * @return 资源文件对应颜色状态
  59 + */
  60 + public static ColorStateList getColorStateList(int id) {
  61 + return AppUtils.getContext().getResources().getColorStateList(id);
  62 + }
  63 +
  64 + /**
  65 + * 获取dimens资源文件中具体像素值
  66 + *
  67 + * @param id 资源文件id
  68 + * @return 资源文件对应像素值
  69 + */
  70 + public static int getDimen(int id) {
  71 + return AppUtils.getContext().getResources().getDimensionPixelSize(id);// 返回具体像素值
  72 + }
  73 +
  74 + /**
  75 + * 加载布局文件
  76 + *
  77 + * @param id 布局文件id
  78 + * @return 布局view
  79 + */
  80 + public static View inflate(int id) {
  81 + return View.inflate(AppUtils.getContext(), id, null);
  82 + }
  83 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/ScreenUtils.java 0 → 100644
@@ -0,0 +1,151 @@ @@ -0,0 +1,151 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.app.Activity;
  4 +import android.app.ActivityGroup;
  5 +import android.content.Context;
  6 +import android.graphics.Bitmap;
  7 +import android.graphics.Rect;
  8 +import android.os.Build;
  9 +import android.support.v7.app.AppCompatActivity;
  10 +import android.util.Log;
  11 +import android.util.TypedValue;
  12 +import android.view.Display;
  13 +import android.view.View;
  14 +import android.view.ViewGroup;
  15 +import android.view.WindowManager;
  16 +
  17 +/**
  18 + * Created by Horrarndoo on 2017/9/7.
  19 + * <p>
  20 + * 屏幕相关工具类
  21 + */
  22 +
  23 +public class ScreenUtils {
  24 + private ScreenUtils() {
  25 + /* cannot be instantiated */
  26 + throw new UnsupportedOperationException("cannot be instantiated");
  27 + }
  28 +
  29 +
  30 + private static int mStatusHeight = -1;
  31 +
  32 + /**
  33 + * 获取屏幕的宽度
  34 + *
  35 + * @param context
  36 + * @return
  37 + */
  38 + public static int getScreenWidth(Context context) {
  39 + WindowManager manager = (WindowManager) context
  40 + .getSystemService(Context.WINDOW_SERVICE);
  41 + Display display = manager.getDefaultDisplay();
  42 + return display.getWidth();
  43 + }
  44 +
  45 + /**
  46 + * 获取屏幕的高度
  47 + *
  48 + * @param context
  49 + * @return
  50 + */
  51 + public static int getScreenHeight(Context context) {
  52 + WindowManager manager = (WindowManager) context
  53 + .getSystemService(Context.WINDOW_SERVICE);
  54 + Display display = manager.getDefaultDisplay();
  55 + return display.getHeight();
  56 + }
  57 +
  58 + /**
  59 + * 获取当前屏幕截图,不包含状态栏
  60 + *
  61 + * @param activity
  62 + * @return bp
  63 + */
  64 + public static Bitmap snapShotWithoutStatusBar(Activity activity) {
  65 + View view = activity.getWindow().getDecorView();
  66 + view.setDrawingCacheEnabled(true);
  67 + view.buildDrawingCache();
  68 + Bitmap bmp = view.getDrawingCache();
  69 + if (bmp == null) {
  70 + return null;
  71 + }
  72 + Rect frame = new Rect();
  73 + activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
  74 + int statusBarHeight = frame.top;
  75 + Bitmap bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, bmp.getWidth(), bmp.getHeight()
  76 + - statusBarHeight);
  77 + view.destroyDrawingCache();
  78 + view.setDrawingCacheEnabled(false);
  79 +
  80 + return bp;
  81 + }
  82 +
  83 + /**
  84 + * 获取actionbar的像素高度,默认使用android官方兼容包做actionbar兼容
  85 + *
  86 + * @return
  87 + */
  88 + public static int getActionBarHeight(Context context) {
  89 + int actionBarHeight = 0;
  90 + if (context instanceof AppCompatActivity && ((AppCompatActivity) context)
  91 + .getSupportActionBar() != null) {
  92 + Log.d("isAppCompatActivity", "==AppCompatActivity");
  93 + actionBarHeight = ((AppCompatActivity) context).getSupportActionBar().getHeight();
  94 + } else if (context instanceof Activity && ((Activity) context).getActionBar() != null) {
  95 + Log.d("isActivity", "==Activity");
  96 + actionBarHeight = ((Activity) context).getActionBar().getHeight();
  97 + } else if (context instanceof ActivityGroup) {
  98 + Log.d("ActivityGroup", "==ActivityGroup");
  99 + if (((ActivityGroup) context).getCurrentActivity() instanceof AppCompatActivity && (
  100 + (AppCompatActivity) ((ActivityGroup) context).getCurrentActivity())
  101 + .getSupportActionBar() != null) {
  102 + actionBarHeight = ((AppCompatActivity) ((ActivityGroup) context)
  103 + .getCurrentActivity()).getSupportActionBar().getHeight();
  104 + } else if (((ActivityGroup) context).getCurrentActivity() instanceof Activity && (
  105 + (Activity) ((ActivityGroup) context).getCurrentActivity()).getActionBar() !=
  106 + null) {
  107 + actionBarHeight = ((Activity) ((ActivityGroup) context).getCurrentActivity())
  108 + .getActionBar().getHeight();
  109 + }
  110 + }
  111 + if (actionBarHeight != 0)
  112 + return actionBarHeight;
  113 + final TypedValue tv = new TypedValue();
  114 + if (context.getTheme().resolveAttribute(android.support.v7.appcompat.R.attr
  115 + .actionBarSize, tv, true)) {
  116 + if (context.getTheme().resolveAttribute(android.support.v7.appcompat.R.attr
  117 + .actionBarSize, tv, true))
  118 + actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, context
  119 + .getResources().getDisplayMetrics());
  120 + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
  121 + if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true))
  122 + actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, context
  123 + .getResources().getDisplayMetrics());
  124 + } else {
  125 + if (context.getTheme().resolveAttribute(android.support.v7.appcompat.R.attr
  126 + .actionBarSize, tv, true))
  127 + actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, context
  128 + .getResources().getDisplayMetrics());
  129 + }
  130 + Log.d("actionBarHeight", "====" + actionBarHeight);
  131 + return actionBarHeight;
  132 + }
  133 +
  134 +
  135 + /**
  136 + * 设置view margin
  137 + *
  138 + * @param v
  139 + * @param l
  140 + * @param t
  141 + * @param r
  142 + * @param b
  143 + */
  144 + public static void setMargins(View v, int l, int t, int r, int b) {
  145 + if (v.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
  146 + ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
  147 + p.setMargins(l, t, r, b);
  148 + v.requestLayout();
  149 + }
  150 + }
  151 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/SnackbarUtils.java 0 → 100644
@@ -0,0 +1,189 @@ @@ -0,0 +1,189 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.graphics.Color;
  4 +import android.support.design.widget.Snackbar;
  5 +import android.view.Gravity;
  6 +import android.view.LayoutInflater;
  7 +import android.view.View;
  8 +import android.widget.LinearLayout;
  9 +import android.widget.TextView;
  10 +
  11 +import com.share.mvpsdk.R;
  12 +
  13 +
  14 +/**
  15 + * Created by Horrarndoo on 2017/8/31.
  16 + * <p>
  17 + * Snackbar工具类
  18 + */
  19 +public class SnackbarUtils {
  20 +
  21 + public static final int Info = 1;
  22 + public static final int Confirm = 2;
  23 + public static final int Warning = 3;
  24 + public static final int Alert = 4;
  25 +
  26 +
  27 + public static int red = 0xfff44336;
  28 + public static int green = 0xff4caf50;
  29 + public static int blue = 0xff2195f3;
  30 + public static int orange = 0xffffc107;
  31 +
  32 + /**
  33 + * 短显示Snackbar,自定义颜色
  34 + *
  35 + * @param view
  36 + * @param message
  37 + * @param messageColor
  38 + * @param backgroundColor
  39 + * @return
  40 + */
  41 + public static Snackbar getShort(View view, String message, int messageColor, int
  42 + backgroundColor) {
  43 + Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_SHORT);
  44 + setSnackbarColor(snackbar, messageColor, backgroundColor);
  45 + return snackbar;
  46 + }
  47 +
  48 + /**
  49 + * 长显示Snackbar,自定义颜色
  50 + *
  51 + * @param view
  52 + * @param message
  53 + * @param messageColor
  54 + * @param backgroundColor
  55 + * @return
  56 + */
  57 + public static Snackbar getLong(View view, String message, int messageColor, int
  58 + backgroundColor) {
  59 + Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_LONG);
  60 + setSnackbarColor(snackbar, messageColor, backgroundColor);
  61 + return snackbar;
  62 + }
  63 +
  64 + /**
  65 + * 自定义时常显示Snackbar,自定义颜色
  66 + *
  67 + * @param view
  68 + * @param message
  69 + * @param messageColor
  70 + * @param backgroundColor
  71 + * @return
  72 + */
  73 + public static Snackbar getIndefinite(View view, String message, int duration, int
  74 + messageColor, int backgroundColor) {
  75 + Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_INDEFINITE).setDuration
  76 + (duration);
  77 + setSnackbarColor(snackbar, messageColor, backgroundColor);
  78 + return snackbar;
  79 + }
  80 +
  81 + /**
  82 + * 短显示Snackbar,可选预设类型
  83 + *
  84 + * @param view
  85 + * @param message
  86 + * @param type
  87 + * @return
  88 + */
  89 + public static Snackbar getShort(View view, String message, int type) {
  90 + Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_SHORT);
  91 + switchType(snackbar, type);
  92 + return snackbar;
  93 + }
  94 +
  95 + /**
  96 + * 长显示Snackbar,可选预设类型
  97 + *
  98 + * @param view
  99 + * @param message
  100 + * @param type
  101 + * @return
  102 + */
  103 + public static Snackbar getLong(View view, String message, int type) {
  104 + Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_LONG);
  105 + switchType(snackbar, type);
  106 + return snackbar;
  107 + }
  108 +
  109 + /**
  110 + * 自定义时常显示Snackbar,可选预设类型
  111 + *
  112 + * @param view
  113 + * @param message
  114 + * @param type
  115 + * @return
  116 + */
  117 + public static Snackbar getIndefinite(View view, String message, int duration, int type) {
  118 + Snackbar snackbar = Snackbar.make(view, message, Snackbar.LENGTH_INDEFINITE).setDuration
  119 + (duration);
  120 + switchType(snackbar, type);
  121 + return snackbar;
  122 + }
  123 +
  124 + //选择预设类型
  125 + private static void switchType(Snackbar snackbar, int type) {
  126 + switch (type) {
  127 + case Info:
  128 + setSnackbarColor(snackbar, blue);
  129 + break;
  130 + case Confirm:
  131 + setSnackbarColor(snackbar, green);
  132 + break;
  133 + case Warning:
  134 + setSnackbarColor(snackbar, orange);
  135 + break;
  136 + case Alert:
  137 + setSnackbarColor(snackbar, Color.YELLOW, red);
  138 + break;
  139 + }
  140 + }
  141 +
  142 + /**
  143 + * 设置Snackbar背景颜色
  144 + *
  145 + * @param snackbar
  146 + * @param backgroundColor
  147 + */
  148 + public static void setSnackbarColor(Snackbar snackbar, int backgroundColor) {
  149 + View view = snackbar.getView();
  150 + if (view != null) {
  151 + view.setBackgroundColor(backgroundColor);
  152 + }
  153 + }
  154 +
  155 + /**
  156 + * 设置Snackbar文字和背景颜色
  157 + *
  158 + * @param snackbar
  159 + * @param messageColor
  160 + * @param backgroundColor
  161 + */
  162 + public static void setSnackbarColor(Snackbar snackbar, int messageColor, int backgroundColor) {
  163 + View view = snackbar.getView();
  164 + if (view != null) {
  165 + view.setBackgroundColor(backgroundColor);
  166 + ((TextView) view.findViewById(R.id.snackbar_text)).setTextColor(messageColor);
  167 + }
  168 + }
  169 +
  170 + /**
  171 + * 向Snackbar中添加view
  172 + *
  173 + * @param snackbar
  174 + * @param layoutId
  175 + * @param index 新加布局在Snackbar中的位置
  176 + */
  177 + public static void addView(Snackbar snackbar, int layoutId, int index) {
  178 + View snackbarview = snackbar.getView();
  179 + Snackbar.SnackbarLayout snackbarLayout = (Snackbar.SnackbarLayout) snackbarview;
  180 +
  181 + View add_view = LayoutInflater.from(snackbarview.getContext()).inflate(layoutId, null);
  182 +
  183 + LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(LinearLayout.LayoutParams
  184 + .WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
  185 + p.gravity = Gravity.CENTER_VERTICAL;
  186 +
  187 + snackbarLayout.addView(add_view, index, p);
  188 + }
  189 +}
0 \ No newline at end of file 190 \ No newline at end of file
mvpsdk/src/main/java/com/share/mvpsdk/utils/SpUtils.java 0 → 100644
@@ -0,0 +1,212 @@ @@ -0,0 +1,212 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +
  4 +import android.content.Context;
  5 +import android.content.SharedPreferences;
  6 +import android.preference.PreferenceManager;
  7 +
  8 +import com.google.gson.Gson;
  9 +import com.google.gson.JsonArray;
  10 +import com.google.gson.JsonElement;
  11 +import com.google.gson.JsonParser;
  12 +
  13 +import java.util.ArrayList;
  14 +import java.util.List;
  15 +
  16 +/**
  17 + * SharedPreferences工具类封装
  18 + */
  19 +public class SpUtils {
  20 + private static SharedPreferences sp;
  21 + private static String mPreferencesName = "share_preference_default";
  22 +
  23 + /**
  24 + * 设置preferencesName
  25 + *
  26 + * @param preferencesName preferencesName
  27 + */
  28 + private void setPreferencesName(String preferencesName) {
  29 + mPreferencesName = preferencesName;
  30 + }
  31 +
  32 + /**
  33 + * 写入boolean变量至sp中
  34 + *
  35 + * @param ctx 上下文环境
  36 + * @param key 存储节点名称
  37 + * @param value 存储节点的值
  38 + */
  39 + public static void putBoolean(Context ctx, String key, boolean value) {
  40 + //(存储节点文件名称,读写方式)
  41 + if (sp == null) {
  42 + sp = ctx.getSharedPreferences(mPreferencesName, Context
  43 + .MODE_PRIVATE);
  44 + }
  45 + sp.edit().putBoolean(key, value).apply();
  46 + }
  47 +
  48 + /**
  49 + * 读取boolean标示从sp中
  50 + *
  51 + * @param ctx 上下文环境
  52 + * @param key 存储节点名称
  53 + * @param defValue 没有此节点默认值
  54 + * @return 默认值或者此节点读取到的结果
  55 + */
  56 + public static boolean getBoolean(Context ctx, String key, boolean defValue) {
  57 + //(存储节点文件名称,读写方式)
  58 + if (sp == null) {
  59 + sp = ctx.getSharedPreferences(mPreferencesName, Context
  60 + .MODE_PRIVATE);
  61 + }
  62 + return sp.getBoolean(key, defValue);
  63 + }
  64 +
  65 + /**
  66 + * 写入String变量至sp中
  67 + *
  68 + * @param ctx 上下文环境
  69 + * @param key 存储节点名称
  70 + * @param value 存储节点的值
  71 + */
  72 + public static void putString(Context ctx, String key, String value) {
  73 + //(存储节点文件名称,读写方式)
  74 + if (sp == null) {
  75 + sp = ctx.getSharedPreferences(mPreferencesName, Context
  76 + .MODE_PRIVATE);
  77 + }
  78 + sp.edit().putString(key, value).apply();
  79 + }
  80 +
  81 + /**
  82 + * 读取String标示从sp中
  83 + *
  84 + * @param ctx 上下文环境
  85 + * @param key 存储节点名称
  86 + * @param defValue 没有此节点默认值
  87 + * @return 默认值或者此节点读取到的结果
  88 + */
  89 + public static String getString(Context ctx, String key, String defValue) {
  90 + //(存储节点文件名称,读写方式)
  91 + if (sp == null) {
  92 + sp = ctx.getSharedPreferences(mPreferencesName, Context
  93 + .MODE_PRIVATE);
  94 + }
  95 + return sp.getString(key, defValue);
  96 + }
  97 +
  98 +
  99 + /**
  100 + * 写入int变量至sp中
  101 + *
  102 + * @param ctx 上下文环境
  103 + * @param key 存储节点名称
  104 + * @param value 存储节点的值
  105 + */
  106 + public static void putInt(Context ctx, String key, int value) {
  107 + //(存储节点文件名称,读写方式)
  108 + if (sp == null) {
  109 + sp = ctx.getSharedPreferences(mPreferencesName, Context
  110 + .MODE_PRIVATE);
  111 + }
  112 + sp.edit().putInt(key, value).apply();
  113 + }
  114 +
  115 + /**
  116 + * 读取int标示从sp中
  117 + *
  118 + * @param ctx 上下文环境
  119 + * @param key 存储节点名称
  120 + * @param defValue 没有此节点默认值
  121 + * @return 默认值或者此节点读取到的结果
  122 + */
  123 + public static int getInt(Context ctx, String key, int defValue) {
  124 + //(存储节点文件名称,读写方式)
  125 + if (sp == null) {
  126 + sp = ctx.getSharedPreferences(mPreferencesName, Context
  127 + .MODE_PRIVATE);
  128 + }
  129 + return sp.getInt(key, defValue);
  130 + }
  131 +
  132 +
  133 + /**
  134 + * 从sp中移除指定节点
  135 + *
  136 + * @param ctx 上下文环境
  137 + * @param key 需要移除节点的名称
  138 + */
  139 + public static void remove(Context ctx, String key) {
  140 + if (sp == null) {
  141 + sp = ctx.getSharedPreferences(mPreferencesName, Context
  142 + .MODE_PRIVATE);
  143 + }
  144 + sp.edit().remove(key).apply();
  145 + }
  146 +
  147 + /**
  148 + * 保存List
  149 + *
  150 + * @param key sp key值
  151 + * @param datalist list
  152 + * @param <T> item 类型
  153 + */
  154 + public static <T> void setDataList(String key, List<T> datalist) {
  155 + if (null == datalist || datalist.size() <= 0)
  156 + return;
  157 +
  158 + Gson gson = new Gson();
  159 + //转换成json数据,再保存
  160 + String strJson = gson.toJson(datalist);
  161 + SpUtils.putString(AppUtils.getContext(), key, strJson);
  162 + }
  163 +
  164 + /**
  165 + * 获取List
  166 + *
  167 + * @param key sp key值
  168 + * @param <T> item 类型
  169 + * @return list
  170 + */
  171 + public static <T> List<T> getDataList(String key, Class<T> cls) {
  172 + List<T> datalist = new ArrayList<T>();
  173 + String strJson = SpUtils.getString(AppUtils.getContext(), key, null);
  174 +
  175 + if (null == strJson) {
  176 + return datalist;
  177 + }
  178 +
  179 + try {
  180 + Gson gson = new Gson();
  181 + // datalist = gson.fromJson(strJson, new TypeToken<List<T>>(){}.getType());
  182 + JsonArray array = new JsonParser().parse(strJson).getAsJsonArray();
  183 + for (final JsonElement elem : array) {
  184 + datalist.add(gson.fromJson(elem, cls));
  185 + }
  186 + }catch (Exception e){
  187 + e.printStackTrace();
  188 + }
  189 +
  190 + return datalist;
  191 + }
  192 +
  193 + public static int getThemeIndex(Context context) {
  194 + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
  195 + return prefs.getInt("ThemeIndex", 5);
  196 + }
  197 +
  198 + public static void setThemeIndex(Context context, int index) {
  199 + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
  200 + prefs.edit().putInt("ThemeIndex", index).apply();
  201 + }
  202 +
  203 + public static boolean getNightModel(Context context) {
  204 + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
  205 + return prefs.getBoolean("pNightMode", false);
  206 + }
  207 +
  208 + public static void setNightModel(Context context, boolean nightModel) {
  209 + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
  210 + prefs.edit().putBoolean("pNightMode", nightModel).apply();
  211 + }
  212 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/StatusBarUtils.java 0 → 100644
@@ -0,0 +1,140 @@ @@ -0,0 +1,140 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.app.Activity;
  4 +import android.content.Context;
  5 +import android.graphics.Color;
  6 +import android.os.Build;
  7 +import android.support.annotation.ColorInt;
  8 +import android.support.v7.widget.Toolbar;
  9 +import android.view.View;
  10 +import android.view.ViewGroup;
  11 +import android.view.Window;
  12 +import android.view.WindowManager;
  13 +
  14 +import java.lang.reflect.Field;
  15 +
  16 +
  17 +/**
  18 + * Created by Horrarndoo on 2017/8/31.
  19 + * <p>
  20 + * StatusBar工具类
  21 + */
  22 +public class StatusBarUtils {
  23 +
  24 + private static final int DEFAULT_STATUS_BAR_ALPHA = 0;
  25 +
  26 + /**
  27 + * 设置状态栏颜色
  28 + *
  29 + * @param activity 需要设置的 activity
  30 + * @param color 状态栏颜色值
  31 + */
  32 + public static void setColor(Activity activity, @ColorInt int color) {
  33 + setBarColor(activity, color);
  34 + }
  35 +
  36 + /**
  37 + * 设置状态栏背景色
  38 + * 4.4以下不处理
  39 + * 4.4使用默认沉浸式状态栏
  40 + *
  41 + * @param color 要为状态栏设置的颜色值
  42 + */
  43 + public static void setBarColor(Activity activity, int color) {
  44 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  45 + Window win = activity.getWindow();
  46 + View decorView = win.getDecorView();
  47 + win.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);//沉浸式状态栏(4.4-5.0透明,5.0以上半透明)
  48 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//android5.0以上设置透明效果
  49 + win.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);//清除flag,为了android5.0以上也全透明效果
  50 + //让应用的主体内容占用系统状态栏的空间
  51 +// int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
  52 +// | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
  53 + int option = View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
  54 + decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() | option);
  55 + win.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
  56 + win.setStatusBarColor(color);//设置状态栏背景色
  57 + }
  58 + }
  59 + }
  60 +
  61 + /**
  62 + * 设置状态栏全透明
  63 + *
  64 + * @param activity 需要设置的activity
  65 + */
  66 + public static void setTransparent(Activity activity) {
  67 + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
  68 + return;
  69 + }
  70 + setColor(activity, Color.TRANSPARENT);
  71 + }
  72 +
  73 + /**
  74 + * 修正 Toolbar 的位置
  75 + * 在 Android 4.4 版本下无法显示内容在 StatusBar 下,所以无需修正 Toolbar 的位置
  76 + *
  77 + * @param toolbar
  78 + */
  79 + public static void fixToolbar(Toolbar toolbar, Activity activity) {
  80 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
  81 + int statusHeight = getStatusBarHeight(activity);
  82 + ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) toolbar.getLayoutParams();
  83 + layoutParams.setMargins(0, statusHeight, 0, 0);
  84 + }
  85 + }
  86 +
  87 + /**
  88 + * 获取系统状态栏高度
  89 + *
  90 + * @param context
  91 + * @return
  92 + */
  93 + public static int getStatusBarHeight(Context context) {
  94 + Class<?> c = null;
  95 + Object obj = null;
  96 + Field field = null;
  97 + int x = 0, statusBarHeight = 0;
  98 + try {
  99 + c = Class.forName("com.android.internal.R$dimen");
  100 + obj = c.newInstance();
  101 + field = c.getField("status_bar_height");
  102 + x = Integer.parseInt(field.get(obj).toString());
  103 + statusBarHeight = context.getResources().getDimensionPixelSize(x);
  104 + } catch (Exception e1) {
  105 + e1.printStackTrace();
  106 + }
  107 + return statusBarHeight;
  108 + }
  109 +
  110 +// /**
  111 +// * 获取状态栏高度
  112 +// *
  113 +// * @param context context
  114 +// * @return 状态栏高度
  115 +// */
  116 +// private static int getStatusBarHeight(Context context) {
  117 +// // 获得状态栏高度
  118 +// int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen",
  119 +// "android");
  120 +// return context.getResources().getDimensionPixelSize(resourceId);
  121 +// }
  122 +
  123 + /**
  124 + * 计算状态栏颜色
  125 + *
  126 + * @param color color值
  127 + * @param alpha alpha值
  128 + * @return 最终的状态栏颜色
  129 + */
  130 + private static int calculateStatusColor(@ColorInt int color, int alpha) {
  131 + float a = 1 - alpha / 255f;
  132 + int red = color >> 16 & 0xff;
  133 + int green = color >> 8 & 0xff;
  134 + int blue = color & 0xff;
  135 + red = (int) (red * a + 0.5);
  136 + green = (int) (green * a + 0.5);
  137 + blue = (int) (blue * a + 0.5);
  138 + return 0xff << 24 | red << 16 | green << 8 | blue;
  139 + }
  140 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/StorageUtils.java 0 → 100644
@@ -0,0 +1,857 @@ @@ -0,0 +1,857 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.app.Activity;
  4 +import android.content.Context;
  5 +import android.database.Cursor;
  6 +import android.graphics.Bitmap;
  7 +import android.graphics.BitmapFactory;
  8 +import android.graphics.Canvas;
  9 +import android.graphics.Matrix;
  10 +import android.graphics.Paint;
  11 +import android.net.Uri;
  12 +import android.os.Environment;
  13 +import android.provider.MediaStore;
  14 +import android.util.Log;
  15 +import android.view.View;
  16 +
  17 +import java.io.BufferedReader;
  18 +import java.io.ByteArrayInputStream;
  19 +import java.io.ByteArrayOutputStream;
  20 +import java.io.DataOutputStream;
  21 +import java.io.File;
  22 +import java.io.FileInputStream;
  23 +import java.io.FileNotFoundException;
  24 +import java.io.FileOutputStream;
  25 +import java.io.FileReader;
  26 +import java.io.IOException;
  27 +import java.io.InputStream;
  28 +import java.io.InputStreamReader;
  29 +import java.net.HttpURLConnection;
  30 +import java.net.MalformedURLException;
  31 +import java.net.URL;
  32 +import java.util.ArrayList;
  33 +import java.util.Arrays;
  34 +import java.util.HashSet;
  35 +import java.util.List;
  36 +import java.util.Map;
  37 +import java.util.StringTokenizer;
  38 +import java.util.zip.ZipEntry;
  39 +import java.util.zip.ZipOutputStream;
  40 +
  41 +/**
  42 + * Created by ToaHanDong on 2017/7/24.
  43 + */
  44 +
  45 +public class StorageUtils {
  46 + private static final String TAG = "StorageUtils";
  47 +
  48 + public static class StorageInfo {
  49 +
  50 + public final String path;
  51 + public final boolean internal;
  52 + public final boolean readonly;
  53 + public final int display_number;
  54 +
  55 + StorageInfo(String path, boolean internal, boolean readonly, int display_number) {
  56 + this.path = path;
  57 + this.internal = internal;
  58 + this.readonly = readonly;
  59 + this.display_number = display_number;
  60 + }
  61 +
  62 + public String getDisplayName() {
  63 + StringBuilder res = new StringBuilder();
  64 + if (internal) {
  65 + res.append("Internal SD card");
  66 + } else if (display_number > 1) {
  67 + res.append("SD card " + display_number);
  68 + } else {
  69 + res.append("SD card");
  70 + }
  71 + if (readonly) {
  72 + res.append(" (Read only)");
  73 + }
  74 + return res.toString();
  75 + }
  76 + }
  77 +
  78 + public static List<StorageInfo> getStorageList() throws Exception {
  79 +
  80 + List<StorageInfo> list = new ArrayList<StorageInfo>();
  81 + String def_path = Environment.getExternalStorageDirectory().getPath();
  82 + boolean def_path_internal = !Environment.isExternalStorageRemovable();
  83 + String def_path_state = Environment.getExternalStorageState();
  84 + boolean def_path_available = def_path_state.equals(Environment.MEDIA_MOUNTED)
  85 + || def_path_state.equals(Environment.MEDIA_MOUNTED_READ_ONLY);
  86 + boolean def_path_readonly = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED_READ_ONLY);
  87 + BufferedReader buf_reader = null;
  88 + try {
  89 + HashSet<String> paths = new HashSet<String>();
  90 + buf_reader = new BufferedReader(new FileReader("/proc/mounts"));
  91 + String line;
  92 + int cur_display_number = 1;
  93 + Log.d(TAG, "/proc/mounts");
  94 + while ((line = buf_reader.readLine()) != null) {
  95 + Log.d(TAG, line);
  96 + if (line.contains("vfat") || line.contains("/mnt")) {
  97 + StringTokenizer tokens = new StringTokenizer(line, " ");
  98 + String unused = tokens.nextToken(); //device
  99 + String mount_point = tokens.nextToken(); //mount point
  100 + if (paths.contains(mount_point)) {
  101 + continue;
  102 + }
  103 + unused = tokens.nextToken(); //file system
  104 + List<String> flags = Arrays.asList(tokens.nextToken().split(",")); //flags
  105 + boolean readonly = flags.contains("ro");
  106 +
  107 + if (mount_point.equals(def_path)) {
  108 + paths.add(def_path);
  109 + list.add(0, new StorageInfo(def_path, def_path_internal, readonly, -1));
  110 + } else if (line.contains("/dev/block/vold")) {
  111 + if (!line.contains("/mnt/secure")
  112 + && !line.contains("/mnt/asec")
  113 + && !line.contains("/mnt/obb")
  114 + && !line.contains("/dev/mapper")
  115 + && !line.contains("tmpfs")) {
  116 + paths.add(mount_point);
  117 + list.add(new StorageInfo(mount_point, false, readonly, cur_display_number++));
  118 + }
  119 + }
  120 + }
  121 + }
  122 +
  123 + if (!paths.contains(def_path) && def_path_available) {
  124 + list.add(0, new StorageInfo(def_path, def_path_internal, def_path_readonly, -1));
  125 + }
  126 +
  127 + } catch (FileNotFoundException ex) {
  128 + ex.printStackTrace();
  129 + } catch (IOException ex) {
  130 + ex.printStackTrace();
  131 + } finally {
  132 + if (buf_reader != null) {
  133 + try {
  134 + buf_reader.close();
  135 + } catch (IOException ex) {
  136 + }
  137 + }
  138 + }
  139 + return list;
  140 + }
  141 +
  142 + public static boolean DeleteDirAndFile(File file) {
  143 + if (file != null && file.isDirectory()) {
  144 + String[] children = file.list();
  145 + //递归删除目录中的子目录下
  146 + for (int i = 0; i < children.length; i++) {
  147 + boolean success = DeleteDirAndFile(new File(file, children[i]));
  148 + if (!success) {
  149 + return false;
  150 + }
  151 + }
  152 + }
  153 + // 目录此时为空,可以删除
  154 + return file.delete();
  155 + }
  156 +
  157 +
  158 + //通过url获取Bitmap
  159 + public static Bitmap getBitmap(String urlPath) throws Exception {
  160 + URL url = new URL(urlPath);
  161 + HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  162 + conn.setConnectTimeout(5000);
  163 + conn.setRequestMethod("GET");
  164 + Bitmap bm = null;
  165 + if (conn.getResponseCode() == 200) {
  166 +
  167 + InputStream inputStream = conn.getInputStream();
  168 + bm = BitmapFactory.decodeStream(inputStream);
  169 +//
  170 +// if(bm==null){
  171 +// Log.e(TAG, "getBitmap2: 为空");
  172 +// }else{
  173 +// Log.e(TAG, "getBitmap2: 不为空");
  174 +// }
  175 + return bm;
  176 + }
  177 + return null;
  178 +
  179 + }
  180 +
  181 + /**
  182 + * 通过URL获得网上图片。并设置最大内存如:http://www.xxxxxx.com/xx.jpg
  183 + *
  184 + * @param url 网络图片地址
  185 + * @param displaypixels 最大图片内存
  186 + * @return
  187 + * @throws MalformedURLException
  188 + * @throws IOException
  189 + */
  190 + public static Bitmap getBitmap(String url, int displaypixels) throws MalformedURLException, IOException {
  191 + Bitmap bmp = null;
  192 + BitmapFactory.Options opts = new BitmapFactory.Options();
  193 + InputStream stream = new URL(url).openStream();
  194 + byte[] bytes = getBytes(stream);
  195 +//这3句是处理图片溢出的begin( 如果不需要处理溢出直接 opts.inSampleSize=1;)
  196 + opts.inJustDecodeBounds = true;
  197 + BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts);
  198 + opts.inSampleSize = computeSampleSize(opts, -1, displaypixels);
  199 +//end
  200 + opts.inJustDecodeBounds = false;
  201 + bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts);
  202 + return bmp;
  203 + }
  204 +
  205 +
  206 + /**
  207 + * 数据流转成btyle[]数组
  208 + */
  209 + private static byte[] getBytes(InputStream is) {
  210 + ByteArrayOutputStream baos = new ByteArrayOutputStream();
  211 + byte[] b = new byte[2048];
  212 + int len = 0;
  213 + try {
  214 + while ((len = is.read(b, 0, 2048)) != -1) {
  215 + baos.write(b, 0, len);
  216 + baos.flush();
  217 + }
  218 + } catch (IOException e) {
  219 + e.printStackTrace();
  220 + }
  221 + byte[] bytes = baos.toByteArray();
  222 + return bytes;
  223 + }
  224 +
  225 + /****
  226 + * 处理图片bitmap size exceeds VM budget (Out Of Memory 内存溢出)
  227 + */
  228 + private static int computeSampleSize(BitmapFactory.Options options,
  229 + int minSideLength, int maxNumOfPixels) {
  230 + int initialSize = computeInitialSampleSize(options, minSideLength,
  231 + maxNumOfPixels);
  232 + int roundedSize;
  233 + if (initialSize <= 8) {
  234 + roundedSize = 1;
  235 + while (roundedSize < initialSize) {
  236 + roundedSize <<= 1;
  237 + }
  238 + } else {
  239 + roundedSize = (initialSize + 7) / 8 * 8;
  240 + }
  241 + return roundedSize;
  242 + }
  243 +
  244 + private static int computeInitialSampleSize(BitmapFactory.Options options,
  245 + int minSideLength, int maxNumOfPixels) {
  246 + double w = options.outWidth;
  247 + double h = options.outHeight;
  248 + int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math
  249 + .sqrt(w * h / maxNumOfPixels));
  250 + int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(
  251 + Math.floor(w / minSideLength), Math.floor(h / minSideLength));
  252 + if (upperBound < lowerBound) {
  253 + return lowerBound;
  254 + }
  255 + if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
  256 + return 1;
  257 + } else if (minSideLength == -1) {
  258 + return lowerBound;
  259 + } else {
  260 + return upperBound;
  261 + }
  262 + }
  263 +
  264 +
  265 + public static String getFileName(String pathName) {
  266 + int start = pathName.lastIndexOf("/");
  267 + if (start != -1) {
  268 + return pathName.substring(start + 1, pathName.length());
  269 + }
  270 + return pathName;
  271 +
  272 + }
  273 +
  274 + public static String getFileExtName(String pathName) {
  275 + int start = pathName.lastIndexOf(".");
  276 + if (start != -1) {
  277 + return pathName.substring(start + 1, pathName.length());
  278 + }
  279 + return pathName;
  280 + }
  281 +
  282 + public static void write1(Bitmap bmp, File file) {
  283 + FileOutputStream fos = null;
  284 + try {
  285 + if (!file.exists()) {
  286 + file.createNewFile();
  287 + }
  288 + fos = new FileOutputStream(file);
  289 + bmp.compress(Bitmap.CompressFormat.PNG, 75, fos);
  290 +
  291 + fos.flush();
  292 + } catch (FileNotFoundException e) {
  293 + e.printStackTrace();
  294 + } catch (IOException e) {
  295 + e.printStackTrace();
  296 + } finally {
  297 + if (null != fos) {
  298 + try {
  299 +
  300 + fos.close();
  301 + } catch (IOException e) {
  302 + e.printStackTrace();
  303 + }
  304 + }
  305 + }
  306 + }
  307 +
  308 + /**
  309 + * 把png或jpg(jpeg)格式图片按指定名称写入指定目录下
  310 + *
  311 + * @param bmp
  312 + * @param file
  313 + */
  314 + public static boolean write(Bitmap bmp, File file) {
  315 +
  316 +
  317 +// try {
  318 +// ByteArrayOutputStream baos = new ByteArrayOutputStream();
  319 +// bmp.compress(Bitmap.CompressFormat.JPEG, 100, baos); // 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
  320 +// bmp.recycle();
  321 +// ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
  322 +// baos.reset(); // 把压缩后的数据baos存放到ByteArrayInputStream中
  323 +// BitmapFactory.Options options = new BitmapFactory.Options();
  324 +// options.inJustDecodeBounds = true;//只
  325 +// BitmapFactory.decodeStream(isBm, null,options); // 把ByteArrayInputStream数据生成图片
  326 +// int w = options.outWidth;
  327 +// int h = options.outHeight;
  328 +// options.inSampleSize = calculateInSampleSize(w, h, 720, 405);
  329 +// options.inJustDecodeBounds = false;
  330 +// isBm.reset();
  331 +// bmp = BitmapFactory.decodeStream(isBm,null,options); // 把ByteArrayInputStream数据生成图片
  332 +// double bitcount = bmp.getByteCount()/1000;
  333 +// //Log.e("StorageUtils", "这里压缩尺寸后的容量:" + bitcount + "---------------");
  334 +//
  335 +// bmp.compress(Bitmap.CompressFormat.JPEG, 100, baos);
  336 +// int compressOptions = 100 ;
  337 +// //Log.e("StorageUtils", "这里压缩容量前的容量:" + baos.toByteArray().length / 1024 + "---------------");
  338 +// while (baos.toByteArray().length / 1024 > 500 ) { // 循环判断如果压缩后图片是否大于500kb,大于继续压缩
  339 +// baos.reset(); // 重置baos即清空baos
  340 +// bmp.compress(Bitmap.CompressFormat.JPEG, compressOptions, baos); // 这里压缩options%,把压缩后的数据存放到baos中
  341 +// compressOptions -= 10 ; // 每次都减少10
  342 +// }
  343 +// ByteArrayInputStream isCompress = new ByteArrayInputStream(baos.toByteArray()); // 把压缩后的数据baos存放到ByteArrayInputStream中
  344 +// bmp = BitmapFactory.decodeStream(isCompress, null , null ); // 把ByteArrayInputStream数据生成图片
  345 +// bitcount = bmp.getByteCount()/1000;
  346 +// //Log.e("StorageUtils", "这里压缩容量后的容量:" + bitcount + "---------------");
  347 +// } catch (Exception e) {
  348 +// e.printStackTrace();
  349 +// return false;
  350 +// }
  351 +// //write
  352 +// FileOutputStream fos = null;
  353 +// try {
  354 +// if (!file.exists()) {
  355 +// file.createNewFile();
  356 +// }
  357 +// fos = new FileOutputStream(file);
  358 +// bmp.compress(Bitmap.CompressFormat.PNG, 100, fos);
  359 +//
  360 +// fos.flush();
  361 +// } catch (FileNotFoundException e) {
  362 +// e.printStackTrace();
  363 +// return false;
  364 +// } catch (IOException e) {
  365 +// e.printStackTrace();
  366 +// return false;
  367 +// } finally {
  368 +// if (null != fos) {
  369 +// try {
  370 +// fos.close();
  371 +// } catch (IOException e) {
  372 +// e.printStackTrace();
  373 +// }
  374 +// }
  375 +// }
  376 +// return true;
  377 +
  378 +
  379 + try {
  380 + FileOutputStream fos = new FileOutputStream(file);
  381 + bmp.compress(Bitmap.CompressFormat.JPEG, 90, fos);
  382 + return true;
  383 + } catch (FileNotFoundException e) {
  384 + e.printStackTrace();
  385 + return false;
  386 + }
  387 + }
  388 +
  389 +
  390 + /**
  391 + * 质量压缩到固定的容量
  392 + *
  393 + * @param image
  394 + * @param imagesize 压缩的大小限制 k
  395 + * @return
  396 + */
  397 + public static Bitmap compressImage(Bitmap image, int imagesize) {
  398 + ByteArrayOutputStream baos = new ByteArrayOutputStream();
  399 + image.compress(Bitmap.CompressFormat.JPEG, 100, baos); // 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
  400 + int options = 100;
  401 + while (baos.toByteArray().length / 1024 > imagesize) { // 循环判断如果压缩后图片是否大于100kb,大于继续压缩
  402 + baos.reset(); // 重置baos即清空baos
  403 + options -= 10; // 每次都减少10
  404 + image.compress(Bitmap.CompressFormat.JPEG, options, baos); // 这里压缩options%,把压缩后的数据存放到baos中
  405 + }
  406 + ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray()); // 把压缩后的数据baos存放到ByteArrayInputStream中
  407 + Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null); // 把ByteArrayInputStream数据生成图片
  408 + return bitmap;
  409 + }
  410 +
  411 + /**
  412 + * 质量压缩到固定的容量 到指定路径下
  413 + *
  414 + * @param image
  415 + * @param maxSize 压缩的大小限制 k
  416 + * @return
  417 + */
  418 + public static void compressAndGenImage(Bitmap image, File file, int maxSize) throws IOException {
  419 + ByteArrayOutputStream os = new ByteArrayOutputStream();
  420 + // scale
  421 + int options = 100;
  422 + // Store the bitmap into output stream(no compress)
  423 +// image.compress(Bitmap.CompressFormat.JPEG, options, os);
  424 + image.compress(Bitmap.CompressFormat.PNG, options, os);
  425 + // Compress by loop
  426 + /* while (os.toByteArray().length / 1024 > maxSize) {
  427 + // Clean up os
  428 + os.reset();
  429 + // interval 10
  430 + options -= 10;
  431 + image.compress(Bitmap.CompressFormat.PNG, options, os);
  432 + }*/
  433 +
  434 + // Generate compressed image file
  435 + FileOutputStream fos = new FileOutputStream(file);
  436 + fos.write(os.toByteArray());
  437 + fos.flush();
  438 + fos.close();
  439 + }
  440 +
  441 + /**
  442 + * 压缩图片到固定的尺寸
  443 + */
  444 + public static Bitmap revitionImageSize(Bitmap bitmap, int oldwidth, int oldheight, int reqWidth, int reqHeight) throws IOException {
  445 +
  446 +// // 生成压缩的图片
  447 +// int i = 0;
  448 +// BitmapFactory.Options options = new BitmapFactory.Options();
  449 +// // 这个参数代表,不为bitmap分配内存空间,只记录一些该图片的信息(例如图片大小),说白了就是为了内存优化
  450 +// options.inSampleSize = calculateInSampleSize(oldwidth,oldheight,reqWidth,reqHeight);
  451 +// options.inJustDecodeBounds = false;
  452 +// ByteArrayOutputStream baos = new ByteArrayOutputStream();
  453 +// bitmap.compress(Bitmap.CompressFormat.JPEG, 80 , baos); // 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
  454 +//
  455 +// ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray()); // 把压缩后的数据baos存放到ByteArrayInputStream中
  456 +// bitmap = BitmapFactory.decodeStream(isBm, null , options ); // 把ByteArrayInputStream数据生成图片
  457 +// double bitcount =bitmap.getByteCount()/1000;
  458 +// Log.e("StorageUtils", "这里压缩尺寸后的容量:" + bitcount + "---------------");
  459 +// return bitmap;
  460 + //上面这段代码在搞笑吧?
  461 +
  462 + if (oldwidth <= reqWidth && oldheight <= reqHeight)
  463 + return bitmap;
  464 + Bitmap ret = Bitmap.createScaledBitmap(bitmap, reqWidth, reqHeight, false);
  465 + bitmap.recycle();
  466 + return ret;
  467 + }
  468 +
  469 + /**
  470 + * 压缩bitmap到指定的尺寸
  471 + *
  472 + * @param image
  473 + * @param pixelW
  474 + * @param pixelH
  475 + * @return
  476 + */
  477 + public static Bitmap ratio(Bitmap image, float pixelW, float pixelH) {
  478 + ByteArrayOutputStream os = new ByteArrayOutputStream();
  479 + image.compress(Bitmap.CompressFormat.PNG, 100, os);
  480 + if (os.toByteArray().length / 1024 > 1024) {//判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出
  481 + os.reset();//重置baos即清空baos
  482 + image.compress(Bitmap.CompressFormat.PNG, 100, os);//这里压缩50%,把压缩后的数据存放到baos中
  483 + }
  484 + ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
  485 + BitmapFactory.Options newOpts = new BitmapFactory.Options();
  486 + //开始读入图片,此时把options.inJustDecodeBounds 设回true了
  487 + newOpts.inJustDecodeBounds = true;
  488 + newOpts.inPreferredConfig = Bitmap.Config.ARGB_8888;
  489 + Bitmap bitmap = BitmapFactory.decodeStream(is, null, newOpts);
  490 + newOpts.inJustDecodeBounds = false;
  491 + int w = newOpts.outWidth;
  492 + int h = newOpts.outHeight;
  493 + float hh = pixelH;// 设置高度为240f时,可以明显看到图片缩小了
  494 + float ww = pixelW;// 设置宽度为120f,可以明显看到图片缩小了
  495 + //缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
  496 + int be = 1;//be=1表示不缩放
  497 + if (w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
  498 + be = (int) (newOpts.outWidth / ww);
  499 + } else if (w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放
  500 + be = (int) (newOpts.outHeight / hh);
  501 + }
  502 + if (be <= 0) be = 1;
  503 + newOpts.inSampleSize = be;//设置缩放比例
  504 + //重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
  505 + is = new ByteArrayInputStream(os.toByteArray());
  506 + bitmap = BitmapFactory.decodeStream(is, null, newOpts);
  507 + //压缩好比例大小后再进行质量压缩
  508 +// return compress(bitmap, maxSize); // 这里再进行质量压缩的意义不大,反而耗资源,删除
  509 + return bitmap;
  510 + }
  511 +
  512 +
  513 + /**
  514 + * 计算图片的缩放值
  515 + */
  516 + public static int calculateInSampleSize(final int width, final int height, int reqWidth, int reqHeight) {
  517 + // Raw height and width of image
  518 +
  519 + int inSampleSize = 1;
  520 +
  521 + if (height > reqHeight || width > reqWidth) {//图片本身分辨率大于
  522 +
  523 + // Calculate ratios of height and width to requested height and
  524 + // width
  525 + final int heightRatio = Math.round((float) height / (float) reqHeight);
  526 + final int widthRatio = Math.round((float) width / (float) reqWidth);
  527 +
  528 + // Choose the smallest ratio as inSampleSize value, this will
  529 + // guarantee
  530 + // a final image with both dimensions larger than or equal to the
  531 + // requested height and width.
  532 + inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
  533 + }
  534 +
  535 + return inSampleSize;
  536 + }
  537 +
  538 +
  539 + /**
  540 + * 旋转图片角度
  541 + *
  542 + * @param bm
  543 + * @param orientationDegree
  544 + * @return
  545 + */
  546 + public static Bitmap adjustPhotoRotation(Bitmap bm, final int orientationDegree) {
  547 +
  548 + Matrix m = new Matrix();
  549 + m.setRotate(orientationDegree, (float) bm.getWidth() / 2, (float) bm.getHeight() / 2);
  550 + float targetX, targetY;
  551 + if (orientationDegree == 90) {
  552 + targetX = bm.getHeight();
  553 + targetY = 0;
  554 + } else {
  555 + targetX = bm.getHeight();
  556 + targetY = bm.getWidth();
  557 + }
  558 +
  559 + final float[] values = new float[9];
  560 + m.getValues(values);
  561 +
  562 + float x1 = values[Matrix.MTRANS_X];
  563 + float y1 = values[Matrix.MTRANS_Y];
  564 +
  565 + m.postTranslate(targetX - x1, targetY - y1);
  566 +
  567 + Bitmap bm1 = Bitmap.createBitmap(bm.getHeight(), bm.getWidth(), Bitmap.Config.ARGB_8888);
  568 + Paint paint = new Paint();
  569 + Canvas canvas = new Canvas(bm1);
  570 + canvas.drawBitmap(bm, m, paint);
  571 +
  572 + return bm1;
  573 + }
  574 +
  575 +
  576 + /**
  577 + * 查找视频文件对应于MediaStore的Uri
  578 + *
  579 + * @param file 视频文件
  580 + * @return
  581 + */
  582 +
  583 + public static Uri queryUriForVideo(Context context, File file) {
  584 + int id = getId(context, file);
  585 + if (id == -1) {
  586 + return null;
  587 + }
  588 +
  589 + return Uri.withAppendedPath(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, String.valueOf(id));
  590 + }
  591 +
  592 + /**
  593 + * 获得 指定视频文件F在MediaStore中对应的ID
  594 + *
  595 + * @param f 视频文件
  596 + * @return 对应ID
  597 + */
  598 +
  599 + private static int getId(Context context, File f) {
  600 + int id = -1;
  601 + // MediaStore.Video.Media.DATA:视频文件路径;
  602 + // MediaStore.Video.Media.DISPLAY_NAME : 视频文件名,如 testVideo.mp4
  603 + // MediaStore.Video.Media.TITLE: 视频标题 : testVideo
  604 + String[] mediaColumns = {MediaStore.Video.Media._ID,
  605 + MediaStore.Video.Media.DATA, MediaStore.Video.Media.TITLE,
  606 + MediaStore.Video.Media.MIME_TYPE,
  607 + MediaStore.Video.Media.DISPLAY_NAME};
  608 +
  609 + final String where = MediaStore.Video.Media.DATA + "=" + "?";
  610 +
  611 + Cursor cursor = ((Activity) context).managedQuery(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
  612 + mediaColumns, where, new String[]{f.getAbsolutePath()}, null);
  613 + if (cursor == null) {
  614 + //Toast.makeText(this, "没有找到可播放视频文件", 1).show();
  615 + return -1;
  616 + }
  617 + if (cursor.moveToFirst()) {
  618 + do {
  619 + id = cursor.getInt(cursor.getColumnIndex(MediaStore.Video.Media._ID));
  620 + //sysVideoList.add(info);
  621 + } while (cursor.moveToNext());
  622 + }
  623 + return id;
  624 + }
  625 +
  626 +
  627 + private final static String LINEND = "\r\n";
  628 + private final static String BOUNDARY = "---------------------------7da2137580612"; //数据分隔线
  629 + private final static String PREFIX = "--";
  630 +
  631 + /**
  632 + * 封装表单文本数据
  633 + *
  634 + * @param paramText
  635 + * @return
  636 + */
  637 + static String bulidFormText(Map<String, String> paramText) {
  638 + if (paramText == null || paramText.isEmpty()) return "";
  639 + StringBuffer sb = new StringBuffer("");
  640 + for (Map.Entry<String, String> entry : paramText.entrySet()) {
  641 + sb.append(PREFIX).append(BOUNDARY).append(LINEND);
  642 + sb.append("Content-Disposition:form-data;name=\""
  643 + + entry.getKey() + "\"" + LINEND);
  644 + //sb.append("Content-Type:text/plain;charset=" + CHARSET + LINEND);
  645 + sb.append(LINEND);
  646 + sb.append(entry.getValue());
  647 + sb.append(LINEND);
  648 + }
  649 + return sb.toString();
  650 + }
  651 +
  652 + private static final int TIME_OUT = 10 * 1000; // 超时时间
  653 + private static final String CHARSET = "UTF-8"; // 设置编码
  654 +
  655 + /**
  656 + * 上传文件到服务器
  657 + *
  658 + * @param file 需要上传的文件
  659 + * @param RequestURL 请求的rul
  660 + * @return 返回响应的内容
  661 + */
  662 + public static int uploadFile(File file, String RequestURL, Map<String, String> params) {
  663 + int res = 0;
  664 + String result = null;
  665 + //String BOUNDARY = "-xst--image--upload-"; // 边界标识 随机生成
  666 + //String PREFIX = "--", LINE_END = "\r\n";
  667 + String CONTENT_TYPE = "multipart/form-data"; // 内容类型
  668 +
  669 + try {
  670 + URL url = new URL(RequestURL);
  671 + HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  672 + conn.setReadTimeout(TIME_OUT);
  673 + conn.setConnectTimeout(TIME_OUT);
  674 + conn.setDoInput(true); // 允许输入流
  675 + conn.setDoOutput(true); // 允许输出流
  676 + conn.setUseCaches(false); // 不允许使用缓存
  677 + conn.setRequestMethod("POST"); // 请求方式
  678 + conn.setRequestProperty("Charset", CHARSET); // 设置编码
  679 + conn.setRequestProperty("connection", "keep-alive");
  680 + conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY);
  681 +
  682 + if (file != null) {
  683 + /**
  684 + * 当文件不为空时执行上传
  685 + */
  686 + DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
  687 + //构建表单数据
  688 + String entryText = bulidFormText(params);
  689 + //Log.e("-描述信息-", entryText);
  690 + dos.write(entryText.getBytes());
  691 +
  692 + StringBuffer sb = new StringBuffer();
  693 + sb.append(PREFIX);
  694 + sb.append(BOUNDARY);
  695 + sb.append(LINEND);
  696 + /**
  697 + * 这里重点注意: name里面的值为服务器端需要key 只有这个key 才可以得到对应的文件
  698 + * filename是文件的名字,包含后缀名
  699 + */
  700 +
  701 + sb.append("Content-Disposition: form-data; name=\"file\"; filename=\""
  702 + + file.getName() + "\"" + LINEND);
  703 + sb.append("Content-Type: application/octet-stream; charset="
  704 + + CHARSET + LINEND);
  705 + sb.append(LINEND);
  706 + dos.write(sb.toString().getBytes());
  707 + InputStream is = new FileInputStream(file);
  708 + byte[] bytes = new byte[1024];
  709 + int len = 0;
  710 + while ((len = is.read(bytes)) != -1) {
  711 + dos.write(bytes, 0, len);
  712 + }
  713 + is.close();
  714 + dos.write(LINEND.getBytes());
  715 + byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINEND).getBytes();
  716 + dos.write(end_data);
  717 + dos.flush();
  718 + /**
  719 + * 获取响应码 200=成功 当响应成功,获取响应的流
  720 + */
  721 + res = conn.getResponseCode();
  722 + Log.e(TAG, "response code:" + res);
  723 + if (res == 200) {
  724 + InputStream input = conn.getInputStream();
  725 + StringBuffer sb1 = new StringBuffer();
  726 + String line = "";
  727 + BufferedReader br = new BufferedReader(new InputStreamReader(input, "UTF-8"));//UTF-8,utf-8,GBK,gbk
  728 + while ((line = br.readLine()) != null) {
  729 + sb1.append(line);
  730 + }
  731 + Log.e(TAG, "--result : " + sb1.toString());
  732 +
  733 + } else {
  734 + Log.e(TAG, "--request error");
  735 + }
  736 + }
  737 + } catch (MalformedURLException e) {
  738 + e.printStackTrace();
  739 + } catch (Exception e) {
  740 + e.printStackTrace();
  741 + }
  742 + return res;
  743 + }
  744 +
  745 +
  746 + public static void zip(String src, String dest) throws IOException {
  747 + //提供了一个数据项压缩成一个ZIP归档输出流
  748 + ZipOutputStream out = null;
  749 + try {
  750 + File outFile = new File(dest);//源文件或者目录
  751 + File fileOrDirectory = new File(src);//压缩文件路径
  752 + out = new ZipOutputStream(new FileOutputStream(outFile));
  753 + //如果此文件是一个文件,否则为false。
  754 + if (fileOrDirectory.isFile()) {
  755 + zipFileOrDirectory(out, fileOrDirectory, "");
  756 + } else {
  757 + //返回一个文件或空阵列。
  758 + File[] entries = fileOrDirectory.listFiles();
  759 + for (int i = 0; i < entries.length; i++) {
  760 + // 递归压缩,更新curPaths
  761 + zipFileOrDirectory(out, entries[i], "");
  762 + }
  763 + }
  764 + } catch (IOException ex) {
  765 + ex.printStackTrace();
  766 + } finally {
  767 + //关闭输出流
  768 + if (out != null) {
  769 + try {
  770 + out.close();
  771 + } catch (IOException ex) {
  772 + ex.printStackTrace();
  773 + }
  774 + }
  775 + }
  776 + }
  777 +
  778 + private static void zipFileOrDirectory(ZipOutputStream out, File fileOrDirectory, String curPath) throws IOException {
  779 + //从文件中读取字节的输入流
  780 + FileInputStream in = null;
  781 + try {
  782 + //如果此文件是一个目录,否则返回false。
  783 + if (!fileOrDirectory.isDirectory()) {
  784 + // 压缩文件
  785 + byte[] buffer = new byte[4096];
  786 + int bytes_read;
  787 + in = new FileInputStream(fileOrDirectory);
  788 + //实例代表一个条目内的ZIP归档
  789 + ZipEntry entry = new ZipEntry(curPath + fileOrDirectory.getName());
  790 + //条目的信息写入底层流
  791 + out.putNextEntry(entry);
  792 + while ((bytes_read = in.read(buffer)) != -1) {
  793 + out.write(buffer, 0, bytes_read);
  794 + }
  795 + out.closeEntry();
  796 + } else {
  797 + // 压缩目录
  798 + File[] entries = fileOrDirectory.listFiles();
  799 + for (int i = 0; i < entries.length; i++) {
  800 + // 递归压缩,更新curPaths
  801 + zipFileOrDirectory(out, entries[i], curPath + fileOrDirectory.getName() + "/");
  802 + }
  803 + }
  804 + } catch (IOException ex) {
  805 + ex.printStackTrace();
  806 + Log.e("dhj", "zipFileOrDirectory: 出错");
  807 + // throw ex;
  808 + } finally {
  809 + if (in != null) {
  810 + try {
  811 + in.close();
  812 + } catch (IOException ex) {
  813 + ex.printStackTrace();
  814 + }
  815 + }
  816 + }
  817 + }
  818 +
  819 + private void getScreenHot(View v, String filePath) {
  820 + try {
  821 + Bitmap bitmap = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
  822 + Canvas canvas = new Canvas();
  823 + canvas.setBitmap(bitmap);
  824 + v.draw(canvas);
  825 + FileOutputStream fos = new FileOutputStream(filePath);
  826 + bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
  827 +
  828 + } catch (Exception e) {
  829 + e.printStackTrace();
  830 + }
  831 + }
  832 +
  833 + /**
  834 + * 保存日志到指定文件夹下
  835 + *
  836 + * @param filename 日志文件名字 AppConfig.DEFAULT_SAVE_LOG_PATH + DateUtils.getDateFormat(new Date(), "yyyyMMdd") + "_"+filename+".txt";
  837 + * @param text 日志内容
  838 + */
  839 + /* public static void fileLog(String filename, String text) {
  840 + File logPath = new File(AppConfig.DEFAULT_SAVE_LOG_PATH);
  841 + if (!logPath.exists()) {
  842 + logPath.mkdirs();
  843 + }
  844 + String logfilePath = AppConfig.DEFAULT_SAVE_LOG_PATH + DateUtils.getDateFormat(new Date(), "yyyyMMdd") + "_" + filename + ".txt";
  845 + File logFile = new File(logfilePath);
  846 + try {
  847 + if (!logFile.exists()) logFile.createNewFile();
  848 + String log = String.format("[%s][%s][%s]: %s\r\n", filename, SystemUtils.getDeviceIdLite(AppContext.getInstance()), DateUtils.getDateFormat(new Date(), "yyyy-MM-dd HH:mm:ss"), text);
  849 + RandomAccessFile raf = new RandomAccessFile(logFile, "rwd");
  850 + raf.seek(logFile.length());
  851 + raf.write(log.getBytes());
  852 + raf.close();
  853 + } catch (IOException e) {
  854 + e.printStackTrace();
  855 + }
  856 + }*/
  857 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/StringUtils.java 0 → 100644
@@ -0,0 +1,152 @@ @@ -0,0 +1,152 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.text.TextUtils;
  4 +import android.util.Base64;
  5 +
  6 +import java.util.regex.Matcher;
  7 +import java.util.regex.Pattern;
  8 +
  9 +/**
  10 + * Created by Horrarndoo on 2017/4/5.
  11 + * 字符串工具类
  12 + */
  13 +public class StringUtils {
  14 + /**
  15 + * 判断字符串是否有值,如果为null或者是空字符串或者只有空格或者为"null"字符串,则返回true,否则则返回false
  16 + */
  17 + public static boolean isEmpty(String value) {
  18 + return !(value != null && !"".equalsIgnoreCase(value.trim())
  19 + && !"null".equalsIgnoreCase(value.trim()));
  20 + }
  21 +
  22 + /**
  23 + * 判断字符串是否是邮箱
  24 + *
  25 + * @param email email
  26 + * @return 字符串是否是邮箱
  27 + */
  28 + public static boolean isEmail(String email) {
  29 + String str = "^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(" +
  30 + "([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$";
  31 + Pattern p = Pattern.compile(str);
  32 + Matcher m = p.matcher(email);
  33 + return m.matches();
  34 + }
  35 +
  36 + /**
  37 + * 判断手机号字符串是否合法
  38 + *
  39 + * @param phoneNumber 手机号字符串
  40 + * @return 手机号字符串是否合法
  41 + */
  42 + public static boolean isPhoneNumberValid(String phoneNumber) {
  43 + boolean isValid = false;
  44 + String expression = "^1[3|4|5|7|8]\\d{9}$";
  45 + CharSequence inputStr = phoneNumber;
  46 + Pattern pattern = Pattern.compile(expression);
  47 + Matcher matcher = pattern.matcher(inputStr);
  48 + if (matcher.matches()) {
  49 + isValid = true;
  50 + }
  51 + return isValid;
  52 + }
  53 +
  54 + /**
  55 + * 判断手机号字符串是否合法
  56 + *
  57 + * @param areaCode 区号
  58 + * @param phoneNumber 手机号字符串
  59 + * @return 手机号字符串是否合法
  60 + */
  61 + public static boolean isPhoneNumberValid(String areaCode, String phoneNumber) {
  62 + if (TextUtils.isEmpty(phoneNumber)) {
  63 + return false;
  64 + }
  65 +
  66 + if (phoneNumber.length() < 5) {
  67 + return false;
  68 + }
  69 +
  70 + if (TextUtils.equals(areaCode, "+86") || TextUtils.equals(areaCode, "86")) {
  71 + return isPhoneNumberValid(phoneNumber);
  72 + }
  73 +
  74 + boolean isValid = false;
  75 + String expression = "^[0-9]*$";
  76 + CharSequence inputStr = phoneNumber;
  77 + Pattern pattern = Pattern.compile(expression);
  78 + Matcher matcher = pattern.matcher(inputStr);
  79 + if (matcher.matches()) {
  80 + isValid = true;
  81 + }
  82 + return isValid;
  83 + }
  84 +
  85 + /**
  86 + * 判断字符串是否是手机号格式
  87 + *
  88 + * @param areaCode 区号
  89 + * @param phoneNumber 手机号字符串
  90 + * @return 字符串是否是手机号格式
  91 + */
  92 + public static boolean isPhoneFormat(String areaCode, String phoneNumber) {
  93 + if (TextUtils.isEmpty(phoneNumber)) {
  94 + return false;
  95 + }
  96 +
  97 + if (phoneNumber.length() < 7) {
  98 + return false;
  99 + }
  100 +
  101 + boolean isValid = false;
  102 + String expression = "^[0-9]*$";
  103 + CharSequence inputStr = phoneNumber;
  104 + Pattern pattern = Pattern.compile(expression);
  105 + Matcher matcher = pattern.matcher(inputStr);
  106 + if (matcher.matches()) {
  107 + isValid = true;
  108 + }
  109 + return isValid;
  110 + }
  111 +
  112 + /**
  113 + * 判断字符串是否为纯数字
  114 + *
  115 + * @param str 字符串
  116 + * @return 是否纯数字
  117 + */
  118 + public static boolean isNumber(String str) {
  119 + for (int i = 0; i < str.length(); i++) {
  120 + if (!Character.isDigit(str.charAt(i))) {
  121 + return false;
  122 + }
  123 + }
  124 + return true;
  125 + }
  126 +
  127 + private final static String appSecret = "f71467cfd98d";
  128 + public static String getSign(){
  129 + String sign = "";
  130 + try {
  131 + String clientid = MD5(System.currentTimeMillis() + new int[(int) (Math.random() * 100)].toString());
  132 + sign = "Basic " + Base64.encodeToString((clientid + ":" + MD5(clientid + appSecret)).getBytes("ASCII"), Base64.NO_WRAP);
  133 + } catch (Exception err) {
  134 + err.printStackTrace();
  135 + }
  136 + return sign;
  137 + }
  138 +
  139 + public static String MD5(String str) {
  140 + try {
  141 + java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
  142 + byte[] array = md.digest(str.getBytes("utf-8"));
  143 + StringBuffer sb = new StringBuffer();
  144 + for (int i = 0; i < array.length; ++i) {
  145 + sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1, 3));
  146 + }
  147 + return sb.toString().toUpperCase();
  148 + } catch (Exception e) {
  149 + }
  150 + return "";
  151 + }
  152 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/ThemeUtils.java 0 → 100644
@@ -0,0 +1,75 @@ @@ -0,0 +1,75 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.content.Context;
  4 +import android.content.res.TypedArray;
  5 +import android.support.annotation.AttrRes;
  6 +import android.support.annotation.NonNull;
  7 +
  8 +import com.share.mvpsdk.R;
  9 +
  10 +
  11 +/**
  12 + * 作者:杭鹏伟
  13 + * 日期:16-7-8 15:15
  14 + * 邮箱:424346976@qq.com
  15 + */
  16 +public class ThemeUtils {
  17 + public static int[][] themeArr = {
  18 + {R.style.AppThemeLight_Red, R.style.AppThemeDark_Red},
  19 + {R.style.AppThemeLight_Pink, R.style.AppThemeDark_Pink},
  20 + {R.style.AppThemeLight_Purple, R.style.AppThemeDark_Purple},
  21 + {R.style.AppThemeLight_DeepPurple, R.style.AppThemeDark_DeepPurple},
  22 + {R.style.AppThemeLight_Indigo, R.style.AppThemeDark_Indigo},
  23 + {R.style.AppThemeLight_Blue, R.style.AppThemeDark_Blue},
  24 + {R.style.AppThemeLight_LightBlue, R.style.AppThemeDark_LightBlue},
  25 + {R.style.AppThemeLight_Cyan, R.style.AppThemeDark_Cyan},
  26 + {R.style.AppThemeLight_Teal, R.style.AppThemeDark_Teal},
  27 + {R.style.AppThemeLight_Green, R.style.AppThemeDark_Green},
  28 + {R.style.AppThemeLight_LightGreen, R.style.AppThemeDark_LightGreen},
  29 + {R.style.AppThemeLight_Lime, R.style.AppThemeDark_Lime},
  30 + {R.style.AppThemeLight_Yellow, R.style.AppThemeDark_Yellow},
  31 + {R.style.AppThemeLight_Amber, R.style.AppThemeDark_Amber},
  32 + {R.style.AppThemeLight_Orange, R.style.AppThemeDark_Orange},
  33 + {R.style.AppThemeLight_DeepOrange, R.style.AppThemeDark_DeepOrange},
  34 + {R.style.AppThemeLight_Brown, R.style.AppThemeDark_Brown},
  35 + {R.style.AppThemeLight_Grey, R.style.AppThemeDark_Grey},
  36 + {R.style.AppThemeLight_BlueGrey, R.style.AppThemeDark_BlueGrey}
  37 + };
  38 +
  39 + public static int[][] themeColorArr = {
  40 + {R.color.md_red_500, R.color.md_red_700}, {R.color.md_pink_500, R.color.md_pink_700},
  41 + {R.color.md_purple_500, R.color.md_purple_700},
  42 + {R.color.md_deep_purple_500, R.color.md_deep_purple_700},
  43 + {R.color.md_indigo_500, R.color.md_indigo_700},
  44 + {R.color.md_blue_500, R.color.md_blue_700},
  45 + {R.color.md_light_blue_500, R.color.md_light_blue_700},
  46 + {R.color.md_cyan_500, R.color.md_cyan_700}, {R.color.md_teal_500, R.color.md_teal_500},
  47 + {R.color.md_green_500, R.color.md_green_500},
  48 + {R.color.md_light_green_500, R.color.md_light_green_500},
  49 + {R.color.md_lime_500, R.color.md_lime_700},
  50 + {R.color.md_yellow_500, R.color.md_yellow_700},
  51 + {R.color.md_amber_500, R.color.md_amber_700},
  52 + {R.color.md_orange_500, R.color.md_orange_700},
  53 + {R.color.md_deep_orange_500, R.color.md_deep_orange_700},
  54 + {R.color.md_brown_500, R.color.md_brown_700}, {R.color.md_grey_500, R.color.md_grey_700},
  55 + {R.color.md_blue_grey_500, R.color.md_blue_grey_700}
  56 + };
  57 +
  58 + public static int getTheme(Context context) {
  59 + return context.getResources()
  60 + .getColor(themeColorArr[SpUtils.getThemeIndex(context)][0]);
  61 + }
  62 +
  63 + public static int getThemeColor(@NonNull Context context) {
  64 + return getThemeAttrColor(context, R.attr.colorPrimary);
  65 + }
  66 +
  67 + public static int getThemeAttrColor(@NonNull Context context, @AttrRes int attr) {
  68 + TypedArray a = context.obtainStyledAttributes(null, new int[]{attr});
  69 + try {
  70 + return a.getColor(0, 0);
  71 + } finally {
  72 + a.recycle();
  73 + }
  74 + }
  75 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/TimestampUtils.java 0 → 100644
@@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import java.text.SimpleDateFormat;
  4 +import java.util.Date;
  5 +import java.util.TimeZone;
  6 +
  7 +public class TimestampUtils {
  8 + /**
  9 + * 获取当前的时间戳,时区为北京
  10 + *
  11 + * @return
  12 + */
  13 + public static String getCurrentTimestamp() {
  14 + //时间戳的格式必须为 yyyy-MM-dd HH:mm:ss
  15 + String timestamp = null;
  16 + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  17 + timestamp = format.format(new Date());
  18 + return timestamp;
  19 + }
  20 +
  21 + /**
  22 + * 获取当前的时间戳,时区为北京
  23 + *
  24 + * @return
  25 + */
  26 + public static String getCurrentTime(long times) {
  27 + //时间戳的格式必须为 yyyy-MM-dd HH:mm:ss
  28 + Date date = new Date(Long.valueOf(times));
  29 + SimpleDateFormat format = new SimpleDateFormat(
  30 + "yyyy-MM-dd HH:mm:ss");
  31 + String time = format.format(date);
  32 + LogUtils.e("timetimetimetimetimetimetime为:" + time);
  33 +
  34 + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
  35 + .format(new Date());
  36 +
  37 + return time;
  38 + }
  39 +
  40 + //法国时间:东一区
  41 + public static String getDateTimeByGMT(int timeZone) {
  42 + SimpleDateFormat dff = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  43 + switch (timeZone) {
  44 + case 1:
  45 + dff.setTimeZone(TimeZone.getTimeZone("GMT+1"));
  46 + break;
  47 + case 8:
  48 + dff.setTimeZone(TimeZone.getTimeZone("GMT+8"));
  49 + //LogUtils.i("采用东八区时区");
  50 + break;
  51 + }
  52 +
  53 + String time = dff.format(new Date());
  54 + //LogUtils.i("东八区时区时间为--》》" + time);
  55 + return time;
  56 + }
  57 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/ToastUtils.java 0 → 100644
@@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.content.Context;
  4 +import android.widget.Toast;
  5 +
  6 +/**
  7 + * Created by Horrarndoo on 2017/4/5.
  8 + * <p>
  9 + * toast工具类封装
  10 + */
  11 +public class ToastUtils {
  12 + private static Toast mToast = null;
  13 +
  14 + /**
  15 + * 显示一个toast提示
  16 + *
  17 + * @param resouceId toast字符串资源id
  18 + */
  19 + public static void showToast(int resouceId) {
  20 + showToast(ResourcesUtils.getString(resouceId));
  21 + }
  22 +
  23 + /**
  24 + * 显示一个toast提示
  25 + *
  26 + * @param text toast字符串
  27 + */
  28 + public static void showToast(String text) {
  29 + showToast(text, Toast.LENGTH_SHORT);
  30 + }
  31 +
  32 + /**
  33 + * 显示一个toast提示
  34 + *
  35 + * @param text toast字符串
  36 + * @param duration toast显示时间
  37 + */
  38 + public static void showToast(String text, int duration) {
  39 + showToast(AppUtils.getContext(), text, duration);
  40 + }
  41 +
  42 + /**
  43 + * 显示一个toast提示
  44 + *
  45 + * @param context context 上下文对象
  46 + * @param text toast字符串
  47 + * @param duration toast显示时间
  48 + */
  49 + public static void showToast(final Context context, final String text, final int duration) {
  50 + /**
  51 + * 保证运行在主线程
  52 + */
  53 + AppUtils.runOnUIThread(new Runnable() {
  54 + @Override
  55 + public void run() {
  56 + if (mToast == null) {
  57 + mToast = Toast.makeText(context, text, duration);
  58 + } else {
  59 + mToast.setText(text);
  60 + mToast.setDuration(duration);
  61 + }
  62 + mToast.show();
  63 + }
  64 + });
  65 + }
  66 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/UnicodeUtils.java 0 → 100644
@@ -0,0 +1,108 @@ @@ -0,0 +1,108 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +/**
  4 + * Created by Horrarndoo on 2017/10/11.
  5 + * <p>
  6 + */
  7 +public class UnicodeUtils {
  8 + /**
  9 + * utf-8 转换成 unicode
  10 + *
  11 + * @param inStr
  12 + * @return
  13 + */
  14 + public static String utf8ToUnicode(String inStr) {
  15 + char[] myBuffer = inStr.toCharArray();
  16 +
  17 + StringBuffer sb = new StringBuffer();
  18 + for (int i = 0; i < inStr.length(); i++) {
  19 + Character.UnicodeBlock ub = Character.UnicodeBlock.of(myBuffer[i]);
  20 + if (ub == Character.UnicodeBlock.BASIC_LATIN) {
  21 + //英文及数字等
  22 + sb.append(myBuffer[i]);
  23 + } else if (ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) {
  24 + //全角半角字符
  25 + int j = (int) myBuffer[i] - 65248;
  26 + sb.append((char) j);
  27 + } else {
  28 + //汉字
  29 + short s = (short) myBuffer[i];
  30 + String hexS = Integer.toHexString(s);
  31 + String unicode = "\\u" + hexS;
  32 + sb.append(unicode.toLowerCase());
  33 + }
  34 + }
  35 + return sb.toString();
  36 + }
  37 +
  38 + /**
  39 + * unicode 转换成 utf-8
  40 + *
  41 + * @param theString
  42 + * @return
  43 + */
  44 + public static String unicodeToUtf8(String theString) {
  45 + char aChar;
  46 + int len = theString.length();
  47 + StringBuffer outBuffer = new StringBuffer(len);
  48 + for (int x = 0; x < len; ) {
  49 + aChar = theString.charAt(x++);
  50 + if (aChar == '\\') {
  51 + aChar = theString.charAt(x++);
  52 + if (aChar == 'u') {
  53 + // Read the xxxx
  54 + int value = 0;
  55 + for (int i = 0; i < 4; i++) {
  56 + aChar = theString.charAt(x++);
  57 + switch (aChar) {
  58 + case '0':
  59 + case '1':
  60 + case '2':
  61 + case '3':
  62 + case '4':
  63 + case '5':
  64 + case '6':
  65 + case '7':
  66 + case '8':
  67 + case '9':
  68 + value = (value << 4) + aChar - '0';
  69 + break;
  70 + case 'a':
  71 + case 'b':
  72 + case 'c':
  73 + case 'd':
  74 + case 'e':
  75 + case 'f':
  76 + value = (value << 4) + 10 + aChar - 'a';
  77 + break;
  78 + case 'A':
  79 + case 'B':
  80 + case 'C':
  81 + case 'D':
  82 + case 'E':
  83 + case 'F':
  84 + value = (value << 4) + 10 + aChar - 'A';
  85 + break;
  86 + default:
  87 + throw new IllegalArgumentException(
  88 + "Malformed \\uxxxx encoding.");
  89 + }
  90 + }
  91 + outBuffer.append((char) value);
  92 + } else {
  93 + if (aChar == 't')
  94 + aChar = '\t';
  95 + else if (aChar == 'r')
  96 + aChar = '\r';
  97 + else if (aChar == 'n')
  98 + aChar = '\n';
  99 + else if (aChar == 'f')
  100 + aChar = '\f';
  101 + outBuffer.append(aChar);
  102 + }
  103 + } else
  104 + outBuffer.append(aChar);
  105 + }
  106 + return outBuffer.toString();
  107 + }
  108 +}
0 \ No newline at end of file 109 \ No newline at end of file
mvpsdk/src/main/java/com/share/mvpsdk/utils/ValueUtils.java 0 → 100644
@@ -0,0 +1,222 @@ @@ -0,0 +1,222 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.support.annotation.NonNull;
  4 +import android.support.annotation.Nullable;
  5 +import android.support.v4.app.NotificationCompat;
  6 +
  7 +import com.share.mvpsdk.view.chartview.data.Chart;
  8 +import com.share.mvpsdk.view.chartview.data.ChartPath;
  9 +import com.share.mvpsdk.view.chartview.data.DrawData;
  10 +import com.share.mvpsdk.view.chartview.data.InputData;
  11 +
  12 +import java.util.ArrayList;
  13 +import java.util.List;
  14 +import java.util.ListIterator;
  15 +
  16 +public class ValueUtils {
  17 +
  18 + public static float getCorrectedMaxValue(float maxValue) {
  19 + for (float value = maxValue; value >= Chart.CHART_PART_VALUE; value--) {
  20 + if (isRightValue(value)) {
  21 + return value;
  22 + }
  23 + }
  24 +
  25 + return maxValue;
  26 + }
  27 +
  28 + public static float max(@Nullable List<ChartPath> dataList) {
  29 + float maxValue = 0;
  30 +
  31 + if (dataList == null || dataList.isEmpty()) {
  32 + return maxValue;
  33 + }
  34 + for (ChartPath charpath :
  35 + dataList) {
  36 + for (InputData data : charpath.inputDataList) {
  37 + if (data.valueY > maxValue) {
  38 + maxValue = data.valueY;
  39 + }
  40 + }
  41 + }
  42 +
  43 + return maxValue;
  44 + }
  45 +
  46 + private static long getMax(long max) {
  47 + if (max < 10) {
  48 + max = 10;
  49 + } else if (max / 10 < 10) {
  50 + max = (max / 10 + 1) * 10;
  51 + } else if (max / 100 < 10) {
  52 + max = (max / 100 + 1) * 100;
  53 + } else if (max / 1000 < 10) {
  54 + max = (max / 1000 + 1) * 1000;
  55 + }
  56 + return max;
  57 + }
  58 +
  59 + private static float maxOne(List<InputData> dataList) {
  60 + float maxValue = 0;
  61 +
  62 + if (dataList == null || dataList.isEmpty()) {
  63 + return maxValue;
  64 + }
  65 + for (InputData data : dataList) {
  66 + if (data.valueY > maxValue) {
  67 + maxValue = data.valueY;
  68 + }
  69 + }
  70 +
  71 + return maxValue;
  72 + }
  73 +
  74 + private static boolean isRightValue(float value) {
  75 + float valueResidual = value % Chart.CHART_PART_VALUE;
  76 + return valueResidual == 0;
  77 + }
  78 +
  79 + @NotificationCompat.NotificationVisibility
  80 + public static List<DrawData> getDrawData(@Nullable Chart chart) {
  81 + if (chart == null || chart.getInputDataList()==null||chart.getInputDataList().isEmpty()) {
  82 + return new ArrayList<>();
  83 + }
  84 +
  85 + List<InputData> dataList = chart.getInputDataList();
  86 +// correctDataListSize(dataList);//移除多余的数据
  87 + return createDrawDataList(chart, createValueList(dataList));
  88 + }
  89 +
  90 + @NotificationCompat.NotificationVisibility
  91 + public static List<DrawData> getDrawDatas(@Nullable List<InputData> inputDataList, @NonNull Chart chart) {
  92 + return createDrawDataList(chart, createValueList(inputDataList));
  93 + }
  94 +
  95 +// private static void correctDataListSize(@NonNull List<InputData> dataList) {
  96 +// if (dataList.size() < Chart.MAX_ITEMS_COUNT) {
  97 +// addLackingItems(dataList);
  98 +//
  99 +// } else if (dataList.size() > Chart.MAX_ITEMS_COUNT) {
  100 +// removeExcessItems(dataList);
  101 +// }
  102 +// }
  103 +//
  104 +// private static void addLackingItems(@NonNull List<InputData> dataList) {
  105 +// for (int i = dataList.size(); i < Chart.MAX_ITEMS_COUNT; i++) {
  106 +// long millis = dataList.get(0).valueX - TimeUnit.DAYS.toMillis(1);
  107 +// if (millis < 0) {
  108 +// millis = 0;
  109 +// }
  110 +//
  111 +// dataList.add(0, new InputData(0, millis));
  112 +// }
  113 +// }
  114 +
  115 + private static void removeExcessItems(@NonNull List<InputData> dataList) {
  116 + for (ListIterator<InputData> iterator = dataList.listIterator(); iterator.hasNext(); ) {
  117 + if (iterator.nextIndex() > Chart.MAX_ITEMS_COUNT) {
  118 + iterator.remove();
  119 + return;
  120 + }
  121 + iterator.next();
  122 + }
  123 + }
  124 +
  125 + public static float topValue = 0.00f;
  126 +
  127 + public static void calMax(List<ChartPath> chartPathList) {
  128 +
  129 + for (int i = 0; i < chartPathList.size(); i++) {
  130 + createValueList(chartPathList.get(i).inputDataList);
  131 + }
  132 + }
  133 +
  134 + private static List<Float> createValueList(@NonNull List<InputData> dataList) {
  135 + List<Float> valueList = new ArrayList<>();
  136 + topValue = topValue > ValueUtils.maxOne(dataList) ? topValue : ValueUtils.maxOne(dataList);//取最大值
  137 +
  138 + for (InputData data : dataList) {
  139 + float value = data.valueY / topValue;
  140 + valueList.add(value);
  141 + }
  142 +
  143 + return valueList;
  144 + }
  145 +
  146 + @NonNull
  147 + private static List<DrawData> createDrawDataList(@NonNull Chart chart, @NonNull List<Float> valueList) {
  148 + List<DrawData> drawDataList = new ArrayList<>();
  149 + for (int i = 0; i < valueList.size() - 1; i++) {
  150 + DrawData drawData = createDrawData(chart, valueList, i);
  151 + drawDataList.add(drawData);
  152 + }
  153 + return drawDataList;
  154 + }
  155 +
  156 + @NonNull
  157 + private static DrawData createDrawData(@NonNull Chart chart, @NonNull List<Float> valueList, int position) {
  158 + DrawData drawData = new DrawData();
  159 + if (position > valueList.size() - 1) {
  160 + return drawData;
  161 + }
  162 +
  163 + float value = valueList.get(position);
  164 + float startX = getCoordinateX(chart, position);
  165 + float startY = getCoordinateY(chart, value);
  166 + drawData.startX = startX;
  167 + drawData.startY = startY;
  168 +// drawData.setStartX(startX);
  169 +// drawData.setStartY(startY);
  170 + int nextPosition = position + 1;
  171 + if (nextPosition < valueList.size()) {
  172 + float nextValue = valueList.get(nextPosition);
  173 + float stopX = getCoordinateX(chart, nextPosition);
  174 + float stopY = getCoordinateY(chart, nextValue);
  175 +
  176 +// drawData.setStopX(stopX);
  177 +// drawData.setStopY(stopY);
  178 +
  179 + drawData.stopX = stopX;
  180 + drawData.stopY = stopY;
  181 + }
  182 +
  183 + return drawData;
  184 + }
  185 +
  186 + @SuppressWarnings("UnnecessaryLocalVariable")
  187 + private static float getCoordinateX(@NonNull Chart chart, int index) {
  188 + float width = chart.width;
  189 + float titleWidth = chart.titleWidth;
  190 +
  191 + float widthCorrected = width - titleWidth;
  192 + float partWidth = widthCorrected / (Chart.MAX_ITEMS_COUNT - 1);
  193 + float coordinate = titleWidth + (partWidth * index);
  194 +
  195 + if (coordinate < 0) {
  196 + coordinate = 0;
  197 +
  198 + } else if (coordinate > width) {
  199 + coordinate = width;
  200 + }
  201 +
  202 + return coordinate;
  203 + }
  204 +
  205 + @SuppressWarnings("UnnecessaryLocalVariable")
  206 + private static float getCoordinateY(@NonNull Chart chart, float value) {
  207 + float height = chart.height - chart.padding - chart.textSize;
  208 + float heightOffset = chart.heightOffset;
  209 + float heightCorrected = height - heightOffset;
  210 + float coordinate = (heightCorrected - (heightCorrected * value));
  211 + if (coordinate < 0) {
  212 + coordinate = 0;
  213 +
  214 + } else if (coordinate > heightCorrected) {
  215 + coordinate = heightCorrected;
  216 + }
  217 +
  218 + coordinate += heightOffset;
  219 + return coordinate;
  220 + }
  221 +
  222 +}
mvpsdk/src/main/java/com/share/mvpsdk/utils/WifiAutoConnectManager.java 0 → 100644
@@ -0,0 +1,224 @@ @@ -0,0 +1,224 @@
  1 +package com.share.mvpsdk.utils;
  2 +
  3 +import android.content.Context;
  4 +import android.net.wifi.ScanResult;
  5 +import android.net.wifi.WifiConfiguration;
  6 +import android.net.wifi.WifiManager;
  7 +
  8 +import java.util.List;
  9 +
  10 +/**
  11 + * Created by Horrarndoo on 2017/8/10.
  12 + * <p>
  13 + * 兼容Android 6.0以上手机连接wifi
  14 + */
  15 +
  16 +public class WifiAutoConnectManager {
  17 +
  18 + private static final String TAG = WifiAutoConnectManager.class
  19 + .getSimpleName();
  20 +
  21 + WifiManager wifiManager;
  22 +
  23 + // 定义几种加密方式,一种是WEP,一种是WPA,还有没有密码的情况
  24 + public enum WifiCipherType {
  25 + WIFICIPHER_WEP, WIFICIPHER_WPA, WIFICIPHER_NOPASS, WIFICIPHER_INVALID
  26 + }
  27 +
  28 + // 构造函数
  29 + public WifiAutoConnectManager(WifiManager wifiManager) {
  30 + this.wifiManager = wifiManager;
  31 + }
  32 +
  33 + // 提供一个外部接口,传入要连接的无线网
  34 + public void connect(String ssid, String password, WifiCipherType type) {
  35 + Thread thread = new Thread(new ConnectRunnable(ssid, password, type));
  36 + thread.start();
  37 + }
  38 +
  39 + // 查看以前是否也配置过这个网络
  40 + private WifiConfiguration isExsits(String SSID) {
  41 + List<WifiConfiguration> existingConfigs = wifiManager
  42 + .getConfiguredNetworks();
  43 + for (WifiConfiguration existingConfig : existingConfigs) {
  44 + if (existingConfig.SSID.equals("\"" + SSID + "\"")) {
  45 + return existingConfig;
  46 + }
  47 + }
  48 + return null;
  49 + }
  50 +
  51 + private WifiConfiguration createWifiInfo(String SSID, String Password,
  52 + WifiCipherType Type) {
  53 + WifiConfiguration config = new WifiConfiguration();
  54 + config.allowedAuthAlgorithms.clear();
  55 + config.allowedGroupCiphers.clear();
  56 + config.allowedKeyManagement.clear();
  57 + config.allowedPairwiseCiphers.clear();
  58 + config.allowedProtocols.clear();
  59 + config.SSID = "\"" + SSID + "\"";
  60 + // config.SSID = SSID;
  61 + // nopass
  62 + if (Type == WifiCipherType.WIFICIPHER_NOPASS) {
  63 + // config.wepKeys[0] = "";
  64 + config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
  65 + // config.wepTxKeyIndex = 0;
  66 + }
  67 + // wep
  68 + if (Type == WifiCipherType.WIFICIPHER_WEP) {
  69 + if (!StringUtils.isEmpty(Password)) {
  70 + if (isHexWepKey(Password)) {
  71 + config.wepKeys[0] = Password;
  72 + } else {
  73 + config.wepKeys[0] = "\"" + Password + "\"";
  74 + }
  75 + }
  76 + config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
  77 + config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
  78 + config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
  79 + config.wepTxKeyIndex = 0;
  80 + }
  81 + // wpa
  82 + if (Type == WifiCipherType.WIFICIPHER_WPA) {
  83 + config.preSharedKey = "\"" + Password + "\"";
  84 + config.hiddenSSID = true;
  85 + config.allowedAuthAlgorithms
  86 + .set(WifiConfiguration.AuthAlgorithm.OPEN);
  87 + config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
  88 + config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
  89 + config.allowedPairwiseCiphers
  90 + .set(WifiConfiguration.PairwiseCipher.TKIP);
  91 + // 此处需要修改否则不能自动重联
  92 + // config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
  93 + config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
  94 + config.allowedPairwiseCiphers
  95 + .set(WifiConfiguration.PairwiseCipher.CCMP);
  96 + config.status = WifiConfiguration.Status.ENABLED;
  97 +
  98 + }
  99 + return config;
  100 + }
  101 +
  102 + // 打开wifi功能
  103 + private boolean openWifi() {
  104 + boolean bRet = true;
  105 + if (!wifiManager.isWifiEnabled()) {
  106 + bRet = wifiManager.setWifiEnabled(true);
  107 + }
  108 + return bRet;
  109 + }
  110 +
  111 + // 关闭WIFI
  112 + private void closeWifi() {
  113 + if (wifiManager.isWifiEnabled()) {
  114 + wifiManager.setWifiEnabled(false);
  115 + }
  116 + }
  117 +
  118 + class ConnectRunnable implements Runnable {
  119 + private String ssid;
  120 +
  121 + private String password;
  122 +
  123 + private WifiCipherType type;
  124 +
  125 + public ConnectRunnable(String ssid, String password, WifiCipherType type) {
  126 + this.ssid = ssid;
  127 + this.password = password;
  128 + this.type = type;
  129 + }
  130 +
  131 + @Override
  132 + public void run() {
  133 + // 打开wifi
  134 + openWifi();
  135 + // 开启wifi功能需要一段时间(我在手机上测试一般需要1-3秒左右),所以要等到wifi
  136 + // 状态变成WIFI_STATE_ENABLED的时候才能执行下面的语句
  137 + while (wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLING) {
  138 + try {
  139 + // 为了避免程序一直while循环,让它睡个100毫秒检测……
  140 + Thread.sleep(100);
  141 +
  142 + } catch (InterruptedException ie) {
  143 + LogUtils.e(ie.toString());
  144 + }
  145 + }
  146 +
  147 + WifiConfiguration tempConfig = isExsits(ssid);
  148 +
  149 + if (tempConfig != null) {
  150 + boolean b = wifiManager.enableNetwork(tempConfig.networkId,
  151 + true);
  152 + } else {
  153 + WifiConfiguration wifiConfig = createWifiInfo(ssid, password,
  154 + type);
  155 + if (wifiConfig == null) {
  156 + LogUtils.d("wifiConfig is null!");
  157 + return;
  158 + }
  159 +
  160 + int netID = wifiManager.addNetwork(wifiConfig);
  161 + boolean enabled = wifiManager.enableNetwork(netID, true);
  162 + LogUtils.d("enableNetwork status enable=" + enabled);
  163 + boolean connected = wifiManager.reconnect();
  164 + LogUtils.d("enableNetwork connected=" + connected);
  165 + }
  166 +
  167 + }
  168 + }
  169 +
  170 + private static boolean isHexWepKey(String wepKey) {
  171 + final int len = wepKey.length();
  172 +
  173 + // WEP-40, WEP-104, and some vendors using 256-bit WEP (WEP-232?)
  174 + if (len != 10 && len != 26 && len != 58) {
  175 + return false;
  176 + }
  177 +
  178 + return isHex(wepKey);
  179 + }
  180 +
  181 + private static boolean isHex(String key) {
  182 + for (int i = key.length() - 1; i >= 0; i--) {
  183 + final char c = key.charAt(i);
  184 + if (!(c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a'
  185 + && c <= 'f')) {
  186 + return false;
  187 + }
  188 + }
  189 +
  190 + return true;
  191 + }
  192 +
  193 + // 获取ssid的加密方式
  194 + public static WifiCipherType getCipherType(Context context, String ssid) {
  195 + WifiManager wifiManager = (WifiManager) context
  196 + .getSystemService(Context.WIFI_SERVICE);
  197 +
  198 + List<ScanResult> list = wifiManager.getScanResults();
  199 +
  200 + for (ScanResult scResult : list) {
  201 +
  202 + if (!StringUtils.isEmpty(scResult.SSID) && scResult.SSID.equals(ssid)) {
  203 + String capabilities = scResult.capabilities;
  204 +
  205 + if (!StringUtils.isEmpty(capabilities)) {
  206 +
  207 + if (capabilities.contains("WPA")
  208 + || capabilities.contains("wpa")) {
  209 + LogUtils.i("wpa");
  210 + return WifiCipherType.WIFICIPHER_WPA;
  211 + } else if (capabilities.contains("WEP")
  212 + || capabilities.contains("wep")) {
  213 + LogUtils.i("wep");
  214 + return WifiCipherType.WIFICIPHER_WEP;
  215 + } else {
  216 + LogUtils.i("no");
  217 + return WifiCipherType.WIFICIPHER_NOPASS;
  218 + }
  219 + }
  220 + }
  221 + }
  222 + return WifiCipherType.WIFICIPHER_INVALID;
  223 + }
  224 +}
0 \ No newline at end of file 225 \ No newline at end of file
mvpsdk/src/main/java/com/share/mvpsdk/view/MyEyeView.java 0 → 100644
@@ -0,0 +1,71 @@ @@ -0,0 +1,71 @@
  1 +package com.share.mvpsdk.view;
  2 +
  3 +import android.content.Context;
  4 +import android.graphics.Canvas;
  5 +import android.graphics.Color;
  6 +import android.graphics.Paint;
  7 +import android.graphics.Shader;
  8 +import android.support.annotation.Nullable;
  9 +import android.util.AttributeSet;
  10 +import android.view.View;
  11 +
  12 +/**
  13 + * Created by ToaHanDong on 2018/2/7.
  14 + */
  15 +
  16 +public class MyEyeView extends View {
  17 +
  18 + Paint myPaint;
  19 +
  20 + int mypaintWidth=2;
  21 +
  22 + int centerLeft=0,centerTop=0,centerRight=0,centerBottom=0;
  23 + public MyEyeView(Context context) {
  24 + super(context);
  25 + init(context);
  26 + }
  27 +
  28 + public MyEyeView(Context context, @Nullable AttributeSet attrs) {
  29 + super(context, attrs);
  30 + init(context);
  31 + }
  32 +
  33 + public MyEyeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
  34 + super(context, attrs, defStyleAttr);
  35 + init(context);
  36 + }
  37 +
  38 + @Override
  39 + protected void onDraw(Canvas canvas) {
  40 + super.onDraw(canvas);
  41 + while (centerLeft>0){
  42 + centerLeft-=10;
  43 + centerTop-=10;
  44 + centerRight+=10;
  45 + centerBottom+=10;
  46 + canvas.drawRect(centerLeft,centerTop,centerRight,centerBottom,myPaint);
  47 + }
  48 + }
  49 +
  50 + private void init(Context context) {
  51 + myPaint=new Paint();
  52 + myPaint.setColor(Color.WHITE);
  53 + myPaint.setAntiAlias(true);
  54 + myPaint.setStyle(Paint.Style.STROKE);
  55 + myPaint.setStrokeWidth(mypaintWidth);
  56 +// myPaint.setShader(new Shader());
  57 + }
  58 +
  59 + public void setMyPaintWidth(int paintWidth){
  60 + mypaintWidth=paintWidth;
  61 + }
  62 +
  63 + public void setIndexPoint(int centerLeft,int centerTop,int centerRight,int centerBottom){
  64 + this.centerLeft=centerLeft;
  65 + this.centerTop=centerTop;
  66 + this.centerRight=centerRight;
  67 + this.centerBottom=centerBottom;
  68 + invalidate();
  69 + }
  70 +
  71 +}
mvpsdk/src/main/java/com/share/mvpsdk/view/MyVieoView.java 0 → 100644
@@ -0,0 +1,115 @@ @@ -0,0 +1,115 @@
  1 +package com.share.mvpsdk.view;
  2 +
  3 +import android.content.Context;
  4 +import android.media.MediaMetadataRetriever;
  5 +import android.media.MediaPlayer;
  6 +import android.net.Uri;
  7 +import android.text.TextUtils;
  8 +import android.util.AttributeSet;
  9 +import android.util.Log;
  10 +import android.widget.MediaController;
  11 +import android.widget.VideoView;
  12 +
  13 +/**
  14 + * Created by ToaHanDong on 2018/4/10.
  15 + */
  16 +
  17 +public class MyVieoView extends VideoView {
  18 +
  19 + private Context mContext = null;
  20 +
  21 + //最终的视频资源宽度
  22 + private int mVideoWidth = 480;
  23 +
  24 + //最终视频资源高度
  25 + private int mVideoHeight = 480;
  26 +
  27 + //视频资源原始宽度
  28 + private int videoRealW = 1;
  29 +
  30 + //视频资源原始高度
  31 + private int videoRealH = 1;
  32 +
  33 + private String url = "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4";
  34 +
  35 + public MyVieoView(Context context) {
  36 + super(context);
  37 + mContext = context;
  38 + }
  39 +
  40 + public MyVieoView(Context context, AttributeSet attrs) {
  41 + super(context, attrs);
  42 + mContext = context;
  43 + }
  44 +
  45 + public MyVieoView(Context context, AttributeSet attrs, int defStyleAttr) {
  46 + super(context, attrs, defStyleAttr);
  47 + mContext = context;
  48 + }
  49 +
  50 + public void setVideoPath(String urlPath) {
  51 +
  52 +// if (TextUtils.isEmpty(urlPath)) urlPath = url;
  53 + setVideoURI(Uri.parse(urlPath));
  54 + //创建视频播放时的控制器,这个控制器可以自定义。此处是默认的实现
  55 + setMediaController(null);
  56 + //请求焦点
  57 + requestFocus();
  58 + //设置播放监听
  59 + setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
  60 + @Override
  61 + public void onPrepared(MediaPlayer mediaPlayer) {
  62 + // optional need Vitamio 4.0
  63 + //设置重放速度
  64 +// mediaPlayer.setPlaybackSpeed(1.0f);
  65 + }
  66 + });
  67 + //加载结束后开始播放,这行代码可以控制视频的播放。
  68 + start();
  69 +
  70 + }
  71 +
  72 +
  73 + @Override
  74 + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  75 + int width = getDefaultSize(0, widthMeasureSpec);
  76 + int height = getDefaultSize(0, heightMeasureSpec);
  77 + if (height > width) {
  78 + //竖屏
  79 + if (videoRealH > videoRealW) {
  80 + //如果视频资源是竖屏
  81 + //占满屏幕
  82 + mVideoHeight = height;
  83 + mVideoWidth = width;
  84 + } else {
  85 + //如果视频资源是横屏
  86 + //宽度占满,高度保存比例
  87 + mVideoWidth = width;
  88 + float r = videoRealH / (float) videoRealW;
  89 +// mVideoHeight = (int) (mVideoWidth * r);
  90 + mVideoHeight=height;
  91 + }
  92 + } else {
  93 + //横屏
  94 + if (videoRealH > videoRealW) {
  95 + //如果视频资源是竖屏
  96 + //宽度占满,高度保存比例
  97 + mVideoHeight = height;
  98 + float r = videoRealW / (float) videoRealH;
  99 + mVideoWidth = (int) (mVideoHeight * r);
  100 + } else {
  101 + //如果视频资源是横屏
  102 + //占满屏幕
  103 + mVideoHeight = height;
  104 + mVideoWidth = width;
  105 + }
  106 + }
  107 + setMeasuredDimension(mVideoWidth, mVideoHeight);
  108 +// if (videoRealH == videoRealW && videoRealH == 1) {
  109 +// //没能获取到视频真实的宽高,自适应就可以了,什么也不用做
  110 +// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  111 +// } else {
  112 +// setMeasuredDimension(mVideoWidth, mVideoHeight);
  113 +// }
  114 + }
  115 +}
mvpsdk/src/main/java/com/share/mvpsdk/view/MyViewView.java 0 → 100644
@@ -0,0 +1,368 @@ @@ -0,0 +1,368 @@
  1 +package com.share.mvpsdk.view;
  2 +
  3 +import android.content.Context;
  4 +import android.graphics.Bitmap;
  5 +import android.net.http.SslError;
  6 +import android.os.Build;
  7 +import android.util.AttributeSet;
  8 +import android.util.Log;
  9 +import android.view.View;
  10 +import android.webkit.JavascriptInterface;
  11 +import android.webkit.JsPromptResult;
  12 +import android.webkit.JsResult;
  13 +import android.webkit.SslErrorHandler;
  14 +import android.webkit.WebChromeClient;
  15 +import android.webkit.WebResourceError;
  16 +import android.webkit.WebResourceRequest;
  17 +import android.webkit.WebResourceResponse;
  18 +import android.webkit.WebSettings;
  19 +import android.webkit.WebView;
  20 +import android.webkit.WebViewClient;
  21 +import android.widget.FrameLayout;
  22 +
  23 +import com.share.mvpsdk.utils.FileUtils;
  24 +import com.share.mvpsdk.utils.NetworkConnectionUtils;
  25 +
  26 +/**
  27 + * Created by ToaHanDong on 2018/1/25.
  28 + */
  29 +
  30 +public class MyViewView extends WebView {
  31 +
  32 + public MyViewView(Context context) {
  33 + super(context);
  34 + init(context);
  35 + }
  36 +
  37 + public MyViewView(Context context, AttributeSet attrs) {
  38 + super(context, attrs);
  39 + init(context);
  40 + }
  41 +
  42 + public MyViewView(Context context, AttributeSet attrs, int defStyleAttr) {
  43 + super(context, attrs, defStyleAttr);
  44 + init(context);
  45 + }
  46 +
  47 + private String TAG="MyWebView";
  48 + //WebView的设置类
  49 + private WebSettings webSettings = null;
  50 +
  51 + private void init(Context context) {
  52 +
  53 + initWebSetting(context);
  54 +
  55 + }
  56 +
  57 + private void initWebSetting(Context context) {
  58 +
  59 + webSettings = getSettings();//初始化websettings
  60 +
  61 + //如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
  62 + webSettings.setJavaScriptEnabled(true);
  63 + //支持插件
  64 + webSettings.setPluginState(WebSettings.PluginState.ON);
  65 + //设置自适应屏幕,两者合用
  66 + webSettings.setUseWideViewPort(true);//将图片调整适合WebView的大小
  67 + webSettings.setLoadWithOverviewMode(true);//缩放至屏幕的大小
  68 + //缩放操作
  69 + webSettings.setSupportZoom(true); //支持缩放,默认为true。是下面那个的前提。
  70 + webSettings.setBuiltInZoomControls(true);//设置内置的缩放控件。若为false,则该WebView不可缩放
  71 + webSettings.setDisplayZoomControls(true);//隐藏原生的缩放控件
  72 + //其他细节操作
  73 + //LOAD_CACHE_ONLY: 不使用网络,只读取本地缓存数据
  74 + //LOAD_DEFAULT: (默认)根据cache-control决定是否从网络上取数据。
  75 + //LOAD_NO_CACHE: 不使用缓存,只从网络获取数据.
  76 + //LOAD_CACHE_ELSE_NETWORK,只要本地有,无论是否过期,或者no-cache,都使用缓存中的数据。
  77 +// webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存
  78 + webSettings.setAllowFileAccess(true);//设置可以访问文件
  79 + webSettings.setJavaScriptCanOpenWindowsAutomatically(true);//支持通过js打开新窗口
  80 + webSettings.setLoadsImagesAutomatically(true);//设置自动加载图片
  81 + webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式为ytf-8
  82 + if (NetworkConnectionUtils.isConnected(context))
  83 + webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
  84 + else webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
  85 + webSettings.setDomStorageEnabled(true); // 开启 DOM storage API 功能
  86 + webSettings.setDatabaseEnabled(true); //开启 database storage API 功能
  87 + webSettings.setAppCacheEnabled(true);//开启 Application Caches 功能
  88 + if (!FileUtils.webViewCacheIsExit()) {
  89 + webSettings.setAppCachePath(FileUtils.getCache()); //设置 Application Caches 缓存目录,只能设置一次
  90 + webSettings.setAppCacheMaxSize(8 * 1024 * 1024);
  91 + }
  92 + }
  93 +
  94 + FrameLayout frame;
  95 + public void setView(FrameLayout frame) {
  96 + this.frame=frame;
  97 + }
  98 +
  99 + /**
  100 + * js接口
  101 + */
  102 + public class SupportJavascriptInterface {
  103 + private Context context;
  104 +
  105 + public SupportJavascriptInterface(Context context) {
  106 + this.context = context;
  107 + }
  108 +
  109 + @JavascriptInterface
  110 + public void openImage(final String img) {
  111 + Log.d(TAG,"openImage="+img);
  112 +// goBackOrForward(-1);
  113 +// AppUtils.runOnUIThread(new Runnable() {
  114 +// @Override
  115 +// public void run() {
  116 +// gotoImageBrowse(img);
  117 +// }
  118 +// });
  119 + }
  120 + }
  121 +
  122 + // WebViewClient类(主要作用是:处理各种通知 & 请求事件)
  123 + public void setMyWebViewClient(String url) {
  124 + //步骤1: 选择加载方式
  125 +//方式a. 加载一个网页:
  126 + loadUrl(url);
  127 +//方式b:加载apk包中的html页面
  128 +// loadUrl("file:///android_asset/test.html");
  129 +//方式c:加载手机本地的html页面
  130 +// loadUrl("content://com.android.htmlfileprovider/sdcard/test.html");
  131 + addJavascriptInterface(new SupportJavascriptInterface(getContext()),"imagelistener");
  132 + setWebViewClient(new WebViewClient() {
  133 +
  134 + //设定加载开始的操作
  135 + @Override
  136 + public void onPageStarted(WebView view, String url, Bitmap favicon) {
  137 + super.onPageStarted(view, url, favicon);
  138 + Log.d(TAG,"onPageStarted="+url+"favicon="+favicon);
  139 + }
  140 +
  141 + //html加载完成
  142 + @Override
  143 + public void onPageFinished(WebView view, String url) {
  144 + super.onPageFinished(view, url);
  145 + Log.d(TAG,"onPageFinished="+url);
  146 + addWebImageClickListner(view);
  147 + }
  148 +
  149 + // 注入js函数监听
  150 + protected void addWebImageClickListner(WebView webView) {
  151 + // 这段js函数的功能就是,遍历所有的img节点,并添加onclick函数,
  152 + // 函数的功能是在图片点击的时候调用本地java接口并传递url过去
  153 + webView.loadUrl("javascript:(function(){" +
  154 + "var objs = document.getElementsByTagName(\"img\"); " +
  155 + "for(var i=0;i<objs.length;i++) " +
  156 + "{"
  157 + + " objs[i].onclick=function() " +
  158 + " { "
  159 + + " window.imagelistener.openImage(this.src); " +
  160 + " } " +
  161 + "}" +
  162 + "})()");
  163 + }
  164 +
  165 + /**
  166 + * 加载资源时会调用该方法
  167 + * @param view
  168 + * @param url
  169 + */
  170 + @Override
  171 + public void onLoadResource(WebView view, String url) {
  172 + super.onLoadResource(view, url);
  173 + Log.d(TAG,"onLoadResource="+url);
  174 + }
  175 +
  176 + @Override
  177 + public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
  178 + super.onReceivedError(view, errorCode, description, failingUrl);
  179 + switch (errorCode) {
  180 + case WebViewClient.ERROR_BAD_URL:
  181 + Log.d(TAG,"ERROR_BAD_URL");
  182 + break;
  183 + case WebViewClient.ERROR_UNKNOWN:
  184 + Log.d(TAG,"ERROR_UNKNOWN");
  185 + break;
  186 + }
  187 + }
  188 +
  189 +// @Override
  190 +// public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
  191 +// super.onReceivedError(view, request, error);
  192 +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  193 +// switch (error.getErrorCode())
  194 +// }
  195 +// }
  196 +
  197 + @Override
  198 + public boolean shouldOverrideUrlLoading(WebView view, String url) {
  199 + view.loadUrl(url);
  200 + return true;
  201 + }
  202 +
  203 + //webView默认是不处理https请求的,页面显示空白,需要进行如下设置:
  204 + @Override
  205 + public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
  206 + super.onReceivedSslError(view, handler, error);
  207 + Log.d(TAG,"onReceivedSslError");
  208 + handler.proceed();//表示等待证书响应
  209 + }
  210 + });
  211 +
  212 + }
  213 +
  214 + //辅助 WebView 处理 Javascript 的对话框,网站图标,网站标题等等。
  215 + public void setMyWebChromeClient(){
  216 + setWebChromeClient(new WebChromeClient(){
  217 +
  218 + @Override
  219 + public void onShowCustomView(View view, CustomViewCallback callback) {
  220 + super.onShowCustomView(view, callback);
  221 + Log.d(TAG,"onShowCustomView=");
  222 + }
  223 +
  224 + @Override
  225 + public void onProgressChanged(WebView view, int newProgress) {
  226 + super.onProgressChanged(view, newProgress);
  227 + Log.d(TAG,"newProgress="+newProgress);
  228 + }
  229 +
  230 + @Override
  231 + public void onReceivedTitle(WebView view, String title) {
  232 + super.onReceivedTitle(view, title);
  233 + Log.d(TAG,"onReceivedTitle="+title);
  234 + }
  235 +
  236 + /**
  237 + * js中的弹出框
  238 + * @param view
  239 + * @param url
  240 + * @param message
  241 + * @param result 可以对弹出框做取消和确认操作
  242 + * @return
  243 + */
  244 + @Override
  245 + public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
  246 + Log.d(TAG,"onJsAlert="+message+"url="+url);
  247 + return super.onJsAlert(view, url, message, result);
  248 + }
  249 +
  250 +// 支持javascript输入框,点击确认返回输入框中的值,点击取消返回 null。
  251 + @Override
  252 + public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
  253 + return super.onJsPrompt(view, url, message, defaultValue, result);
  254 + }
  255 + });
  256 + }
  257 +
  258 +
  259 + //WebView的状态
  260 +
  261 + /**
  262 + * 激活webView为活跃状态,能正常执行网页的响应
  263 + */
  264 + public void setonResume() {
  265 + onResume();
  266 + }
  267 +
  268 + /**
  269 + * 当页面被失去焦点被切换到后台不可见状态,需要执行onPause
  270 + * 通过onPause动作通知内核暂停所有的动作,比如DOM的解析、plugin的执行、JavaScript执行。
  271 + */
  272 + public void setOnPause() {
  273 + onPause();
  274 + }
  275 +
  276 + /**
  277 + * 当应用程序(存在webview)被切换到后台时,这个方法不仅仅针对当前的webview而是全局的全应用程序的webview
  278 + * 它会暂停所有webview的layout,parsing,javascripttimer。降低CPU功耗。
  279 + */
  280 + public void setPauseTimers() {
  281 + pauseTimers();
  282 + }
  283 +
  284 + /**
  285 + * 恢复pauseTimers状态
  286 + */
  287 + public void setResumeTimers() {
  288 + resumeTimers();
  289 + }
  290 +
  291 + public void destroyWebView() {
  292 + removeView(this);
  293 + destroy();
  294 + }
  295 +
  296 + //WebView的简单操作
  297 +
  298 + /**
  299 + * 判断网页是否可以回退
  300 + *
  301 + * @return
  302 + */
  303 + public boolean getCanGoBack() {
  304 + return canGoBack();
  305 + }
  306 +
  307 + /**
  308 + * 回退网页
  309 + */
  310 + public void setGoBack() {
  311 + goBack();
  312 + }
  313 +
  314 + /**
  315 + * 设置是否可以前进
  316 + *
  317 + * @return
  318 + */
  319 + public boolean setCanForward() {
  320 + return canGoForward();
  321 + }
  322 +
  323 + /**
  324 + * 前进网页
  325 + */
  326 + public void setGoForward() {
  327 + goForward();
  328 + }
  329 +
  330 + /**
  331 + * 以当前的index为起始点前进或者后退到历史记录中指定的steps
  332 + * 如果steps为负数则为后退,正数则为前进
  333 + *
  334 + * @param steps
  335 + */
  336 + public void setGoBackOrForward(int steps) {
  337 + goBackOrForward(steps);
  338 + }
  339 +
  340 + //清除缓存数据
  341 +
  342 + /**
  343 + * 清除网页访问留下的缓存
  344 + * 由于内核缓存是全局的因此这个方法不仅仅针对webview而是针对整个应用程序.
  345 + *
  346 + * @param isClear
  347 + */
  348 + public void clearMyCache(boolean isClear) {
  349 + clearCache(isClear);
  350 + }
  351 +
  352 + /**
  353 + * 清除当前webview访问的历史记录
  354 + * 只会webview访问历史记录里的所有记录除了当前访问记录
  355 + */
  356 + public void clearMyHistory() {
  357 +
  358 + }
  359 +
  360 + /**
  361 + * 这个api仅仅清除自动完成填充的表单数据,并不会清除WebView存储到本地的数据
  362 + */
  363 + public void clearMyFormData() {
  364 + clearFormData();
  365 + }
  366 +
  367 +
  368 +}
mvpsdk/src/main/java/com/share/mvpsdk/view/chartview/ChartView.java 0 → 100644
@@ -0,0 +1,307 @@ @@ -0,0 +1,307 @@
  1 +package com.share.mvpsdk.view.chartview;
  2 +
  3 +import android.content.Context;
  4 +import android.graphics.Canvas;
  5 +import android.graphics.Paint;
  6 +import android.graphics.Path;
  7 +import android.graphics.PathDashPathEffect;
  8 +import android.support.annotation.NonNull;
  9 +import android.support.annotation.Nullable;
  10 +import android.util.AttributeSet;
  11 +import android.util.Log;
  12 +import android.view.View;
  13 +
  14 +import com.share.mvpsdk.R;
  15 +import com.share.mvpsdk.utils.ValueUtils;
  16 +import com.share.mvpsdk.view.chartview.data.Chart;
  17 +import com.share.mvpsdk.view.chartview.data.ChartPath;
  18 +import com.share.mvpsdk.view.chartview.data.DrawData;
  19 +import com.share.mvpsdk.view.chartview.data.InputData;
  20 +
  21 +import java.text.DecimalFormat;
  22 +import java.util.ArrayList;
  23 +import java.util.List;
  24 +
  25 +/**
  26 + * Created by ToaHanDong on 2018/3/28.
  27 + */
  28 +
  29 +public class ChartView extends View {
  30 +
  31 + Paint axisPaint;//轴的画笔
  32 +
  33 + Paint valuesPaint;//值的画笔
  34 +
  35 + Paint textPaint;//轴的数值的画笔
  36 +
  37 + Paint effectPaint;//有间隔的画笔
  38 +
  39 + Chart chart;//图表属性
  40 +
  41 + List<ChartPath> chartPathList = null;//路径的集合
  42 +
  43 + private int axisColor, valuesColor, textColor;
  44 +
  45 +
  46 + public ChartView(Context context) {
  47 + super(context);
  48 + initCharView();
  49 + }
  50 +
  51 + public ChartView(Context context, @Nullable AttributeSet attrs) {
  52 + super(context, attrs);
  53 + initCharView();
  54 + }
  55 +
  56 + public ChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
  57 + super(context, attrs, defStyleAttr);
  58 + initCharView();
  59 + }
  60 +
  61 + private void initCharView() {
  62 +
  63 + initPaint();
  64 +
  65 +
  66 + }
  67 +
  68 + //设置颜色
  69 + public void setColors(int textColor, int axisColor, int valuesColor) {
  70 + this.textColor = textColor;
  71 + this.axisColor = axisColor;
  72 + this.valuesColor = valuesColor;
  73 + }
  74 +
  75 + private int getTitleWidth() {
  76 + List<InputData> valueList = chart.inputDataList;
  77 + if (valueList == null || valueList.isEmpty()) {
  78 + return 0;
  79 + }
  80 +
  81 + String maxValue = String.valueOf(ValueUtils.max(chartPathList));
  82 + int titleWidth = (int) textPaint.measureText(maxValue);
  83 + int padding = chart.padding;
  84 +
  85 + return padding + titleWidth + padding;
  86 + }
  87 +
  88 + //添加路径
  89 + public void setChartPaths(List<InputData> inputData) {
  90 + if (null == chartPathList) chartPathList = new ArrayList<>();
  91 + ChartPath chartPath = new ChartPath(inputData);
  92 + chartPathList.add(chartPath);
  93 + chart.setInputDataList(inputData);
  94 + chart.titleWidth = getTitleWidth();
  95 + invalidate();
  96 + }
  97 +
  98 + public void setDrawData(){
  99 +// chart.setDrawDataList(ValueUtils.getDrawData(chart));
  100 + invalidate();
  101 + }
  102 +
  103 + /**
  104 + * 初始化 画笔
  105 + */
  106 + Path path = new Path();
  107 +
  108 + private void initPaint() {
  109 +
  110 + chart = new Chart();
  111 +// chart.height = getMeasuredHeight();
  112 +// chart.width = getWidth();
  113 + chart.heightOffset = (int) (getResources().getDimension(R.dimen.dp_4) + getResources().getDimension(R.dimen.dp_4));
  114 + chart.padding = (int) (getResources().getDimension(R.dimen.dp_10));
  115 + chart.textSize = (int) getResources().getDimension(R.dimen.dp_14);
  116 + chart.radius = (int) getResources().getDimension(R.dimen.dp_4);
  117 + chart.inerRadius = (int) getResources().getDimension(R.dimen.dp_4);
  118 +
  119 + axisPaint = new Paint();
  120 + axisPaint.setColor(getResources().getColor(R.color.theme_day_blue));
  121 + axisPaint.setStyle(Paint.Style.FILL);
  122 + axisPaint.setAntiAlias(true);
  123 + axisPaint.setTextSize(chart.textSize);
  124 +
  125 + valuesPaint = new Paint();
  126 + valuesPaint.setAntiAlias(true);
  127 + valuesPaint.setTextSize(chart.textSize);
  128 + valuesPaint.setStrokeWidth(2);
  129 + valuesPaint.setStyle(Paint.Style.FILL);
  130 + valuesPaint.setColor(getResources().getColor(R.color.theme_day_blue));
  131 +
  132 + textPaint = new Paint();
  133 + textPaint.setColor(getResources().getColor(R.color.text_color_dark));
  134 + textPaint.setTextSize(chart.textSize);
  135 + textPaint.setAntiAlias(true);
  136 + textPaint.setStyle(Paint.Style.FILL);
  137 +
  138 + effectPaint = new Paint();
  139 + effectPaint.setStyle(Paint.Style.STROKE);
  140 + effectPaint.setAntiAlias(true);
  141 + effectPaint.setStrokeWidth(2);
  142 + effectPaint.setColor(getResources().getColor(R.color.theme_day_blue));
  143 +// path.lineTo();
  144 + effectPaint.setPathEffect(new PathDashPathEffect(path, 15, 0, PathDashPathEffect.Style.ROTATE));
  145 +
  146 + }
  147 +
  148 + @Override
  149 + protected void onDraw(Canvas canvas) {
  150 + super.onDraw(canvas);
  151 +
  152 + drawChartVertical(canvas);
  153 + drawFrameLines(canvas);
  154 + drawChartHorizontal(canvas);
  155 +
  156 +
  157 + }
  158 +
  159 +
  160 + private void drawChartVertical(@NonNull Canvas canvas) {
  161 + List<InputData> inputDataList = chart.getInputDataList();
  162 + if (inputDataList == null || inputDataList.isEmpty()) {
  163 + return;
  164 + }
  165 +
  166 + float maxValue = ValueUtils.max(chartPathList);
  167 + float correctedMaxValue = ValueUtils.getCorrectedMaxValue(maxValue);
  168 + float value = (float) correctedMaxValue / maxValue;
  169 +
  170 + float heightOffset = chart.heightOffset;
  171 + int padding = chart.padding;
  172 + int textSize = chart.textSize;
  173 + int titleWidth = chart.titleWidth;
  174 +
  175 + float width = chart.width - chart.textSize - chart.padding;
  176 + float height = chart.height - textSize - padding;
  177 + float chartPartHeight = ((height - heightOffset) * value) / Chart.CHART_PARTS;
  178 +
  179 + float currHeight = height;
  180 + float currTitle = 0.0f;
  181 +
  182 + for (int i = 0; i <= Chart.CHART_PARTS; i++) {
  183 + float titleY = currHeight;
  184 +
  185 + if (i <= 0) {
  186 + titleY = height;
  187 +
  188 + } else if (textSize + chart.heightOffset > currHeight) {
  189 + titleY = currHeight + textSize - Chart.TEXT_SIZE_OFFSET;
  190 + }
  191 +
  192 + if (i > 0) {
  193 +// canvas.drawLine(titleWidth, currHeight, width, currHeight, frameInternalPaint);
  194 + //横向间隔线
  195 + textPaint.setColor(0xFFE7E5E7);
  196 + canvas.drawLine(titleWidth - 5, titleY - textSize / 2, width, titleY - textSize / 2, textPaint);
  197 + }
  198 + DecimalFormat decimalFormat = new DecimalFormat("0.0");
  199 + String title = String.valueOf(decimalFormat.format(currTitle));
  200 + textPaint.setColor(getResources().getColor(R.color.gray));
  201 + canvas.drawText(title, padding - textSize / 2, titleY, textPaint);
  202 +
  203 + currHeight -= chartPartHeight;
  204 + currTitle += correctedMaxValue / Chart.CHART_PARTS;
  205 + }
  206 + }
  207 +
  208 + private void drawChartHorizontal(@NonNull Canvas canvas) {
  209 + if (null!=chartPathList){
  210 + ValueUtils.calMax(chartPathList);
  211 + for (int j = 0; j < chartPathList.size(); j++) {
  212 + chagerColor(j);
  213 + List<InputData> inputDataList = chart.getInputDataList();
  214 +// List<DrawData> drawDataList = chart.getDrawDataList();
  215 + List<DrawData> drawDataList = ValueUtils.getDrawDatas(chartPathList.get(j).inputDataList, chart);
  216 +// Log.e("111111", "chartPathList.get(j).inputDataList----===="+chartPathList.get(j).inputDataList);
  217 +// Log.e("111111", "drawDataList----===="+drawDataList);
  218 + if (inputDataList == null || inputDataList.isEmpty() || drawDataList == null || drawDataList.isEmpty()) {
  219 + return;
  220 + }
  221 + for (int i = 0; i < inputDataList.size(); i++) {
  222 +
  223 + InputData inputData = inputDataList.get(i);
  224 +// String date = DateUtils.format(inputData.valueX);
  225 + String date = inputData.valueX;
  226 + int dateWidth = (int) axisPaint.measureText(date);
  227 + float x;
  228 + if (drawDataList.size() > i) {
  229 + DrawData drawData = drawDataList.get(i);
  230 + x = drawData.startX;
  231 + if (i > 0) {
  232 +// x -= (dateWidth / 2);
  233 + x = drawDataList.get(i).startX - (dateWidth / 2) - chart.padding - chart.textSize;
  234 + }
  235 + } else {
  236 + x = drawDataList.get(drawDataList.size() - 1).stopX - dateWidth - chart.padding - chart.textSize;
  237 + }
  238 + if (i > 0) {
  239 + float startX = i == drawDataList.size() ? x + chart.textSize : x + dateWidth / 2;
  240 + float startY = drawDataList.get(i - 1).stopY;
  241 + float stopX = i == drawDataList.size() ? x + chart.textSize : x + dateWidth / 2;
  242 + float stopY = chart.height - chart.textSize - chart.padding;
  243 +
  244 +// canvas.drawLine(startX,
  245 +// startY,
  246 +// stopX,
  247 +// stopY, effectPaint);
  248 +
  249 + //画文字
  250 + canvas.drawText(date, x, chart.height - chart.padding / 2, textPaint);
  251 +
  252 + //画圆点
  253 + canvas.drawCircle(startX, startY, 10, valuesPaint);
  254 + Log.e("11111", "startX----===="+startX+"startY="+startY);
  255 + //点之间的连线
  256 + if (i < drawDataList.size() - 1) {
  257 + canvas.drawLine(startX, startY, drawDataList.get(i + 1).startX - chart.padding - chart.textSize, drawDataList.get(i + 1).startY, valuesPaint);
  258 + } else {
  259 + canvas.drawLine(drawDataList.get(drawDataList.size() - 1).startX - chart.padding - chart.textSize,
  260 + drawDataList.get(drawDataList.size() - 1).startY, startX, startY, valuesPaint);
  261 + }
  262 + }
  263 + }
  264 + }
  265 + }
  266 + }
  267 +
  268 + private void chagerColor(int j) {
  269 + switch (j) {
  270 + case 0:
  271 + valuesPaint.setColor(getResources().getColor(R.color.theme_day_blue));
  272 + break;
  273 + case 1:
  274 + valuesPaint.setColor(getResources().getColor(R.color.md_light_green_500));
  275 + break;
  276 + case 2:
  277 + valuesPaint.setColor(getResources().getColor(R.color.light_yellow));
  278 + break;
  279 + }
  280 + }
  281 +
  282 + //画横纵坐标轴
  283 + private void drawFrameLines(@NonNull Canvas canvas) {
  284 + int textSize = chart.textSize;
  285 + int padding = chart.padding;
  286 +
  287 + int height = chart.height - textSize - padding;
  288 + int width = chart.width - textSize - padding;
  289 + int titleWidth = chart.titleWidth - 5;
  290 + int heightOffset = chart.heightOffset;
  291 +
  292 + canvas.drawLine(titleWidth, heightOffset, titleWidth, height, axisPaint);
  293 + canvas.drawLine(titleWidth, height, width, height, axisPaint);
  294 + }
  295 +
  296 + @Override
  297 + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  298 + super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  299 +
  300 + int width = MeasureSpec.getSize(widthMeasureSpec);
  301 + int height = MeasureSpec.getSize(heightMeasureSpec);
  302 + chart.width = width;
  303 + chart.height = height;
  304 + setMeasuredDimension(width, height);
  305 + chart.setDrawDataList(ValueUtils.getDrawData(chart));
  306 + }
  307 +}
mvpsdk/src/main/java/com/share/mvpsdk/view/chartview/data/Chart.java 0 → 100644
@@ -0,0 +1,62 @@ @@ -0,0 +1,62 @@
  1 +package com.share.mvpsdk.view.chartview.data;
  2 +
  3 +import java.util.List;
  4 +
  5 +/**
  6 + * Created by ToaHanDong on 2018/3/28.
  7 + * 定义chart表单需要的一些数据
  8 + */
  9 +
  10 +public class Chart {
  11 +
  12 + public static final float CHART_PARTS = 5.0f;
  13 + public static final int MAX_ITEMS_COUNT = 7;
  14 + public static final int CHART_PART_VALUE = 10;
  15 + public static final int TEXT_SIZE_OFFSET = 10;
  16 +
  17 + public int width;//表单的宽
  18 + public int height;//表单的高
  19 +
  20 + public int padding;//内边距
  21 + public int titleWidth;//
  22 + public int textSize;//字体大小
  23 + public int heightOffset;
  24 +
  25 + public int radius;
  26 + public int inerRadius;
  27 +
  28 + public List<InputData> inputDataList;
  29 +
  30 + public List<DrawData> drawDataList;
  31 +
  32 + public void setInputDataList(List<InputData> inputDataList){
  33 + this.inputDataList=inputDataList;
  34 + }
  35 +
  36 + public List<InputData> getInputDataList(){
  37 + return inputDataList;
  38 + }
  39 +
  40 + public void setDrawDataList(List<DrawData> drawDataList){
  41 + this.drawDataList=drawDataList;
  42 + }
  43 +
  44 + public List<DrawData> getDrawDataList(){
  45 + return drawDataList;
  46 + }
  47 +
  48 +
  49 + @Override
  50 + public String toString() {
  51 + return "Chart{" +
  52 + "width=" + width +
  53 + ", height=" + height +
  54 + ", padding=" + padding +
  55 + ", titleWidth=" + titleWidth +
  56 + ", textSize=" + textSize +
  57 + ", heightOffset=" + heightOffset +
  58 + ", radius=" + radius +
  59 + ", inerRadius=" + inerRadius +
  60 + '}';
  61 + }
  62 +}
mvpsdk/src/main/java/com/share/mvpsdk/view/chartview/data/ChartPath.java 0 → 100644
@@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
  1 +package com.share.mvpsdk.view.chartview.data;
  2 +
  3 +import java.util.List;
  4 +
  5 +/**
  6 + * Created by ToaHanDong on 2018/3/28.
  7 + */
  8 +
  9 +//路径
  10 +public class ChartPath {
  11 +
  12 + public List<InputData> inputDataList;
  13 +
  14 + public ChartPath(List<InputData> inputData) {
  15 + this.inputDataList=inputData;
  16 + }
  17 +
  18 + @Override
  19 + public String toString() {
  20 + return "ChartPath{" +
  21 + "inputDataList=" + inputDataList +
  22 + '}';
  23 + }
  24 +}
mvpsdk/src/main/java/com/share/mvpsdk/view/chartview/data/DrawData.java 0 → 100644
@@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
  1 +package com.share.mvpsdk.view.chartview.data;
  2 +
  3 +/**
  4 + * Created by ToaHanDong on 2018/3/28.
  5 + */
  6 +
  7 +public class DrawData {
  8 +
  9 + public float startX;
  10 + public float startY;
  11 +
  12 + public float stopX;
  13 + public float stopY;
  14 +
  15 + @Override
  16 + public String toString() {
  17 + return "DrawData{" +
  18 + "startX=" + startX +
  19 + ", startY=" + startY +
  20 + ", stopX=" + stopX +
  21 + ", stopY=" + stopY +
  22 + '}';
  23 + }
  24 +}
mvpsdk/src/main/java/com/share/mvpsdk/view/chartview/data/InputData.java 0 → 100644
@@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
  1 +package com.share.mvpsdk.view.chartview.data;
  2 +
  3 +/**
  4 + * Created by ToaHanDong on 2018/3/28.
  5 + * 输入的x、y参数
  6 + */
  7 +
  8 +public class InputData {
  9 +
  10 + public String valueX;
  11 +
  12 + public float valueY;
  13 +
  14 + public InputData(String valueX,float valueY){
  15 + this.valueX=valueX;
  16 + this.valueY=valueY;
  17 + }
  18 +
  19 + @Override
  20 + public String toString() {
  21 + return "InputData{" +
  22 + "valueX=" + valueX +
  23 + ", valueY=" + valueY +
  24 + '}';
  25 + }
  26 +}
mvpsdk/src/main/java/com/share/mvpsdk/widgets/CompatNestedScrollView.java 0 → 100644
@@ -0,0 +1,86 @@ @@ -0,0 +1,86 @@
  1 +package com.share.mvpsdk.widgets;
  2 +
  3 +import android.content.Context;
  4 +import android.support.v4.widget.NestedScrollView;
  5 +import android.util.AttributeSet;
  6 +import android.view.View;
  7 +import android.view.ViewGroup;
  8 +
  9 +import com.share.mvpsdk.utils.AppUtils;
  10 +import com.share.mvpsdk.utils.DisplayUtils;
  11 +import com.share.mvpsdk.utils.StatusBarUtils;
  12 +
  13 +
  14 +/**
  15 + * Created by Horrarndoo on 2017/10/19.
  16 + * <p>
  17 + * 自定义NestedScrollView,主要实现根据滑动距离控制绑定View的alpha值
  18 + */
  19 +
  20 +public class CompatNestedScrollView extends NestedScrollView {
  21 + private ViewGroup childViewGroup;
  22 + private View headView;
  23 + private View bindView;
  24 +
  25 + public CompatNestedScrollView(Context context) {
  26 + super(context);
  27 + }
  28 +
  29 + public CompatNestedScrollView(Context context, AttributeSet attrs) {
  30 + super(context, attrs);
  31 + }
  32 +
  33 + public CompatNestedScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
  34 + super(context, attrs, defStyleAttr);
  35 + }
  36 +
  37 + @Override
  38 + protected void onFinishInflate() {
  39 + super.onFinishInflate();
  40 + if (getChildCount() > 1) {
  41 + throw new IllegalArgumentException("only can 1 child in this view");
  42 + } else {
  43 + if (getChildAt(0) instanceof ViewGroup) {
  44 + childViewGroup = (ViewGroup) getChildAt(0);
  45 + if (childViewGroup != null) {
  46 + headView = childViewGroup.getChildAt(0);
  47 + }
  48 + } else {
  49 + throw new IllegalArgumentException("child must be instanceof ViewGroup");
  50 + }
  51 + }
  52 + }
  53 +
  54 + @Override
  55 + protected void onScrollChanged(int l, int t, int oldl, int oldt) {
  56 + super.onScrollChanged(l, t, oldl, oldt);
  57 + float alpha = 1.f;
  58 + if (headView != null && bindView != null) {
  59 + //如果上滑超过toolbar高度,开启伴随动画
  60 + //Logger.e("t = " + t);
  61 + //Logger.e("headView.getHeight = " + headView.getHeight());
  62 + float slideValue = t - (DisplayUtils.dp2px(56) + StatusBarUtils.getStatusBarHeight
  63 + (AppUtils.getContext()));
  64 +
  65 + if (slideValue < 0)
  66 + slideValue = 0;
  67 +
  68 + float fraction = slideValue / (headView.getHeight() / 2.f);
  69 + if (fraction > 1) {
  70 + fraction = 1;
  71 + }
  72 +
  73 + alpha *= fraction;
  74 + bindView.setAlpha(alpha);
  75 + }
  76 + }
  77 +
  78 + /**
  79 + * 绑定要变化Alpha的view
  80 + *
  81 + * @param view 要变化Alpha的view
  82 + */
  83 + public void bindAlphaView(View view) {
  84 + bindView = view;
  85 + }
  86 +}
mvpsdk/src/main/java/com/share/mvpsdk/widgets/HistoryChartView.java 0 → 100644
@@ -0,0 +1,719 @@ @@ -0,0 +1,719 @@
  1 +package com.share.mvpsdk.widgets;
  2 +
  3 +
  4 +import android.animation.ValueAnimator;
  5 +import android.content.Context;
  6 +import android.content.res.TypedArray;
  7 +import android.graphics.Bitmap;
  8 +import android.graphics.Canvas;
  9 +import android.graphics.Color;
  10 +import android.graphics.DashPathEffect;
  11 +import android.graphics.Paint;
  12 +import android.graphics.Path;
  13 +import android.graphics.PathEffect;
  14 +import android.graphics.PathMeasure;
  15 +import android.util.AttributeSet;
  16 +import android.view.View;
  17 +import android.view.animation.DecelerateInterpolator;
  18 +
  19 +import com.share.mvpsdk.R;
  20 +import com.share.mvpsdk.utils.DisplayUtils;
  21 +
  22 +
  23 +/**
  24 + * 历史记录查询图表 基于pathMeasure+DashPathEffect+属性动画实现
  25 + * 绘制时采取双缓冲绘制
  26 + *
  27 + * @author zyw
  28 + * @creation 2017-03-06
  29 + */
  30 +public class HistoryChartView extends View {
  31 +
  32 + private String TAG = "HistoryChartView";
  33 +
  34 + TypedArray ta;
  35 +
  36 + private float MarginTop = 100;
  37 +
  38 + private float MarginBottom = 100;
  39 +
  40 + private float MarginLeft = 100;
  41 +
  42 + private float MarginRight = 100;
  43 +
  44 + private float mYLabelSize = 50;
  45 +
  46 + private float mXlabelSize = 35;
  47 +
  48 + private float mXUnitTextSize;
  49 +
  50 + private float mYUnitTextSize;
  51 +
  52 + // 圆半径
  53 + private int circleRadius = 8;
  54 +
  55 + private int lineStrokeWidth = 3;
  56 +
  57 + private int dataStrokeWidth = 3;
  58 +
  59 + private static final long ANIM_DURATION = 1500;
  60 + private PathMeasure mRoomTempPathMeasure;
  61 + private PathMeasure mTargetTempPathMeasure;
  62 + private Path mRoomTempPath;
  63 + private Path mTargetTempPath;
  64 + private Paint mBmpPaint;
  65 + /**
  66 + * 柱形绘制进度
  67 + */
  68 + private float mRectFration;
  69 +
  70 + // X,Y轴的单位长度
  71 + private float Xscale = 20;
  72 + private float Yscale = 20;
  73 +
  74 + // 绘制X轴总长度
  75 + private float xLength;
  76 + // 绘制Y轴总长度
  77 + private float yLength;
  78 +
  79 + // X轴第1个节点的偏移位置
  80 + private float xFirstPointOffset;
  81 +
  82 + // y轴显示的节点间隔距离
  83 + private int yScaleForData = 1;
  84 +
  85 + // x轴显示的节点间隔距离
  86 + private int xScaleForData = 1;
  87 +
  88 + // 画线颜色
  89 + private int lineColor;
  90 +
  91 + private int roomTempLineColor;
  92 + private int targetTempLineColor;
  93 + private int powerTimeLineColor;
  94 + private int mUnitColor;
  95 +
  96 + private String mXUnitText;
  97 + private String mY1UnitText;
  98 + private String mY2UnitText;
  99 +
  100 + private int mMode = 1;// 从Activity传过来的模式值 1:天 2:周 3:月 4:年
  101 +
  102 + // 原点坐标
  103 + private float Xpoint;
  104 + private float Ypoint;
  105 +
  106 + // X,Y轴上面的显示文字
  107 + private String[] Xlabel = {"1", "2", "3", "4", "5", "6", "7"};
  108 + private String[] Ylabel = {"0", "9", "18", "27", "36"};
  109 + private String[] Ylabel2 = {"0", "25", "50", "75", "100"};
  110 +
  111 + private final static int X_SCALE_FOR_DATA_DAY = 2;
  112 + private final static int X_SCALE_FOR_DATA_WEEK = 1;
  113 + private final static int X_SCALE_FOR_DATA_YEAR = 1;
  114 + private final static int X_SCALE_FOR_DATA_MOUNTH = 5;
  115 +
  116 + private final static int DAY_MODE = 0;
  117 + private final static int WEEK_MODE = 1;
  118 + private final static int MONTH_MODE = 2;
  119 + private final static int YEAR_MODE = 3;
  120 +
  121 + // 曲线数据
  122 + private float[] roomTempDataArray = {15, 15, 15, 15, 15, 15, 15};
  123 + private float[] targetTempDataArray = {16, 16, 16, 16, 16, 16, 16};
  124 + private float[] powerOnTimeDataArray = {100, 100, 100, 100, 100, 100, 100};
  125 +
  126 + /**
  127 + * 各条柱形图当前top值数组
  128 + */
  129 + private Float[] rectCurrentTops;
  130 +
  131 + private ValueAnimator mValueAnimator;
  132 +
  133 + private Paint linePaint;
  134 + private Paint targetTempPaint;
  135 + private Paint roomTempPaint;
  136 + private PathEffect mRoomTempEffect;
  137 + private PathEffect mtargetTempEffect;
  138 + //定义一个内存中的图片,该图片将作为缓冲区
  139 + Bitmap mCacheBitmap = null;
  140 + //定义cacheBitmap上的Canvas对象
  141 + Canvas mCacheCanvas = null;
  142 +
  143 + public HistoryChartView(Context context, String[] xlabel, String[] ylabel,
  144 + float[] roomDataArray) {
  145 + super(context);
  146 + this.Xlabel = xlabel;
  147 + this.Ylabel = ylabel;
  148 + this.roomTempDataArray = roomDataArray;
  149 + }
  150 +
  151 + public HistoryChartView(Context context, AttributeSet attrs,
  152 + int defStyleAttr) {
  153 + super(context, attrs, defStyleAttr);
  154 + //Logger.e("HistoryChartView(Context context, AttributeSet attrs, int defStyleAttr)");
  155 +
  156 + ta = context.obtainStyledAttributes(attrs, R.styleable.HistoryChartView);
  157 +
  158 + setDefaultAttrrbutesValue();
  159 +
  160 + initPaint();
  161 +
  162 + initData();
  163 +
  164 + initParams();
  165 +
  166 + initPath();
  167 +
  168 + ta.recycle();
  169 + }
  170 +
  171 + public HistoryChartView(Context context, AttributeSet attrs) {
  172 + this(context, attrs, 0);
  173 + }
  174 +
  175 + public HistoryChartView(Context context) {
  176 + this(context, null);
  177 + }
  178 +
  179 + /**
  180 + * 设置显示数据
  181 + *
  182 + * @param strAlldata 历史数据全状态
  183 + * @param mode 历史数据模式
  184 + */
  185 + public void setData(String strAlldata, int mode) {
  186 + //Logger.e("history chart view strAlldata = " + strAlldata);
  187 + String[] allHistroyArray = strAlldata.split("-");
  188 +
  189 + String[] arrayRoomTempData = allHistroyArray[0].split(",");
  190 + String[] arraySetTempData = allHistroyArray[1].split(",");
  191 + String[] arrayPowerTimeData = allHistroyArray[2].split(",");
  192 +
  193 + mMode = mode;
  194 +
  195 + initXData(arrayRoomTempData);
  196 +
  197 + initRoomTempData(arrayRoomTempData);
  198 +
  199 + initTargetTempData(arraySetTempData);
  200 +
  201 + initPowerOnTimeData(arrayPowerTimeData);
  202 +
  203 + initData();
  204 +
  205 + initParams();
  206 +
  207 + initPath();
  208 +
  209 + startAnimation();
  210 + }
  211 +
  212 + private void initPaint() {
  213 + linePaint = new Paint();
  214 + linePaint.setStyle(Paint.Style.STROKE);
  215 + linePaint.setAntiAlias(true);
  216 + linePaint.setColor(lineColor);
  217 + linePaint.setDither(true);
  218 + linePaint.setStrokeWidth(lineStrokeWidth);
  219 +
  220 + roomTempPaint = new Paint();
  221 + roomTempPaint.setStyle(Paint.Style.STROKE);
  222 + roomTempPaint.setAntiAlias(true);
  223 + roomTempPaint.setColor(roomTempLineColor);
  224 + roomTempPaint.setDither(true);
  225 + roomTempPaint.setStrokeWidth(dataStrokeWidth);
  226 +
  227 + targetTempPaint = new Paint();
  228 + targetTempPaint.setStyle(Paint.Style.STROKE);
  229 + targetTempPaint.setAntiAlias(true);
  230 + targetTempPaint.setColor(targetTempLineColor);
  231 + targetTempPaint.setDither(true);
  232 + targetTempPaint.setStrokeWidth(dataStrokeWidth);
  233 +
  234 + mBmpPaint = new Paint();
  235 + }
  236 +
  237 + /**
  238 + * 初始化数据
  239 + */
  240 + private void initData() {
  241 +
  242 + mRoomTempPath = new Path();
  243 + mTargetTempPath = new Path();
  244 +
  245 + rectCurrentTops = new Float[roomTempDataArray.length];
  246 + }
  247 +
  248 + /**
  249 + * 初始化宽高比例等数据
  250 + */
  251 + public void initParams() {
  252 + // LogUtils.error(TAG, "initParams");
  253 + Xpoint = MarginLeft;
  254 +
  255 + xLength = this.getWidth() - MarginLeft - MarginRight
  256 + - (MarginRight + MarginLeft) / 16;
  257 + yLength = this.getHeight() - MarginTop - MarginBottom;
  258 +
  259 + Ypoint = this.getHeight() - MarginBottom + mYLabelSize / 3;
  260 + Xscale = (xLength - xFirstPointOffset * 2) / (this.Xlabel.length - 1);
  261 + Yscale = yLength / (this.Ylabel.length - 1);
  262 + }
  263 +
  264 + /**
  265 + * 初始化path
  266 + */
  267 + private void initPath() {
  268 + initRoomTempPath(roomTempDataArray);
  269 + initTargetTempPath(targetTempDataArray);
  270 + }
  271 +
  272 + /**
  273 + * 初始化设定温度数据
  274 + *
  275 + * @param arraySetTempData 设定温度数据
  276 + */
  277 + private void initTargetTempData(String[] arraySetTempData) {
  278 + targetTempDataArray = new float[arraySetTempData.length];
  279 + for (int i = 0; i < arraySetTempData.length; i++) {
  280 + if (arraySetTempData[i].length() > 0) {
  281 + targetTempDataArray[i] = Float.parseFloat(arraySetTempData[i]);
  282 + }
  283 + }
  284 + }
  285 +
  286 + /**
  287 + * 初始化房间温度数据
  288 + *
  289 + * @param arrayRoomTempData 房间温度数据
  290 + */
  291 + private void initRoomTempData(String[] arrayRoomTempData) {
  292 + roomTempDataArray = new float[arrayRoomTempData.length];
  293 + for (int i = 0; i < arrayRoomTempData.length; i++) {
  294 + if (arrayRoomTempData[i].length() > 0) {
  295 + roomTempDataArray[i] = Float.parseFloat(arrayRoomTempData[i]);
  296 + // LogUtils.error(TAG, "" + roomTempDataArray[i]);
  297 + }
  298 + }
  299 + }
  300 +
  301 + /**
  302 + * 初始化开机时间数据
  303 + *
  304 + * @param arrayPowerTimeData 开机时间数据
  305 + */
  306 + private void initPowerOnTimeData(String[] arrayPowerTimeData) {
  307 + powerOnTimeDataArray = new float[arrayPowerTimeData.length];
  308 + for (int i = 0; i < arrayPowerTimeData.length; i++) {
  309 + if (arrayPowerTimeData[i].length() > 0) {
  310 + powerOnTimeDataArray[i] = Float
  311 + .parseFloat(arrayPowerTimeData[i]);
  312 + }
  313 + }
  314 + }
  315 +
  316 + /**
  317 + * 初始化X轴数据
  318 + */
  319 + private void initXData(String[] tempData) {
  320 + switch (mMode) {
  321 + case DAY_MODE:
  322 + xScaleForData = X_SCALE_FOR_DATA_DAY;
  323 + setXUnitText(getResources().getString(R.string.history_x_unit_hour));
  324 + break;
  325 + case WEEK_MODE:
  326 + xScaleForData = X_SCALE_FOR_DATA_WEEK;
  327 + setXUnitText(getResources().getString(R.string.history_x_unit_day));
  328 + break;
  329 + case MONTH_MODE:
  330 + xScaleForData = X_SCALE_FOR_DATA_MOUNTH;
  331 + setXUnitText(getResources().getString(R.string.history_x_unit_day));
  332 + break;
  333 + case YEAR_MODE:
  334 + xScaleForData = X_SCALE_FOR_DATA_YEAR;
  335 + setXUnitText(getResources()
  336 + .getString(R.string.history_x_unit_month));
  337 + break;
  338 + default:
  339 + break;
  340 + }
  341 +
  342 + Xlabel = new String[tempData.length];
  343 + for (int i = 0; i < Xlabel.length; i++) {
  344 + Xlabel[i] = Integer.toString(i + 1);
  345 + }
  346 + }
  347 +
  348 + private void setDefaultAttrrbutesValue() {
  349 + float MarginTopPx = ta.getDimension(
  350 + R.styleable.HistoryChartView_margin_top, 50);
  351 + float MarginBottomPx = ta.getDimension(
  352 + R.styleable.HistoryChartView_margin_bottom, 50);
  353 + float MarginLeftPx = ta.getDimension(
  354 + R.styleable.HistoryChartView_margin_left, 50);
  355 + float MarginRightPx = ta.getDimension(
  356 + R.styleable.HistoryChartView_margin_right, 50);
  357 +
  358 + float yLabelSizePx = ta.getDimension(
  359 + R.styleable.HistoryChartView_ylabel_text_size, 30);
  360 + float xlabelSizePx = ta.getDimension(
  361 + R.styleable.HistoryChartView_xlabel_text_size, 20);
  362 + float xUnitSizePx = ta.getDimension(
  363 + R.styleable.HistoryChartView_x_unit_text_size, 30);
  364 + float yUnitSizePx = ta.getDimension(
  365 + R.styleable.HistoryChartView_y_unit_text_size, 30);
  366 +
  367 + float xFirstPointOffsetPx = ta.getDimension(
  368 + R.styleable.HistoryChartView_x_first_point_offset, 30);
  369 + float lineStrokeWidthPx = ta.getDimension(
  370 + R.styleable.HistoryChartView_line_stroke_width, 5);
  371 + float dataStrokeWidthPx = ta.getDimension(
  372 + R.styleable.HistoryChartView_data_stroke_width, 5);
  373 + float circleRadiusPx = ta.getDimension(
  374 + R.styleable.HistoryChartView_circle_radius, 6);
  375 +
  376 + xFirstPointOffset = DisplayUtils.px2sp(xFirstPointOffsetPx);
  377 +
  378 + MarginTop = DisplayUtils.px2dp(MarginTopPx);
  379 + MarginBottom = DisplayUtils.px2dp(MarginBottomPx);
  380 + MarginLeft = DisplayUtils.px2dp(MarginLeftPx);
  381 + MarginRight = DisplayUtils.px2dp(MarginRightPx);
  382 +
  383 + mYLabelSize = DisplayUtils.px2sp(yLabelSizePx);
  384 + mXlabelSize = DisplayUtils.px2sp(xlabelSizePx);
  385 +
  386 + mXUnitTextSize = DisplayUtils.px2sp(xUnitSizePx);
  387 + mYUnitTextSize = DisplayUtils.px2sp(yUnitSizePx);
  388 +
  389 + lineStrokeWidth = DisplayUtils.px2sp(lineStrokeWidthPx);
  390 + dataStrokeWidth = DisplayUtils.px2sp(dataStrokeWidthPx);
  391 + circleRadius = DisplayUtils.px2sp(circleRadiusPx);
  392 +
  393 + lineColor = ta.getColor(R.styleable.HistoryChartView_line_color,
  394 + getResources().getColor(R.color.light_yellow));
  395 + roomTempLineColor = ta.getColor(
  396 + R.styleable.HistoryChartView_first_data_line_color,
  397 + getResources().getColor(R.color.indoor_temp));
  398 + targetTempLineColor = ta.getColor(
  399 + R.styleable.HistoryChartView_second_data_line_color,
  400 + getResources().getColor(R.color.setpoint_temp));
  401 +
  402 + powerTimeLineColor = ta.getColor(
  403 + R.styleable.HistoryChartView_rect_background_color,
  404 + getResources().getColor(R.color.power_time));
  405 +
  406 + mUnitColor = ta.getColor(R.styleable.HistoryChartView_unit_color,
  407 + getResources().getColor(R.color.light_grey));
  408 +
  409 + mXUnitText = ta.getString(R.styleable.HistoryChartView_x_unit_text);
  410 + mY1UnitText = ta.getString(R.styleable.HistoryChartView_y1_unit_text);
  411 + mY2UnitText = ta.getString(R.styleable.HistoryChartView_y2_unit_text);
  412 + }
  413 +
  414 + /**
  415 + * 设置X轴单位符号
  416 + *
  417 + * @param xUnit x轴单位符号
  418 + */
  419 + public void setXUnitText(String xUnit) {
  420 + mXUnitText = xUnit;
  421 + }
  422 +
  423 + /**
  424 + * 绘制单位符号
  425 + *
  426 + * @param canvas canvas
  427 + */
  428 + private void drawUnit(Canvas canvas) {
  429 + Paint p = new Paint();
  430 + p.setAntiAlias(true);
  431 + p.setStrokeWidth(dataStrokeWidth);
  432 + p.setColor(mUnitColor);
  433 +
  434 + drawXUnit(canvas, p);
  435 + drawY1Unit(canvas, p);
  436 + drawY2Unit(canvas, p);
  437 + }
  438 +
  439 + // 画横轴
  440 + private void drawXLine(Canvas canvas, Paint p) {
  441 + p.setColor(getResources().getColor(R.color.light_yellow));
  442 + canvas.drawLine(Xpoint, Ypoint, xLength + MarginLeft, Ypoint, p);
  443 + }
  444 +
  445 + // 画灰色横轴
  446 + private void drawGreyXLine(Canvas canvas, Paint p) {
  447 + p.setColor(getResources().getColor(R.color.grey_line));
  448 + float startX = Xpoint + MarginLeft / 4;
  449 + // 纵向
  450 + for (int i = yScaleForData; (yLength - i * Yscale) >= 0; i += yScaleForData) {
  451 + float startY = Ypoint - i * Yscale;
  452 + canvas.drawLine(startX - MarginLeft / 4, startY, xLength
  453 + + MarginLeft, startY, p);
  454 + }
  455 + }
  456 +
  457 + // 画数据
  458 + private void drawData(Canvas canvas, float[] data, int dataColor) {
  459 + Paint p = new Paint();
  460 + p.setAntiAlias(true);
  461 + p.setStrokeWidth(dataStrokeWidth);
  462 + p.setTextSize(mXlabelSize);
  463 + // 横向
  464 + for (int i = 0; i < Xlabel.length; i++) {
  465 + int xLableInt = Integer.parseInt(Xlabel[i]);
  466 + float startX = Xpoint + i * Xscale + xFirstPointOffset;
  467 + if (xLableInt % xScaleForData == 0) {
  468 + p.setColor(lineColor);
  469 + canvas.drawText(this.Xlabel[i], startX - mXlabelSize / 3,
  470 + Ypoint + mXlabelSize * 3 / 2, p);
  471 + }
  472 + p.setColor(dataColor);
  473 + canvas.drawCircle(startX, getDataY(data[i], Ylabel), circleRadius,
  474 + p);
  475 + }
  476 +
  477 + p.setTextSize(mYLabelSize);
  478 + // 纵向
  479 + for (int i = 0; (yLength - i * Yscale) >= 0; i += yScaleForData) {
  480 + p.setColor(lineColor);
  481 + canvas.drawText(this.Ylabel[i], MarginLeft / 4,
  482 + getDataY(Float.valueOf(Ylabel[i]), Ylabel) + mYLabelSize
  483 + / 3, p);
  484 + canvas.drawText(this.Ylabel2[i], this.getWidth() - MarginLeft,
  485 + getDataY(Float.valueOf(Ylabel2[i]), Ylabel2) + mYLabelSize
  486 + / 3, p);
  487 + }
  488 + }
  489 +
  490 + // 获取room temp绘线Path数据
  491 + private void initRoomTempPath(float[] data) {
  492 + mRoomTempPath.reset();
  493 + // Path path = new Path();
  494 + float pointX;
  495 + float pointY;
  496 + // 横向
  497 + mRoomTempPath.moveTo(Xpoint + xFirstPointOffset,
  498 + getDataY(data[0], Ylabel));
  499 + mRoomTempPath.moveTo(Xpoint + xFirstPointOffset,
  500 + getDataY(data[0], Ylabel));
  501 + for (int i = 0; i < Xlabel.length; i++) {
  502 + float startX = Xpoint + i * Xscale + xFirstPointOffset;
  503 + // 绘制数据连线
  504 + if (i != 0) {
  505 + pointX = Xpoint + (i - 1) * Xscale + xFirstPointOffset;
  506 + pointY = getDataY(data[i - 1], Ylabel);
  507 + mRoomTempPath.lineTo(pointX, pointY);
  508 + }
  509 + if (i == Xlabel.length - 1) {
  510 + pointX = startX;
  511 + pointY = getDataY(data[i], Ylabel);
  512 + mRoomTempPath.lineTo(pointX, pointY);
  513 + }
  514 + }
  515 + mRoomTempPathMeasure = new PathMeasure(mRoomTempPath, false);
  516 + }
  517 +
  518 + /**
  519 + * 获取target temp绘线Path数据
  520 + *
  521 + * @param data target temp绘线Path数据
  522 + */
  523 + private void initTargetTempPath(float[] data) {
  524 + mTargetTempPath.reset();
  525 + float pointX;
  526 + float pointY;
  527 + // 横向
  528 + mTargetTempPath.moveTo(Xpoint + xFirstPointOffset,
  529 + getDataY(data[0], Ylabel));
  530 + for (int i = 0; i < Xlabel.length; i++) {
  531 + float startX = Xpoint + i * Xscale + xFirstPointOffset;
  532 + // 绘制数据连线
  533 + if (i != 0) {
  534 + pointX = Xpoint + (i - 1) * Xscale + xFirstPointOffset;
  535 + pointY = getDataY(data[i - 1], Ylabel);
  536 + mTargetTempPath.lineTo(pointX, pointY);
  537 + }
  538 + if (i == Xlabel.length - 1) {
  539 + pointX = startX;
  540 + pointY = getDataY(data[i], Ylabel);
  541 + mTargetTempPath.lineTo(pointX, pointY);
  542 + }
  543 + }
  544 + mTargetTempPathMeasure = new PathMeasure(mTargetTempPath, false);
  545 + }
  546 +
  547 + // 绘制矩形图
  548 + private void drawRect(Canvas canvas, float[] data, int dataColor) {
  549 + Paint p = new Paint();
  550 + float left;
  551 + float top;
  552 + float right;
  553 + float bottom;
  554 + float stopY = getDataY(Float.parseFloat(Ylabel[Ylabel.length - 1]),
  555 + Ylabel);// 灰色线Y轴位置
  556 + float rectYScale = (Ypoint - stopY) / 100;
  557 +
  558 + p.setAntiAlias(true);
  559 + p.setStrokeWidth(dataStrokeWidth);
  560 + p.setColor(dataColor);
  561 +
  562 + // 横向
  563 + for (int i = 0; i < Xlabel.length; i++) {
  564 + // 绘制柱形图
  565 + if (i != 0) {
  566 + left = Xpoint + (i - 1) * Xscale + xFirstPointOffset + Xscale
  567 + / 6;
  568 + top = Ypoint - data[i - 1] * rectYScale + lineStrokeWidth;// 要绘制的rect最终top值
  569 + // 起点top + (起点top - 终点top) * mRectFration
  570 + rectCurrentTops[i] = Ypoint - (Ypoint - top) * mRectFration;// 根据fraction动态更新top值
  571 + right = left + Xscale * 4 / 6;
  572 + bottom = Ypoint;
  573 + canvas.drawRect(left, rectCurrentTops[i], right, bottom, p);//
  574 + // 每次valueAnimator更新时重绘最新top值
  575 + }
  576 + }
  577 + }
  578 +
  579 + private void drawY1Unit(Canvas canvas, Paint p) {
  580 + int maxYLabelValue = Integer.valueOf(Ylabel[Ylabel.length - 1]);
  581 + p.setTextSize(mYUnitTextSize);
  582 + float textWidth = p.measureText(mY1UnitText);
  583 + canvas.drawText(mY1UnitText, MarginLeft / 2 - textWidth / 2,
  584 + getDataY(maxYLabelValue, Ylabel) - mYLabelSize - mYLabelSize
  585 + / 5, p);
  586 + }
  587 +
  588 + private void drawY2Unit(Canvas canvas, Paint p) {
  589 + int maxYLabel2Value = Integer.valueOf(Ylabel2[Ylabel2.length - 1]);
  590 + p.setTextSize(mYUnitTextSize);
  591 + float textWidth = p.measureText(mY2UnitText);
  592 + canvas.drawText(mY2UnitText, this.getWidth() - MarginRight / 2
  593 + - textWidth * 3 / 4, getDataY(maxYLabel2Value, Ylabel2)
  594 + - mYLabelSize - mYLabelSize / 5, p);
  595 + }
  596 +
  597 + private void drawXUnit(Canvas canvas, Paint p) {
  598 + p.setTextSize(mXUnitTextSize);
  599 + float textWidth = p.measureText(mXUnitText);
  600 + canvas.drawText(mXUnitText, this.getWidth() / 2 - textWidth / 2, Ypoint
  601 + + mXlabelSize * 3 + mXlabelSize / 5, p);
  602 + }
  603 +
  604 + /**
  605 + * 获取data对应绘制Y点值
  606 + */
  607 + private float getDataY(float dataY, String[] Ylabel) {
  608 + float y0 = 0;
  609 + float y1 = 0;
  610 + try {
  611 + y0 = Float.parseFloat(Ylabel[0]);
  612 + y1 = Float.parseFloat(Ylabel[1]);
  613 + } catch (Exception e) {
  614 + return 0;
  615 + }
  616 + try {
  617 + return Ypoint - ((dataY - y0) * Yscale / (y1 - y0));
  618 + } catch (Exception e) {
  619 + return 0;
  620 + }
  621 + }
  622 +
  623 + @Override
  624 + protected void onLayout(boolean changed, int left, int top, int right,
  625 + int bottom) {
  626 + super.onLayout(changed, left, top, right, bottom);
  627 + // LogUtils.error(TAG, "onLayout");
  628 + initParams();
  629 +
  630 + if (onViewLayoutListener != null) {
  631 + onViewLayoutListener.onLayoutSuccess();
  632 + }
  633 +
  634 + //创建一个与该View相同大小的缓冲区
  635 + mCacheBitmap = Bitmap.createBitmap(this.getWidth(), this.getHeight(), Bitmap.Config
  636 + .ARGB_8888);
  637 + mCacheCanvas = new Canvas();
  638 + //设置cacheCanvas将会绘制到内存中cacheBitmap上
  639 + mCacheCanvas.setBitmap(mCacheBitmap);
  640 + }
  641 +
  642 + @Override
  643 + protected void onDraw(Canvas canvas) {
  644 + super.onDraw(canvas);
  645 + mCacheCanvas.drawColor(Color.BLACK);
  646 +
  647 + drawGreyXLine(mCacheCanvas, linePaint);
  648 +
  649 + drawUnit(mCacheCanvas);
  650 +
  651 + if (powerOnTimeDataArray.length > 1) {
  652 + drawRect(mCacheCanvas, powerOnTimeDataArray, powerTimeLineColor);
  653 + }
  654 +
  655 + mCacheCanvas.drawPath(mRoomTempPath, roomTempPaint);
  656 +
  657 + if (roomTempDataArray.length > 1) {
  658 + drawData(mCacheCanvas, roomTempDataArray, roomTempLineColor);
  659 + }
  660 +
  661 + mCacheCanvas.drawPath(mTargetTempPath, targetTempPaint);
  662 +
  663 + if (targetTempDataArray.length > 1) {
  664 + drawData(mCacheCanvas, targetTempDataArray, targetTempLineColor);
  665 + }
  666 +
  667 + drawXLine(mCacheCanvas, linePaint);
  668 +
  669 + //将cacheBitmap绘制到该View组件
  670 + canvas.drawBitmap(mCacheBitmap, 0, 0, mBmpPaint);
  671 + }
  672 +
  673 + /**
  674 + * 开启动画
  675 + */
  676 + private void startAnimation() {
  677 + if (mValueAnimator != null) {
  678 + mValueAnimator.cancel();
  679 + }
  680 + final float targetTempLength = mTargetTempPathMeasure.getLength();
  681 + final float roomTempLength = mRoomTempPathMeasure.getLength();
  682 + mValueAnimator = ValueAnimator.ofFloat(1, 0);
  683 + mValueAnimator.setDuration(ANIM_DURATION);
  684 + // 减速插值器
  685 + mValueAnimator.setInterpolator(new DecelerateInterpolator());
  686 + mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  687 + @Override
  688 + public void onAnimationUpdate(ValueAnimator animation) {
  689 + float fraction = (Float) animation.getAnimatedValue();
  690 + // 更新mtargetTempEffect
  691 + mtargetTempEffect = new DashPathEffect(new float[]{
  692 + targetTempLength, targetTempLength}, fraction
  693 + * targetTempLength);
  694 + targetTempPaint.setPathEffect(mtargetTempEffect);
  695 + // 更新mRoomTempEffect
  696 + mRoomTempEffect = new DashPathEffect(new float[]{
  697 + roomTempLength, roomTempLength}, fraction
  698 + * roomTempLength);
  699 + roomTempPaint.setPathEffect(mRoomTempEffect);
  700 + // 更新rect绘制fraction进度
  701 + mRectFration = 1 - fraction;// fraction是1->0 我们需要的柱形图绘制比例是0->1
  702 + postInvalidate();
  703 + }
  704 + });
  705 + mValueAnimator.start();
  706 + }
  707 +
  708 + public interface OnViewLayoutListener {
  709 + void onLayoutSuccess();
  710 + }
  711 +
  712 + public void setOnViewLayoutListener(
  713 + OnViewLayoutListener onViewLayoutListener) {
  714 + this.onViewLayoutListener = onViewLayoutListener;
  715 + }
  716 +
  717 + private OnViewLayoutListener onViewLayoutListener;
  718 +}
  719 +
mvpsdk/src/main/java/com/share/mvpsdk/widgets/HistoryModeView.java 0 → 100644
@@ -0,0 +1,107 @@ @@ -0,0 +1,107 @@
  1 +package com.share.mvpsdk.widgets;
  2 +
  3 +import android.content.Context;
  4 +import android.content.res.TypedArray;
  5 +import android.util.AttributeSet;
  6 +import android.view.View;
  7 +import android.widget.LinearLayout;
  8 +import android.widget.TextView;
  9 +
  10 +import com.share.mvpsdk.R;
  11 +import com.share.mvpsdk.utils.ResourcesUtils;
  12 +
  13 +
  14 +/**
  15 + * 历史数据查询界面模式自定义View
  16 + * @author zyw
  17 + * @creation 2016-12-26
  18 + */
  19 +public class HistoryModeView extends LinearLayout {
  20 + private LinearLayout ll_click_view;
  21 + private TextView tv_mode;
  22 + private float mSelectTextSize;
  23 + private float mUnSelectTextSize;
  24 +
  25 + public HistoryModeView(Context context, AttributeSet attrs, int defStyleAttr) {
  26 + super(context, attrs, defStyleAttr);
  27 +
  28 + ll_click_view = (LinearLayout) View.inflate(context, R.layout.sub_history_click_view, this);
  29 + tv_mode = (TextView) findViewById(R.id.tv_click_view);
  30 +
  31 + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.HistoryModeView);
  32 +
  33 + setText(ta.getString(R.styleable.HistoryModeView_android_text));
  34 + setSelectTextSize(ta.getDimension(R.styleable.HistoryModeView_select_text_size, 16));
  35 + setUnSelectTextSize(ta.getDimension(R.styleable.HistoryModeView_un_select_text_size, 12));
  36 + setViewTextSize();
  37 +
  38 + ta.recycle();
  39 + }
  40 +
  41 + public HistoryModeView(Context context, AttributeSet attrs) {
  42 + this(context, attrs, 0);
  43 + //init(context);
  44 + }
  45 +
  46 + public HistoryModeView(Context context) {
  47 + this(context, null);
  48 + //init(context);
  49 + }
  50 +
  51 + /**
  52 + * 设置控件选中状态
  53 + * @param isSelected 控件是否选中
  54 + */
  55 + public void setHistoryViewSelected(boolean isSelected){
  56 + ll_click_view.setSelected(isSelected);
  57 + setViewTextSize();
  58 + if(isSelected){
  59 + setTextColor(ResourcesUtils.getColor(R.color.light_yellow));
  60 + }else {
  61 + setTextColor(ResourcesUtils.getColor(R.color.light_grey));
  62 + }
  63 + }
  64 +
  65 + /**
  66 + * 设置控件文字
  67 + * @param str 控件文字
  68 + */
  69 + public void setText(String str){
  70 + tv_mode.setText(str);
  71 + }
  72 +
  73 + /**
  74 + * 设置控件文字颜色
  75 + * @param color 控件文字颜色
  76 + */
  77 + public void setTextColor(int color){
  78 + tv_mode.setTextColor(color);
  79 + }
  80 +
  81 + /**
  82 + * 设置根据view的选中状态更新text字号
  83 + */
  84 + public void setViewTextSize() {
  85 + if(ll_click_view.isSelected()){
  86 + tv_mode.getPaint().setTextSize(mSelectTextSize);
  87 + }else{
  88 + tv_mode.getPaint().setTextSize(mUnSelectTextSize);
  89 + }
  90 + }
  91 +
  92 + /**
  93 + * 设置view选中的字体大小
  94 + * @param selectSize 选中字体大小
  95 + */
  96 + public void setSelectTextSize(float selectSize){
  97 + mSelectTextSize = selectSize;
  98 + }
  99 +
  100 + /**
  101 + * 设置view没有选中的字体大小
  102 + * @param unSelectSize 非选中字体大小
  103 + */
  104 + public void setUnSelectTextSize(float unSelectSize){
  105 + mUnSelectTextSize = unSelectSize;
  106 + }
  107 +}
0 \ No newline at end of file 108 \ No newline at end of file
mvpsdk/src/main/java/com/share/mvpsdk/widgets/HistoryTipView.java 0 → 100644
@@ -0,0 +1,95 @@ @@ -0,0 +1,95 @@
  1 +package com.share.mvpsdk.widgets;
  2 +
  3 +import android.content.Context;
  4 +import android.content.res.TypedArray;
  5 +import android.graphics.Color;
  6 +import android.util.AttributeSet;
  7 +import android.view.View;
  8 +import android.widget.ImageView;
  9 +import android.widget.LinearLayout;
  10 +import android.widget.TextView;
  11 +
  12 +import com.share.mvpsdk.R;
  13 +
  14 +
  15 +/**
  16 + * 历史数据查询界面Tips自定义View
  17 + * @author zyw
  18 + * @creation 2016-12-27
  19 + */
  20 +public class HistoryTipView extends LinearLayout {
  21 + private TextView tv_tips1;
  22 + private TextView tv_tips2;
  23 + private ImageView iv_tips;
  24 + private TypedArray ta;
  25 +
  26 + public HistoryTipView(Context context, AttributeSet attrs, int defStyleAttr) {
  27 + super(context, attrs, defStyleAttr);
  28 +
  29 + ta = context.obtainStyledAttributes(attrs, R.styleable.HistoryTipsView);
  30 + init(context);
  31 + ta.recycle();
  32 + }
  33 +
  34 + public HistoryTipView(Context context, AttributeSet attrs) {
  35 + this(context, attrs, 0);
  36 + //init(context);
  37 + }
  38 +
  39 + public HistoryTipView(Context context) {
  40 + this(context, null);
  41 + //init(context);
  42 + }
  43 +
  44 + public void init(Context context){
  45 + View.inflate(context, R.layout.sub_history_tips, this);
  46 +
  47 + tv_tips1 = (TextView) findViewById(R.id.tv_tip1);
  48 + tv_tips2 = (TextView) findViewById(R.id.tv_tip2);
  49 + iv_tips = (ImageView) findViewById(R.id.iv_tip);
  50 +
  51 + setTipOneText(ta.getString(R.styleable.HistoryTipsView_tip_one_text));
  52 + setTipTwoText(ta.getString(R.styleable.HistoryTipsView_tip_two_text));
  53 + setTextColor(ta.getColor(R.styleable.HistoryTipsView_android_textColor, Color.WHITE));
  54 + setTextSize(ta.getDimension(R.styleable.HistoryTipsView_android_textSize, 12));
  55 + setBackground(ta.getResourceId(R.styleable.HistoryTipsView_android_src, 0));
  56 + }
  57 +
  58 + /**
  59 + * 设置控件Tip1文字
  60 + * @param str
  61 + */
  62 + public void setTipOneText(String str){
  63 + tv_tips1.setText(str);
  64 + }
  65 +
  66 + /**
  67 + * 设置控件Tip2s文字
  68 + * @param str
  69 + */
  70 + public void setTipTwoText(String str){
  71 + tv_tips2.setText(str);
  72 + }
  73 +
  74 + /**
  75 + * 设置控件Tip1 2文字颜色
  76 + * @param color
  77 + */
  78 + public void setTextColor(int color){
  79 + tv_tips1.setTextColor(color);
  80 + tv_tips2.setTextColor(color);
  81 + }
  82 +
  83 + /**
  84 + * 设置根据view的选中状态更新text字号
  85 + */
  86 + public void setTextSize(float textSize) {
  87 + tv_tips1.getPaint().setTextSize(textSize);
  88 + tv_tips2.getPaint().setTextSize(textSize);
  89 + }
  90 +
  91 + public void setBackground(int resId){
  92 + iv_tips.setImageResource(resId);
  93 + }
  94 +}
  95 +
mvpsdk/src/main/java/com/share/mvpsdk/widgets/MovingImageView.java 0 → 100644
@@ -0,0 +1,332 @@ @@ -0,0 +1,332 @@
  1 +/*
  2 + * Copyright (C) 2014 Albert Grobas
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package com.share.mvpsdk.widgets;
  18 +
  19 +import android.content.Context;
  20 +import android.content.res.TypedArray;
  21 +import android.graphics.Bitmap;
  22 +import android.graphics.Matrix;
  23 +import android.graphics.drawable.Drawable;
  24 +import android.net.Uri;
  25 +import android.util.AttributeSet;
  26 +import android.widget.ImageView;
  27 +
  28 +import com.share.mvpsdk.R;
  29 +
  30 +
  31 +/**
  32 + * Created by Horrarndoo on 2017/9/7.
  33 + * <p>
  34 + * 自定义可以背景滚动的ImageView
  35 + */
  36 +public class MovingImageView extends ImageView {
  37 +
  38 + private float canvasWidth, canvasHeight;
  39 + private float imageWidth, imageHeight;
  40 + private float offsetWidth, offsetHeight;
  41 + /**
  42 + * 移动类型
  43 + */
  44 + private int movementType;
  45 +
  46 + /**
  47 + * 限定最大比值
  48 + * canvasHeight/drawableHeight 或者 canvasWidth/drawableWidth
  49 + */
  50 + private float maxRelativeSize;
  51 + /**
  52 + * 最小相对偏移值,图片最起码可以位移图*0.2的距离
  53 + */
  54 + private float minRelativeOffset;
  55 + private int mSpeed;
  56 + private long startDelay;
  57 + private int mRepetitions;
  58 + private boolean loadOnCreate;//load完毕后是否移动
  59 +
  60 + private MovingViewAnimator mAnimator;
  61 +
  62 + public MovingImageView(Context context) {
  63 + this(context, null);
  64 + }
  65 +
  66 + public MovingImageView(Context context, AttributeSet attrs) {
  67 + this(context, attrs, 0);
  68 + }
  69 +
  70 + public MovingImageView(Context context, AttributeSet attrs, int defStyle) {
  71 + super(context, attrs, defStyle);
  72 +
  73 + TypedArray ta = context.getTheme().obtainStyledAttributes(attrs,
  74 + R.styleable.MovingImageView, defStyle, 0);
  75 +
  76 + try {
  77 + maxRelativeSize = ta.getFloat(R.styleable.MovingImageView_miv_max_relative_size, 3.0f);
  78 + minRelativeOffset = ta.getFloat(R.styleable.MovingImageView_miv_min_relative_offset,
  79 + 0.2f);
  80 + mSpeed = ta.getInt(R.styleable.MovingImageView_miv_speed, 50);
  81 + mRepetitions = ta.getInt(R.styleable.MovingImageView_miv_repetitions, -1);
  82 + startDelay = ta.getInt(R.styleable.MovingImageView_miv_start_delay, 0);
  83 + loadOnCreate = ta.getBoolean(R.styleable.MovingImageView_miv_load_on_create, true);
  84 + } finally {
  85 + ta.recycle();
  86 + }
  87 +
  88 + init();
  89 + }
  90 +
  91 + private void init() {
  92 + super.setScaleType(ScaleType.MATRIX);
  93 + mAnimator = new MovingViewAnimator(this);
  94 + }
  95 +
  96 + /**
  97 + * 更新canvas size
  98 + *
  99 + * @param w new width.
  100 + * @param h new height.
  101 + * @param oldW old width.
  102 + * @param oldH old height.
  103 + */
  104 + @Override
  105 + protected void onSizeChanged(int w, int h, int oldW, int oldH) {
  106 + super.onSizeChanged(w, h, oldW, oldH);
  107 + canvasWidth = (float) w - (float) (getPaddingLeft() + getPaddingRight());
  108 + canvasHeight = (float) h - (float) (getPaddingTop() + getPaddingBottom());
  109 + updateAll();
  110 + }
  111 +
  112 + private void updateAll() {
  113 + if (getDrawable() != null) {
  114 + updateImageSize();
  115 + updateOffsets();
  116 + updateAnimatorValues();
  117 + }
  118 + }
  119 +
  120 + /**
  121 + * 更新图片Size
  122 + */
  123 + private void updateImageSize() {
  124 + imageWidth = getDrawable().getIntrinsicWidth();//获取图片高度
  125 + imageHeight = getDrawable().getIntrinsicHeight();//获取图片宽度
  126 + }
  127 +
  128 + /**
  129 + * 更新偏移量,确定动画范围
  130 + */
  131 + private void updateOffsets() {
  132 + float minSizeX = imageWidth * minRelativeOffset;
  133 + float minSizeY = imageHeight * minRelativeOffset;
  134 + offsetWidth = (imageWidth - canvasWidth - minSizeX) > 0 ? imageWidth - canvasWidth : 0;
  135 + offsetHeight = (imageHeight - canvasHeight - minSizeY) > 0 ? imageHeight - canvasHeight : 0;
  136 + }
  137 +
  138 + /**
  139 + * 更新动画基本数据
  140 + */
  141 + private void updateAnimatorValues() {
  142 + if (canvasHeight == 0 && canvasWidth == 0)
  143 + return;
  144 +
  145 + float scale = calculateTypeAndScale();
  146 + if (scale == 0)
  147 + return;
  148 +
  149 + float w = (imageWidth * scale) - canvasWidth;
  150 + float h = (imageHeight * scale) - canvasHeight;
  151 +
  152 + mAnimator.updateValues(movementType, w, h);
  153 + mAnimator.setStartDelay(startDelay);
  154 + mAnimator.setSpeed(mSpeed);
  155 + mAnimator.setRepetition(mRepetitions);
  156 +
  157 + if (loadOnCreate) {
  158 + startMoving();
  159 + }
  160 + }
  161 +
  162 + /**
  163 + * 设置最佳的运动类型
  164 + * 计算缩放比例
  165 + *
  166 + * @return image scale.
  167 + */
  168 + private float calculateTypeAndScale() {
  169 + movementType = MovingViewAnimator.AUTO_MOVE;
  170 + float scale = 1f;
  171 + float scaleByImage = Math.max(imageWidth / canvasWidth, imageHeight / canvasHeight);
  172 + Matrix matrix = new Matrix();
  173 +
  174 + if (offsetWidth == 0 && offsetHeight == 0) {//图片太小,无法动画,需要放大
  175 + //画布宽度/图片宽度
  176 + float sW = canvasWidth / imageWidth;
  177 + //画布高度/图片高度
  178 + float sH = canvasHeight / imageHeight;
  179 +
  180 + if (sW > sH) {
  181 + scale = Math.min(sW, maxRelativeSize);//限定最大缩放值
  182 + matrix.setTranslate((canvasWidth - imageWidth * scale) / 2f, 0);
  183 + movementType = MovingViewAnimator.VERTICAL_MOVE;//垂直移动
  184 +
  185 + } else if (sW < sH) {
  186 + scale = Math.min(sH, maxRelativeSize);//限定最大缩放值
  187 + matrix.setTranslate(0, (canvasHeight - imageHeight * scale) / 2f);
  188 + movementType = MovingViewAnimator.HORIZONTAL_MOVE;//水平移动
  189 +
  190 + } else {
  191 + scale = Math.max(sW, maxRelativeSize);//限定最大缩放值
  192 + movementType = (scale == sW) ? MovingViewAnimator.NONE_MOVE :
  193 + MovingViewAnimator.DIAGONAL_MOVE;//对角线移动
  194 + }
  195 + } else if (offsetWidth == 0) {//宽度太小,无法执行水平动画,放大宽度
  196 + scale = canvasWidth / imageWidth;
  197 + movementType = MovingViewAnimator.VERTICAL_MOVE;
  198 +
  199 + } else if (offsetHeight == 0) {//高度太小,无法执行垂直动画,放大高度
  200 + scale = canvasHeight / imageHeight;//求出画布高度和图片高度的比值用于确定画布起始坐标
  201 + movementType = MovingViewAnimator.HORIZONTAL_MOVE;
  202 +
  203 + } else if (scaleByImage > maxRelativeSize) {//图片太大,根据最大比值设定图片缩放值
  204 + scale = maxRelativeSize / scaleByImage;
  205 + if (imageWidth * scale < canvasWidth || imageHeight * scale < canvasHeight) {
  206 + scale = Math.max(canvasWidth / imageWidth, canvasHeight / imageHeight);
  207 + }
  208 + }
  209 +
  210 + matrix.preScale(scale, scale);
  211 + setImageMatrix(matrix);
  212 + return scale;
  213 + }
  214 +
  215 + /**
  216 + * 禁止设置ScaleType
  217 + *
  218 + * @param scaleType
  219 + */
  220 + @Override
  221 + @Deprecated
  222 + public void setScaleType(ScaleType scaleType) {
  223 + //super.setScaleType(scaleType);
  224 + }
  225 +
  226 + @Override
  227 + public void setImageResource(int resId) {
  228 + super.setImageResource(resId);
  229 + updateAll();
  230 + }
  231 +
  232 + @Override
  233 + public void setImageURI(Uri uri) {
  234 + super.setImageURI(uri);
  235 + updateAll();
  236 + }
  237 +
  238 + @Override
  239 + public void setImageDrawable(Drawable drawable) {
  240 + super.setImageDrawable(drawable);
  241 + updateAll();
  242 + }
  243 +
  244 + @Override
  245 + public void setImageBitmap(Bitmap bm) {
  246 + super.setImageBitmap(bm);
  247 + updateAll();
  248 + }
  249 +
  250 + /**
  251 + * 获取animator
  252 + *
  253 + * @return
  254 + */
  255 + public MovingViewAnimator getMovingAnimator() {
  256 + return mAnimator;
  257 + }
  258 +
  259 + public float getMaxRelativeSize() {
  260 + return maxRelativeSize;
  261 + }
  262 +
  263 + public void setMaxRelativeSize(float max) {
  264 + maxRelativeSize = max;
  265 + updateAnimatorValues();
  266 + }
  267 +
  268 + public float getMinRelativeOffset() {
  269 + return minRelativeOffset;
  270 + }
  271 +
  272 + public void setMinRelativeOffset(float min) {
  273 + minRelativeOffset = min;
  274 + updateAnimatorValues();
  275 + }
  276 +
  277 + public boolean isLoadOnCreate() {
  278 + return loadOnCreate;
  279 + }
  280 +
  281 + public void setLoadOnCreate(boolean loadOnCreate) {
  282 + this.loadOnCreate = loadOnCreate;
  283 + }
  284 +
  285 + /**
  286 + * 开始移动
  287 + * 默认不停的移动
  288 + */
  289 + public void startMoving() {
  290 + startMoving(-1);
  291 + }
  292 +
  293 + /**
  294 + * 开始移动
  295 + *
  296 + * @param repetition 循环模式
  297 + */
  298 + public void startMoving(int repetition) {
  299 + mAnimator.setRepetition(repetition);
  300 + mAnimator.start();
  301 + }
  302 +
  303 + /**
  304 + * 恢复移动
  305 + */
  306 + public void resumeMoving() {
  307 + mAnimator.resume();
  308 + }
  309 +
  310 + /**
  311 + * 暂停移动
  312 + */
  313 + public void pauseMoving() {
  314 + mAnimator.pause();
  315 + }
  316 +
  317 + /**
  318 + * 停止移动
  319 + */
  320 + public void stopMoving() {
  321 + mAnimator.stop();
  322 + }
  323 +
  324 + /**
  325 + * 获取当前状态
  326 + *
  327 + * @return
  328 + */
  329 + public MovingViewAnimator.MovingState getMovingState() {
  330 + return mAnimator.getMovingState();
  331 + }
  332 +}
mvpsdk/src/main/java/com/share/mvpsdk/widgets/MovingViewAnimator.java 0 → 100644
@@ -0,0 +1,448 @@ @@ -0,0 +1,448 @@
  1 +/*
  2 + * Copyright (C) 2014 Albert Grobas
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +package com.share.mvpsdk.widgets;
  18 +
  19 +import android.animation.Animator;
  20 +import android.animation.AnimatorListenerAdapter;
  21 +import android.animation.AnimatorSet;
  22 +import android.animation.ObjectAnimator;
  23 +import android.animation.PropertyValuesHolder;
  24 +import android.annotation.TargetApi;
  25 +import android.os.Build;
  26 +import android.view.View;
  27 +import android.view.animation.AccelerateDecelerateInterpolator;
  28 +import android.view.animation.Interpolator;
  29 +
  30 +import java.util.ArrayList;
  31 +import java.util.List;
  32 +
  33 +/**
  34 + * Created by Horrarndoo on 2017/9/7.
  35 + * <p>
  36 + * 滚动view动画
  37 + */
  38 +public class MovingViewAnimator {
  39 + /**
  40 + * 水平移动
  41 + */
  42 + public static final int HORIZONTAL_MOVE = 1;
  43 + /**
  44 + * 垂直移动
  45 + */
  46 + public static final int VERTICAL_MOVE = 2;
  47 + /**
  48 + * 对角线移动
  49 + */
  50 + public static final int DIAGONAL_MOVE = 3;
  51 + /**
  52 + * 自动移动
  53 + */
  54 + public static final int AUTO_MOVE = 0;
  55 + /**
  56 + * 不移动
  57 + */
  58 + public static final int NONE_MOVE = -1;
  59 +
  60 + private AnimatorSet mAnimatorSet;
  61 + private View mView;
  62 +
  63 + private boolean isRunning;
  64 + private int currentLoop;
  65 + private boolean infiniteRepetition = true;
  66 + private ArrayList<Float> pathDistances;
  67 +
  68 + private int loopCount = -1;
  69 + private int movementType;
  70 + private float offsetWidth, offsetHeight;
  71 + private int mSpeed = 50;
  72 + private long mDelay = 0;
  73 + private Interpolator mInterpolator;
  74 +
  75 + private MovingState currentState = MovingState.stop;
  76 +
  77 + public enum MovingState {
  78 + stop,
  79 + moving,
  80 + pause
  81 + }
  82 +
  83 + private Animator.AnimatorListener animatorListener = new AnimatorListenerAdapter() {
  84 + @Override
  85 + public void onAnimationEnd(final Animator animation) {
  86 + //super.onAnimationEnd(animation);
  87 + //运行在主线程
  88 + mView.post((new Runnable() {
  89 + public void run() {
  90 + if (isRunning) {
  91 + if (infiniteRepetition) {
  92 + mAnimatorSet.start();
  93 + } else {
  94 + currentLoop--;
  95 + if (currentLoop > 0) {
  96 + mAnimatorSet.start();
  97 + }
  98 + }
  99 + }
  100 + }
  101 + }));
  102 + }
  103 + };
  104 +
  105 + public MovingViewAnimator(View imgView) {
  106 + mView = imgView;
  107 + isRunning = false;
  108 + mAnimatorSet = new AnimatorSet();
  109 + pathDistances = new ArrayList<>();
  110 + mInterpolator = new AccelerateDecelerateInterpolator();
  111 + }
  112 +
  113 + public MovingViewAnimator(View imgView, int type, float width, float height) {
  114 + this(imgView);
  115 + updateValues(type, width, height);
  116 + }
  117 +
  118 + private void init() {
  119 + setUpAnimator();
  120 + setUpValues();
  121 + }
  122 +
  123 + /**
  124 + * 根据移动类型设置不同的动画
  125 + */
  126 + private void setUpAnimator() {
  127 + AnimatorSet animatorSet = new AnimatorSet();
  128 + pathDistances.clear();
  129 +
  130 + switch (movementType) {
  131 + case HORIZONTAL_MOVE:
  132 + animatorSet.playSequentially(createHorizontalAnimator(0, offsetWidth),
  133 + createHorizontalAnimator(offsetWidth, 0));
  134 + break;
  135 + case VERTICAL_MOVE:
  136 + animatorSet.playSequentially(createVerticalAnimator(0, offsetHeight),
  137 + createVerticalAnimator(offsetHeight, 0));
  138 + break;
  139 + case DIAGONAL_MOVE:
  140 + animatorSet.playSequentially(createDiagonalAnimator(0, offsetWidth, 0,
  141 + offsetHeight),
  142 + createDiagonalAnimator(offsetWidth, 0, offsetHeight, 0));
  143 + break;
  144 + case AUTO_MOVE:
  145 + animatorSet.playSequentially(
  146 + createVerticalAnimator(0, offsetHeight),
  147 + createDiagonalAnimator(0, offsetWidth, offsetHeight, 0),
  148 + createHorizontalAnimator(offsetWidth, 0),
  149 + createDiagonalAnimator(0, offsetWidth, 0, offsetHeight),
  150 + createHorizontalAnimator(offsetWidth, 0),
  151 + createVerticalAnimator(offsetHeight, 0));
  152 + }
  153 +
  154 + if (mAnimatorSet != null) {
  155 + mAnimatorSet.removeAllListeners();
  156 + stop();
  157 + }
  158 + mAnimatorSet = animatorSet;
  159 + }
  160 +
  161 + /**
  162 + * 设置参数数据
  163 + */
  164 + private void setUpValues() {
  165 + setSpeed(mSpeed);
  166 + setStartDelay(mDelay);
  167 + setRepetition(loopCount);
  168 + setInterpolator(mInterpolator);
  169 + }
  170 +
  171 + private void setListener() {
  172 + mAnimatorSet.addListener(animatorListener);
  173 + }
  174 +
  175 + /**
  176 + * 更新动画值.
  177 + *
  178 + * @param type
  179 + * @param w
  180 + * @param h
  181 + */
  182 + public void updateValues(int type, float w, float h) {
  183 + this.movementType = type;
  184 + this.offsetWidth = w;
  185 + this.offsetHeight = h;
  186 + init();
  187 + }
  188 +
  189 + public void setMovementType(int type) {
  190 + updateValues(type, offsetWidth, offsetHeight);
  191 + }
  192 +
  193 + public void setOffsets(float w, float h) {
  194 + updateValues(movementType, w, h);
  195 + }
  196 +
  197 + public void start() {
  198 + //Log.e("tag", "start.");
  199 + if (movementType != NONE_MOVE) {
  200 + isRunning = true;
  201 + if (!infiniteRepetition)
  202 + currentLoop = loopCount;
  203 + setListener();
  204 + mAnimatorSet.start();
  205 + currentState = MovingState.moving;
  206 + }
  207 + }
  208 +
  209 + public void cancel() {
  210 + if (isRunning) {
  211 + mAnimatorSet.removeListener(animatorListener);
  212 + mAnimatorSet.cancel();
  213 + currentState = MovingState.stop;
  214 + }
  215 + }
  216 +
  217 + @TargetApi(19)
  218 + public void pause() {
  219 + //Log.e("tag", "pause.");
  220 + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
  221 + return;
  222 +
  223 + if (mAnimatorSet.isStarted()) {
  224 + mAnimatorSet.pause();
  225 + currentState = MovingState.pause;
  226 + }
  227 + }
  228 +
  229 + @TargetApi(19)
  230 + public void resume() {
  231 + //Log.e("tag", "resume.");
  232 + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
  233 + return;
  234 +
  235 + if (mAnimatorSet.isPaused()) {
  236 + mAnimatorSet.resume();
  237 + currentState = MovingState.moving;
  238 + }
  239 + }
  240 +
  241 + public void stop() {
  242 + //Log.e("tag", "stop.");
  243 + isRunning = false;
  244 + mAnimatorSet.removeListener(animatorListener);
  245 + mAnimatorSet.end();
  246 + mView.clearAnimation();
  247 + currentState = MovingState.stop;
  248 + }
  249 +
  250 + /**
  251 + * 设置重复模式
  252 + *
  253 + * @param repetition repetition < 0 循环播放
  254 + * repetition > 0 循环repetition次
  255 + */
  256 + public void setRepetition(int repetition) {
  257 + if (repetition < 0)
  258 + infiniteRepetition = true;
  259 + else {
  260 + loopCount = repetition;
  261 + currentLoop = loopCount;
  262 + infiniteRepetition = false;
  263 + }
  264 + }
  265 +
  266 + public Builder addCustomMovement() {
  267 + return new Builder();
  268 + }
  269 +
  270 + public void clearCustomMovement() {
  271 + init();
  272 + start();
  273 + }
  274 +
  275 + public int getMovementType() {
  276 + return movementType;
  277 + }
  278 +
  279 + public int getRemainingRepetitions() {
  280 + return (infiniteRepetition) ? -1 : currentLoop;
  281 + }
  282 +
  283 + public void setInterpolator(Interpolator interpolator) {
  284 + mInterpolator = interpolator;
  285 + mAnimatorSet.setInterpolator(interpolator);
  286 + }
  287 +
  288 + /**
  289 + * 设置动画播放之前的延时时间
  290 + *
  291 + * @param time
  292 + */
  293 + public void setStartDelay(long time) {
  294 + mDelay = time;
  295 + mAnimatorSet.setStartDelay(time);
  296 + }
  297 +
  298 + /**
  299 + * 设置每个动画对应的持续时间
  300 + *
  301 + * @param speed
  302 + */
  303 + public void setSpeed(int speed) {
  304 + mSpeed = speed;
  305 + List<Animator> listAnimator = mAnimatorSet.getChildAnimations();
  306 + for (int i = 0; i < listAnimator.size(); i++) {
  307 + Animator a = listAnimator.get(i);
  308 + a.setDuration(parseSpeed(pathDistances.get(i)));
  309 + }
  310 + }
  311 +
  312 + /**
  313 + * 将速度设置值转换成秒
  314 + *
  315 + * @param distance
  316 + * @return
  317 + */
  318 + private long parseSpeed(float distance) {
  319 + return (long) ((distance / (float) mSpeed) * 1000f);
  320 + }
  321 +
  322 + /**
  323 + * 创建水平移动动画
  324 + *
  325 + * @param startValue
  326 + * @param endValue
  327 + * @return
  328 + */
  329 + private ObjectAnimator createHorizontalAnimator(float startValue, float endValue) {
  330 + pathDistances.add(Math.abs(startValue - endValue));
  331 + return createObjectAnimation("scrollX", startValue, endValue);
  332 + }
  333 +
  334 + /**
  335 + * 创建垂直移动动画
  336 + *
  337 + * @param startValue
  338 + * @param endValue
  339 + * @return
  340 + */
  341 + private ObjectAnimator createVerticalAnimator(float startValue, float endValue) {
  342 + pathDistances.add(Math.abs(startValue - endValue));
  343 + return createObjectAnimation("scrollY", startValue, endValue);
  344 + }
  345 +
  346 + /**
  347 + * 创建对角线移动动画
  348 + *
  349 + * @param startW
  350 + * @param endW
  351 + * @param startH
  352 + * @param endH
  353 + * @return
  354 + */
  355 + private ObjectAnimator createDiagonalAnimator(float startW, float endW, float startH, float
  356 + endH) {
  357 + float diagonal = Pythagoras(Math.abs(startW - endW), Math.abs(startH - endH));
  358 + pathDistances.add(diagonal);
  359 + PropertyValuesHolder pvhX = createPropertyValuesHolder("scrollX", startW, endW);
  360 + PropertyValuesHolder pvhY = createPropertyValuesHolder("scrollY", startH, endH);
  361 + return ObjectAnimator.ofPropertyValuesHolder(mView, pvhX, pvhY);
  362 + }
  363 +
  364 + private ObjectAnimator createObjectAnimation(String prop, float startValue, float endValue) {
  365 + return ObjectAnimator.ofInt(mView, prop, (int) startValue, (int) endValue);
  366 + }
  367 +
  368 + private PropertyValuesHolder createPropertyValuesHolder(String prop, float startValue, float
  369 + endValue) {
  370 + return PropertyValuesHolder.ofInt(prop, (int) startValue, (int) endValue);
  371 + }
  372 +
  373 + private static float Pythagoras(float a, float b) {
  374 + return (float) Math.sqrt((a * a) + (b * b));
  375 + }
  376 +
  377 + /**
  378 + * 自定义自动移动方式
  379 + */
  380 + public class Builder {
  381 +
  382 + private ArrayList<Animator> mList;
  383 +
  384 + private Builder() {
  385 + mList = new ArrayList<>();
  386 + pathDistances.clear();
  387 + }
  388 +
  389 + public Builder addHorizontalMoveToRight() {
  390 + mList.add(createHorizontalAnimator(0, offsetWidth));
  391 + return this;
  392 + }
  393 +
  394 + public Builder addHorizontalMoveToLeft() {
  395 + mList.add(createHorizontalAnimator(offsetWidth, 0));
  396 + return this;
  397 + }
  398 +
  399 + public Builder addVerticalMoveToDown() {
  400 + mList.add(createVerticalAnimator(0, offsetHeight));
  401 + return this;
  402 + }
  403 +
  404 + public Builder addVerticalMoveToUp() {
  405 + mList.add(createVerticalAnimator(offsetHeight, 0));
  406 + return this;
  407 + }
  408 +
  409 + public Builder addDiagonalMoveToDownRight() {
  410 + mList.add(createDiagonalAnimator(0, offsetWidth, 0, offsetHeight));
  411 + return this;
  412 + }
  413 +
  414 + public Builder addDiagonalMoveToDownLeft() {
  415 + mList.add(createDiagonalAnimator(offsetWidth, 0, 0, offsetHeight));
  416 + return this;
  417 + }
  418 +
  419 + public Builder addDiagonalMoveToUpRight() {
  420 + mList.add(createDiagonalAnimator(0, offsetWidth, offsetHeight, 0));
  421 + return this;
  422 + }
  423 +
  424 + public Builder addDiagonalMoveToUpLeft() {
  425 + mList.add(createDiagonalAnimator(offsetWidth, 0, offsetHeight, 0));
  426 + return this;
  427 + }
  428 +
  429 + public void start() {
  430 + mAnimatorSet.removeAllListeners();
  431 + stop();
  432 + mAnimatorSet = new AnimatorSet();
  433 + mAnimatorSet.playSequentially(mList);
  434 + setListener();
  435 + setUpValues();
  436 + MovingViewAnimator.this.start();
  437 + }
  438 + }
  439 +
  440 + /**
  441 + * 获取当前状态
  442 + *
  443 + * @return
  444 + */
  445 + public MovingState getMovingState() {
  446 + return currentState;
  447 + }
  448 +}
0 \ No newline at end of file 449 \ No newline at end of file
mvpsdk/src/main/java/com/share/mvpsdk/widgets/NestedScrollWebView.java 0 → 100644
@@ -0,0 +1,168 @@ @@ -0,0 +1,168 @@
  1 +package com.share.mvpsdk.widgets;
  2 +
  3 +import android.content.Context;
  4 +import android.support.v4.view.MotionEventCompat;
  5 +import android.support.v4.view.NestedScrollingChild;
  6 +import android.support.v4.view.NestedScrollingChildHelper;
  7 +import android.support.v4.view.ViewCompat;
  8 +import android.util.AttributeSet;
  9 +import android.view.MotionEvent;
  10 +import android.webkit.WebView;
  11 +
  12 +/**
  13 + * Created by Horrarndoo on 2017/9/27.
  14 + * <p>
  15 + * 继承原生WebView,目的是为了和AppBarLayout、CollapsingToolbarLayout等Android Design Support Library控件配合使用。
  16 + * <p>
  17 + * 避免AppBarLayout+NestSrollView+WebView嵌套导致的WebView高度判断异常导致WebView跳转后高度异常的问题;
  18 + */
  19 +public class NestedScrollWebView extends WebView implements NestedScrollingChild {
  20 +
  21 + public static final String TAG = NestedScrollWebView.class.getSimpleName();
  22 +
  23 + private int mLastMotionY;
  24 +
  25 + private final int[] mScrollOffset = new int[2];
  26 + private final int[] mScrollConsumed = new int[2];
  27 +
  28 + private int mNestedYOffset;
  29 + private boolean mChange;
  30 +
  31 + private NestedScrollingChildHelper mChildHelper;
  32 +
  33 + public NestedScrollWebView(Context context) {
  34 + super(context);
  35 + init();
  36 + }
  37 +
  38 + public NestedScrollWebView(Context context, AttributeSet attrs) {
  39 + super(context, attrs);
  40 + init();
  41 + }
  42 +
  43 + public NestedScrollWebView(Context context, AttributeSet attrs, int defStyleAttr) {
  44 + super(context, attrs, defStyleAttr);
  45 + init();
  46 + }
  47 +
  48 + private void init() {
  49 + mChildHelper = new NestedScrollingChildHelper(this);
  50 + setNestedScrollingEnabled(true);
  51 + }
  52 +
  53 + @Override
  54 + public boolean onTouchEvent(MotionEvent event) {
  55 + boolean result = false;
  56 +
  57 + MotionEvent trackedEvent = MotionEvent.obtain(event);
  58 +
  59 + final int action = MotionEventCompat.getActionMasked(event);
  60 +
  61 + if (action == MotionEvent.ACTION_DOWN) {
  62 + mNestedYOffset = 0;
  63 + }
  64 +
  65 + int y = (int) event.getY();
  66 +
  67 + event.offsetLocation(0, mNestedYOffset);
  68 +
  69 + switch (action) {
  70 + case MotionEvent.ACTION_DOWN:
  71 + mLastMotionY = y;
  72 + startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
  73 + result = super.onTouchEvent(event);
  74 + mChange = false;
  75 + break;
  76 + case MotionEvent.ACTION_MOVE:
  77 + int deltaY = mLastMotionY - y;
  78 +
  79 + if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) {
  80 + deltaY -= mScrollConsumed[1];
  81 + trackedEvent.offsetLocation(0, mScrollOffset[1]);
  82 + mNestedYOffset += mScrollOffset[1];
  83 + }
  84 +
  85 + int oldY = getScrollY();
  86 + mLastMotionY = y - mScrollOffset[1];
  87 + int newScrollY = Math.max(0, oldY + deltaY);
  88 + deltaY -= newScrollY - oldY;
  89 + if (dispatchNestedScroll(0, newScrollY - deltaY, 0, deltaY, mScrollOffset)) {
  90 + mLastMotionY -= mScrollOffset[1];
  91 + trackedEvent.offsetLocation(0, mScrollOffset[1]);
  92 + mNestedYOffset += mScrollOffset[1];
  93 + }
  94 + if (mScrollConsumed[1] == 0 && mScrollOffset[1] == 0) {
  95 + if (mChange) {
  96 + mChange = false;
  97 + trackedEvent.setAction(MotionEvent.ACTION_DOWN);
  98 + super.onTouchEvent(trackedEvent);
  99 + } else {
  100 + result = super.onTouchEvent(trackedEvent);
  101 + }
  102 + trackedEvent.recycle();
  103 + } else {
  104 + if (!mChange) {
  105 + mChange = true;
  106 + super.onTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_CANCEL, 0,
  107 + 0, 0));
  108 + }
  109 + }
  110 + break;
  111 + case MotionEvent.ACTION_POINTER_DOWN:
  112 + case MotionEvent.ACTION_UP:
  113 + case MotionEvent.ACTION_CANCEL:
  114 + stopNestedScroll();
  115 + result = super.onTouchEvent(event);
  116 + break;
  117 + }
  118 + return result;
  119 + }
  120 +
  121 + // NestedScrollingChild
  122 + @Override
  123 + public void setNestedScrollingEnabled(boolean enabled) {
  124 + mChildHelper.setNestedScrollingEnabled(enabled);
  125 + }
  126 +
  127 + @Override
  128 + public boolean isNestedScrollingEnabled() {
  129 + return mChildHelper.isNestedScrollingEnabled();
  130 + }
  131 +
  132 + @Override
  133 + public boolean startNestedScroll(int axes) {
  134 + return mChildHelper.startNestedScroll(axes);
  135 + }
  136 +
  137 + @Override
  138 + public void stopNestedScroll() {
  139 + mChildHelper.stopNestedScroll();
  140 + }
  141 +
  142 + @Override
  143 + public boolean hasNestedScrollingParent() {
  144 + return mChildHelper.hasNestedScrollingParent();
  145 + }
  146 +
  147 + @Override
  148 + public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int
  149 + dyUnconsumed, int[] offsetInWindow) {
  150 + return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed,
  151 + dyUnconsumed, offsetInWindow);
  152 + }
  153 +
  154 + @Override
  155 + public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
  156 + return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
  157 + }
  158 +
  159 + @Override
  160 + public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
  161 + return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
  162 + }
  163 +
  164 + @Override
  165 + public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
  166 + return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
  167 + }
  168 +}
0 \ No newline at end of file 169 \ No newline at end of file
mvpsdk/src/main/java/com/share/mvpsdk/widgets/PickerView.java 0 → 100644
@@ -0,0 +1,314 @@ @@ -0,0 +1,314 @@
  1 +package com.share.mvpsdk.widgets;
  2 +
  3 +import android.content.Context;
  4 +import android.graphics.Canvas;
  5 +import android.graphics.Paint;
  6 +import android.graphics.Paint.Align;
  7 +import android.graphics.Paint.FontMetricsInt;
  8 +import android.graphics.Paint.Style;
  9 +import android.os.Handler;
  10 +import android.os.Message;
  11 +import android.util.AttributeSet;
  12 +import android.view.MotionEvent;
  13 +import android.view.View;
  14 +
  15 +import java.util.ArrayList;
  16 +import java.util.List;
  17 +import java.util.Timer;
  18 +import java.util.TimerTask;
  19 +
  20 +/**
  21 + * Created by Horrarndoo on 2017/4/5.
  22 + * <p>
  23 + * 滚动选择器
  24 + */
  25 +public class PickerView extends View {
  26 +
  27 + public static final String TAG = "PickerView";
  28 + /**
  29 + * text之间间距和minTextSize之比
  30 + */
  31 + public static final float MARGIN_ALPHA = 2.8f;
  32 + /**
  33 + * 自动回滚到中间的速度
  34 + */
  35 + public static final float SPEED = 2;
  36 +
  37 + private List<String> mDataList;
  38 + /**
  39 + * 选中的位置,这个位置是mDataList的中心位置,一直不变
  40 + */
  41 + private int mCurrentSelected;
  42 + private Paint mPaint;
  43 +
  44 + private float mMaxTextSize = 80;
  45 + private float mMinTextSize = 50;
  46 + // private float mMinTextSize = 40;
  47 +
  48 + private float mMaxTextAlpha = 255;
  49 + private float mMinTextAlpha = 120;
  50 +
  51 + private int mColorText = 0xFF9500;// 森威尔的黄色
  52 +
  53 + private int mViewHeight;
  54 + private int mViewWidth;
  55 +
  56 + private float mLastDownY;
  57 + /**
  58 + * 滑动的距离
  59 + */
  60 + private float mMoveLen = 0;
  61 + private boolean isInit = false;
  62 + private onSelectListener mSelectListener;
  63 + private Timer timer;
  64 + private MyTimerTask mTask;
  65 +
  66 + Handler updateHandler = new Handler() {
  67 + @Override
  68 + public void handleMessage(Message msg) {
  69 + if (Math.abs(mMoveLen) < SPEED) {
  70 + mMoveLen = 0;
  71 + if (mTask != null) {
  72 + mTask.cancel();
  73 + mTask = null;
  74 + performSelect();
  75 + }
  76 + } else
  77 + // 这里mMoveLen / Math.abs(mMoveLen)是为了保有mMoveLen的正负号,以实现上滚或下滚
  78 + mMoveLen = mMoveLen - mMoveLen / Math.abs(mMoveLen) * SPEED;
  79 + invalidate();
  80 + }
  81 +
  82 + };
  83 +
  84 + public PickerView(Context context) {
  85 + super(context);
  86 + init();
  87 + }
  88 +
  89 + public PickerView(Context context, AttributeSet attrs) {
  90 + super(context, attrs);
  91 + init();
  92 + }
  93 +
  94 + public void setOnSelectListener(onSelectListener listener) {
  95 + mSelectListener = listener;
  96 + }
  97 +
  98 + private void performSelect() {
  99 + if (mSelectListener != null)
  100 + mSelectListener.onSelect(mDataList.get(mCurrentSelected));
  101 + }
  102 +
  103 + public void setData(List<String> datas) {
  104 + mDataList = datas;
  105 + mCurrentSelected = datas.size() / 2;
  106 + invalidate();
  107 + }
  108 +
  109 + /**
  110 + * 选择选中的item的index
  111 + *
  112 + * @param selected
  113 + */
  114 + public void setSelected(int selected) {
  115 + mCurrentSelected = selected;
  116 + int distance = mDataList.size() / 2 - mCurrentSelected;
  117 + if (distance < 0)
  118 + for (int i = 0; i < -distance; i++) {
  119 + moveHeadToTail();
  120 + mCurrentSelected--;
  121 + }
  122 + else if (distance > 0)
  123 + for (int i = 0; i < distance; i++) {
  124 + moveTailToHead();
  125 + mCurrentSelected++;
  126 + }
  127 + invalidate();
  128 + }
  129 +
  130 + /**
  131 + * 选择选中的内容
  132 + *
  133 + * @param mSelectItem
  134 + */
  135 + public void setSelected(String mSelectItem) {
  136 + for (int i = 0; i < mDataList.size(); i++)
  137 + if (mDataList.get(i).equals(mSelectItem)) {
  138 + setSelected(i);
  139 + break;
  140 + }
  141 + }
  142 +
  143 + private void moveHeadToTail() {
  144 + String head = mDataList.get(0);
  145 + mDataList.remove(0);
  146 + mDataList.add(head);
  147 + }
  148 +
  149 + private void moveTailToHead() {
  150 + String tail = mDataList.get(mDataList.size() - 1);
  151 + mDataList.remove(mDataList.size() - 1);
  152 + mDataList.add(0, tail);
  153 + }
  154 +
  155 + @Override
  156 + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  157 + super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  158 + mViewHeight = getMeasuredHeight();
  159 + mViewWidth = getMeasuredWidth();
  160 + // 按照View的高度计算字体大小
  161 + mMaxTextSize = mViewHeight / 4.0f;
  162 + mMinTextSize = mMaxTextSize / 2f;
  163 + isInit = true;
  164 + invalidate();
  165 + }
  166 +
  167 + private void init() {
  168 + timer = new Timer();
  169 + mDataList = new ArrayList<String>();
  170 + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  171 + mPaint.setStyle(Style.FILL);
  172 + mPaint.setTextAlign(Align.CENTER);
  173 + mPaint.setColor(mColorText);
  174 + }
  175 +
  176 + @Override
  177 + protected void onDraw(Canvas canvas) {
  178 + super.onDraw(canvas);
  179 + // 根据index绘制view
  180 + if (isInit)
  181 + drawData(canvas);
  182 + }
  183 +
  184 + private void drawData(Canvas canvas) {
  185 + // 先绘制选中的text再往上往下绘制其余的text
  186 + float scale = parabola(mViewHeight / 4.0f, mMoveLen);
  187 + float size = (mMaxTextSize - mMinTextSize) * scale + mMinTextSize;
  188 + mPaint.setTextSize(size);
  189 + mPaint.setAlpha((int) ((mMaxTextAlpha - mMinTextAlpha) * scale + mMinTextAlpha));
  190 + // text居中绘制,注意baseline的计算才能达到居中,y值是text中心坐标
  191 + float x = (float) (mViewWidth / 2.0);
  192 + float y = (float) (mViewHeight / 2.0 + mMoveLen);
  193 + FontMetricsInt fmi = mPaint.getFontMetricsInt();
  194 + float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0));
  195 + if (mDataList.size() > 0) {
  196 + canvas.drawText(mDataList.get(mCurrentSelected), x, baseline,
  197 + mPaint);
  198 + }
  199 + // 绘制上方data
  200 + for (int i = 1; (mCurrentSelected - i) >= 0; i++) {
  201 + drawOtherText(canvas, i, -1);
  202 + }
  203 + // 绘制下方data
  204 + for (int i = 1; (mCurrentSelected + i) < mDataList.size(); i++) {
  205 + drawOtherText(canvas, i, 1);
  206 + }
  207 + }
  208 +
  209 + /**
  210 + * @param canvas
  211 + * @param position 距离mCurrentSelected的差值
  212 + * @param type 1表示向下绘制,-1表示向上绘制
  213 + */
  214 + private void drawOtherText(Canvas canvas, int position, int type) {
  215 + float d = (float) (MARGIN_ALPHA * mMinTextSize * position + type
  216 + * mMoveLen);
  217 + float scale = parabola(mViewHeight / 4.0f, d);
  218 + float size = (mMaxTextSize - mMinTextSize) * scale + mMinTextSize;
  219 + mPaint.setTextSize(size);
  220 + mPaint.setAlpha((int) ((mMaxTextAlpha - mMinTextAlpha) * scale + mMinTextAlpha));
  221 + float y = (float) (mViewHeight / 2.0 + type * d);
  222 + FontMetricsInt fmi = mPaint.getFontMetricsInt();
  223 + float baseline = (float) (y - (fmi.bottom / 2.0 + fmi.top / 2.0));
  224 + canvas.drawText(mDataList.get(mCurrentSelected + type * position),
  225 + (float) (mViewWidth / 2.0), baseline, mPaint);
  226 + }
  227 +
  228 + /**
  229 + * 抛物线
  230 + *
  231 + * @param zero 零点坐标
  232 + * @param x 偏移量
  233 + * @return scale
  234 + */
  235 + private float parabola(float zero, float x) {
  236 + float f = (float) (1 - Math.pow(x / zero, 2));
  237 + return f < 0 ? 0 : f;
  238 + }
  239 +
  240 + @Override
  241 + public boolean onTouchEvent(MotionEvent event) {
  242 + switch (event.getActionMasked()) {
  243 + case MotionEvent.ACTION_DOWN:
  244 + doDown(event);
  245 + break;
  246 + case MotionEvent.ACTION_MOVE:
  247 + doMove(event);
  248 + break;
  249 + case MotionEvent.ACTION_UP:
  250 + doUp(event);
  251 + break;
  252 + }
  253 + return true;
  254 + }
  255 +
  256 + private void doDown(MotionEvent event) {
  257 + if (mTask != null) {
  258 + mTask.cancel();
  259 + mTask = null;
  260 + }
  261 + mLastDownY = event.getY();
  262 + }
  263 +
  264 + private void doMove(MotionEvent event) {
  265 +
  266 + mMoveLen += (event.getY() - mLastDownY);
  267 +
  268 + if (mMoveLen > MARGIN_ALPHA * mMinTextSize / 2) {
  269 + // 往下滑超过离开距离
  270 + moveTailToHead();
  271 + mMoveLen = mMoveLen - MARGIN_ALPHA * mMinTextSize;
  272 + } else if (mMoveLen < -MARGIN_ALPHA * mMinTextSize / 2) {
  273 + // 往上滑超过离开距离
  274 + moveHeadToTail();
  275 + mMoveLen = mMoveLen + MARGIN_ALPHA * mMinTextSize;
  276 + }
  277 +
  278 + mLastDownY = event.getY();
  279 + invalidate();
  280 + }
  281 +
  282 + private void doUp(MotionEvent event) {
  283 + // 抬起手后mCurrentSelected的位置由当前位置move到中间选中位置
  284 + if (Math.abs(mMoveLen) < 0.0001) {
  285 + mMoveLen = 0;
  286 + return;
  287 + }
  288 + if (mTask != null) {
  289 + mTask.cancel();
  290 + mTask = null;
  291 + }
  292 + mTask = new MyTimerTask(updateHandler);
  293 + timer.schedule(mTask, 0, 10);
  294 + }
  295 +
  296 + class MyTimerTask extends TimerTask {
  297 + Handler handler;
  298 +
  299 + public MyTimerTask(Handler handler) {
  300 + this.handler = handler;
  301 + }
  302 +
  303 + @Override
  304 + public void run() {
  305 + handler.sendMessage(handler.obtainMessage());
  306 + }
  307 +
  308 + }
  309 +
  310 + public interface onSelectListener {
  311 + void onSelect(String text);
  312 + }
  313 +}
  314 +
mvpsdk/src/main/java/com/share/mvpsdk/widgets/ProgressButton.java 0 → 100644
@@ -0,0 +1,79 @@ @@ -0,0 +1,79 @@
  1 +package com.share.mvpsdk.widgets;
  2 +
  3 +
  4 +import android.content.Context;
  5 +import android.graphics.Canvas;
  6 +import android.graphics.Color;
  7 +import android.graphics.Paint;
  8 +import android.graphics.Paint.Style;
  9 +import android.graphics.RectF;
  10 +import android.util.AttributeSet;
  11 +import android.widget.Button;
  12 +
  13 +import com.share.mvpsdk.R;
  14 +
  15 +
  16 +/**
  17 + * Created by Horrarndoo on 2017/4/5.
  18 + * <p>
  19 + * 带有进度变化的button
  20 + */
  21 +public class ProgressButton extends Button {
  22 + public static final int MAX_PROGRESS = 1000;
  23 + private boolean isAdding = false;
  24 + private int progress = 0;
  25 + private int progressStrokeWidth = 6;
  26 +
  27 + private Paint mPaint;
  28 + private RectF dst;
  29 +
  30 + private Context context;
  31 +
  32 + public ProgressButton(Context context, AttributeSet attrs) {
  33 + super(context, attrs);
  34 + dst = new RectF();
  35 + mPaint = new Paint();
  36 + mPaint.setAntiAlias(true);
  37 + mPaint.setStyle(Style.STROKE);
  38 + mPaint.setStrokeWidth(progressStrokeWidth);
  39 + this.context = context;
  40 + }
  41 +
  42 + @Override
  43 + protected void onDraw(Canvas canvas) {
  44 + super.onDraw(canvas);
  45 +
  46 + int width = this.getWidth();
  47 + int height = this.getHeight();
  48 +
  49 + if (width != height) {
  50 + int min = Math.min(width, height);
  51 + width = min;
  52 + height = min;
  53 + }
  54 +
  55 + mPaint.setColor(context.getResources().getColor(R.color.dark_grey));
  56 + canvas.drawColor(Color.TRANSPARENT);
  57 +
  58 + dst.left = progressStrokeWidth / 2; // 左上角x
  59 + dst.top = progressStrokeWidth / 2; // 左上角y
  60 + dst.right = width - progressStrokeWidth / 2; // 左下角x
  61 + dst.bottom = height - progressStrokeWidth / 2; // 右下角y
  62 +
  63 + canvas.drawArc(dst, -90, 360, false, mPaint);
  64 +
  65 + if (isAdding) {
  66 + mPaint.setColor(context.getResources().getColor(R.color.light_yellow));
  67 + canvas.drawArc(dst, -90, ((float) progress / MAX_PROGRESS) * 360, false, mPaint);
  68 + }
  69 + }
  70 +
  71 + /**
  72 + * 非UI线程调用
  73 + */
  74 + public void setProgressNotInUiThread(int progress, boolean isAdding) {
  75 + this.isAdding = isAdding;
  76 + this.progress = progress;
  77 + this.postInvalidate();
  78 + }
  79 +}
0 \ No newline at end of file 80 \ No newline at end of file
mvpsdk/src/main/java/com/share/mvpsdk/widgets/SlideSwitchView.java 0 → 100644
@@ -0,0 +1,259 @@ @@ -0,0 +1,259 @@
  1 +package com.share.mvpsdk.widgets;
  2 +
  3 +import android.content.Context;
  4 +import android.content.res.TypedArray;
  5 +import android.graphics.Bitmap;
  6 +import android.graphics.BitmapFactory;
  7 +import android.graphics.Canvas;
  8 +import android.graphics.Color;
  9 +import android.graphics.Matrix;
  10 +import android.graphics.Paint;
  11 +import android.util.AttributeSet;
  12 +import android.view.MotionEvent;
  13 +import android.view.View;
  14 +
  15 +import com.share.mvpsdk.R;
  16 +
  17 +
  18 +/**
  19 + * Created by Horrarndoo on 2017/6/1.
  20 + * <p>
  21 + * 自定义滑动开关
  22 + * <p>
  23 + * Android 的界面绘制流程
  24 + * 测量 摆放 绘制
  25 + * measure -> layout -> draw
  26 + * | | |
  27 + * onMeasure -> onLayout -> onDraw 重写这些方法, 实现自定义控件
  28 + * <p>
  29 + * onResume()之后执行
  30 + * <p>
  31 + * View
  32 + * onMeasure() (在这个方法里指定自己的宽高) -> onDraw() (绘制自己的内容)
  33 + * <p>
  34 + * ViewGroup
  35 + * onMeasure() (指定自己的宽高, 所有子View的宽高)-> onLayout() (摆放所有子View) -> onDraw() (绘制内容)
  36 + */
  37 +public class SlideSwitchView extends View {
  38 + private Bitmap slideButtonBitmap; // 滑块图片
  39 + private Paint mPaint; // 画笔
  40 + private float currentX; //当前滑动的x坐标
  41 + private int mBaseLineY; // text基准线
  42 + private String mTextContent; //text内容
  43 +
  44 + public SlideSwitchView(Context context) {
  45 + this(context, null);
  46 + }
  47 +
  48 + public SlideSwitchView(Context context, AttributeSet attrs) {
  49 + this(context, attrs, 0);
  50 + }
  51 +
  52 + public SlideSwitchView(Context context, AttributeSet attrs, int defStyle) {
  53 + super(context, attrs, defStyle);
  54 + initPaint();
  55 + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlideSwitchView);
  56 + setSlideButtonResource(ta.getResourceId(R.styleable.SlideSwitchView_slide_button, -1));
  57 + setText(ta.getString(R.styleable.SlideSwitchView_android_text));
  58 + setTextSize(ta.getDimension(R.styleable.SlideSwitchView_android_textSize, 30));
  59 + setTextColor(ta.getColor(R.styleable.SlideSwitchView_android_textColor, Color.BLACK));
  60 + ta.recycle();
  61 + }
  62 +
  63 + /**
  64 + * 初始化画笔
  65 + */
  66 + private void initPaint() {
  67 + mPaint = new Paint();
  68 + mPaint.setStyle(Paint.Style.FILL);
  69 + mPaint.setTextAlign(Paint.Align.LEFT);
  70 + mPaint.setAntiAlias(true);
  71 + }
  72 +
  73 + /**
  74 + * 初始化text居中基准线
  75 + */
  76 + private void initTextBaseLine() {
  77 + Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
  78 + float top = fontMetrics.top;//为基线到字体上边框的距离,即上图中的top
  79 + float bottom = fontMetrics.bottom;//为基线到字体下边框的距离,即上图中的bottom
  80 + mBaseLineY = (int) (getMeasuredHeight() / 2 - top / 2 - bottom / 2);//基线中间点的y轴计算公式
  81 + }
  82 +
  83 + @Override
  84 + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  85 + int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  86 + int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  87 + int width = MeasureSpec.getSize(widthMeasureSpec);
  88 + int height = MeasureSpec.getSize(heightMeasureSpec);
  89 +
  90 + if (widthMode == MeasureSpec.AT_MOST) {
  91 + int newWidth = (int) (slideButtonBitmap.getWidth() * 2 + getTextWidth());
  92 + if (width >= newWidth)
  93 + width = newWidth;
  94 + }
  95 +
  96 + if (heightMode == MeasureSpec.EXACTLY) {
  97 + if (height < slideButtonBitmap.getHeight()) {
  98 + // 获得图片的宽高
  99 + int widthSlide = slideButtonBitmap.getWidth();
  100 + int heightSlide = slideButtonBitmap.getHeight();
  101 + float scaleHeight = height * 1.0f / slideButtonBitmap.getHeight();
  102 + Matrix matrix = new Matrix();
  103 + matrix.postScale(scaleHeight, scaleHeight);
  104 + slideButtonBitmap = Bitmap.createBitmap(slideButtonBitmap, 0, 0, widthSlide,
  105 + heightSlide, matrix, true);
  106 + invalidate();
  107 + }
  108 + }
  109 +
  110 + if (slideButtonBitmap.getWidth() > (width - getTextWidth()) / 2) {
  111 + // 获得图片的宽高
  112 + int widthSlide = slideButtonBitmap.getWidth();
  113 + int heightSlide = slideButtonBitmap.getHeight();
  114 + float scaleWidth = (width - getTextWidth()) / 2 / slideButtonBitmap.getWidth();
  115 + Matrix matrix = new Matrix();
  116 + matrix.postScale(scaleWidth, scaleWidth);
  117 + slideButtonBitmap = Bitmap.createBitmap(slideButtonBitmap, 0, 0, widthSlide,
  118 + heightSlide, matrix, true);
  119 + invalidate();
  120 + }
  121 +
  122 + setMeasuredDimension(width, slideButtonBitmap.getHeight());
  123 + initTextBaseLine();
  124 + }
  125 +
  126 + // Canvas 画布, 画板. 在上边绘制的内容都会显示到界面上.
  127 + @Override
  128 + protected void onDraw(Canvas canvas) {
  129 + // 1. 绘制text
  130 + canvas.drawText(mTextContent, slideButtonBitmap.getWidth(), mBaseLineY, mPaint);
  131 +
  132 + // 2. 绘制滑块
  133 + if (isTouchMode) {
  134 + // 根据当前用户触摸到的位置画滑块
  135 + // 让滑块向左移动自身一半大小的位置
  136 + float newLeft = currentX - slideButtonBitmap.getWidth() / 2.0f;
  137 +
  138 + int maxLeft = getMeasuredWidth() - slideButtonBitmap.getWidth();
  139 +
  140 + // 限定滑块范围
  141 + if (newLeft < 0) {
  142 + newLeft = 0; // 左边范围
  143 + } else if (newLeft > maxLeft) {
  144 + newLeft = maxLeft; // 右边范围
  145 + }
  146 +
  147 + canvas.drawBitmap(slideButtonBitmap, newLeft, 0, mPaint);
  148 + } else {
  149 + //还原button位置
  150 + canvas.drawBitmap(slideButtonBitmap, 0, 0, mPaint);
  151 + }
  152 +
  153 + }
  154 +
  155 + boolean isTouchMode = false;
  156 + private OnSwitchStateUpdateListener onSwitchStateUpdateListener;
  157 +
  158 + // 重写触摸事件, 响应用户的触摸.
  159 + @Override
  160 + public boolean onTouchEvent(MotionEvent event) {
  161 +
  162 + switch (event.getAction()) {
  163 + case MotionEvent.ACTION_DOWN:
  164 + isTouchMode = true;
  165 + currentX = event.getX();
  166 + break;
  167 + case MotionEvent.ACTION_MOVE:
  168 + currentX = event.getX();
  169 + break;
  170 + case MotionEvent.ACTION_UP:
  171 + isTouchMode = false;
  172 + currentX = event.getX();
  173 +
  174 + float center = getMeasuredWidth() / 2.0f;
  175 +
  176 + // 根据当前按下的位置, 和控件中心的位置进行比较.
  177 + boolean isStateChanged = currentX > center;
  178 +
  179 + // 如果开关状态变化了, 通知界面
  180 + if (isStateChanged && onSwitchStateUpdateListener != null) {
  181 + onSwitchStateUpdateListener.onStateUpdate();
  182 + }
  183 + break;
  184 +
  185 + default:
  186 + break;
  187 + }
  188 +
  189 + // 重绘界面
  190 + invalidate(); // 会引发onDraw()被调用, 里边的变量会重新生效.界面会更新
  191 +
  192 + return true; // 消费了用户的触摸事件, 才可以收到其他的事件.
  193 + }
  194 +
  195 + /**
  196 + * 设置滑块图片资源
  197 + *
  198 + * @param slideButton 滑块图片资源
  199 + */
  200 + public void setSlideButtonResource(int slideButton) {
  201 + slideButtonBitmap = BitmapFactory.decodeResource(getResources(), slideButton);
  202 + }
  203 +
  204 + /**
  205 + * 设置text字号大小
  206 + *
  207 + * @param textSize text字号大小
  208 + */
  209 + public void setTextSize(float textSize) {
  210 + mPaint.setTextSize(textSize);
  211 + mPaint.setStrokeWidth(textSize / 15.f);
  212 + }
  213 +
  214 + /**
  215 + * 设置text内容
  216 + *
  217 + * @param text text内容
  218 + */
  219 + public void setText(String text) {
  220 + mTextContent = text;
  221 + }
  222 +
  223 + /**
  224 + * 设置text颜色
  225 + *
  226 + * @param color text颜色资源
  227 + */
  228 + public void setTextColor(int color) {
  229 + mPaint.setColor(color);
  230 + }
  231 +
  232 + /**
  233 + * 获取text文字宽度
  234 + *
  235 + * @return text文字宽度
  236 + */
  237 + private float getTextWidth() {
  238 + return mPaint.measureText(mTextContent);
  239 + }
  240 +
  241 + /**
  242 + * 获取text文字高度
  243 + *
  244 + * @return text文字高度
  245 + */
  246 + private float getTextHeight() {
  247 + return mPaint.getFontMetrics().bottom - mPaint.getFontMetrics().top;
  248 + }
  249 +
  250 + public interface OnSwitchStateUpdateListener {
  251 + // 状态回调
  252 + void onStateUpdate();
  253 + }
  254 +
  255 + public void setOnSwitchStateUpdateListener(
  256 + OnSwitchStateUpdateListener onSwitchStateUpdateListener) {
  257 + this.onSwitchStateUpdateListener = onSwitchStateUpdateListener;
  258 + }
  259 +}
0 \ No newline at end of file 260 \ No newline at end of file
mvpsdk/src/main/java/com/share/mvpsdk/widgets/WaitPorgressDialog.java 0 → 100644
@@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
  1 +package com.share.mvpsdk.widgets;
  2 +
  3 +import android.app.ProgressDialog;
  4 +import android.content.Context;
  5 +
  6 +/**
  7 + * Created by Horrarndoo on 2017/4/17.
  8 + * <p>
  9 + * 等待提示dialog
  10 + */
  11 +
  12 +public class WaitPorgressDialog extends ProgressDialog {
  13 +
  14 + public WaitPorgressDialog(Context context) {
  15 + this(context, 0);
  16 + }
  17 +
  18 + public WaitPorgressDialog(Context context, int theme) {
  19 + super(context, theme);
  20 + setCanceledOnTouchOutside(false);
  21 + }
  22 +}
mvpsdk/src/main/java/com/share/mvpsdk/widgets/headclip/ClipView.java 0 → 100644
@@ -0,0 +1,157 @@ @@ -0,0 +1,157 @@
  1 +package com.share.mvpsdk.widgets.headclip;
  2 +
  3 +/**
  4 + * Created by Horrarndoo on 2017/9/25.
  5 + * <p>
  6 + */
  7 +
  8 +import android.content.Context;
  9 +import android.graphics.Canvas;
  10 +import android.graphics.Color;
  11 +import android.graphics.Paint;
  12 +import android.graphics.PorterDuff;
  13 +import android.graphics.PorterDuffXfermode;
  14 +import android.graphics.Rect;
  15 +import android.graphics.Xfermode;
  16 +import android.util.AttributeSet;
  17 +import android.util.DisplayMetrics;
  18 +import android.view.View;
  19 +import android.view.WindowManager;
  20 +
  21 +/**
  22 + * 头像上传裁剪框
  23 + */
  24 +public class ClipView extends View {
  25 + private Paint paint = new Paint();
  26 + //画裁剪区域边框的画笔
  27 + private Paint borderPaint = new Paint();
  28 + //裁剪框水平方向间距
  29 + private float mHorizontalPadding;
  30 + //裁剪框边框宽度
  31 + private int clipBorderWidth;
  32 + //裁剪圆框的半径
  33 + private int clipRadiusWidth;
  34 + //裁剪框矩形宽度
  35 + private int clipWidth;
  36 + //裁剪框类别,(圆形、矩形),默认为圆形
  37 + private ClipType clipType = ClipType.CIRCLE;
  38 + private Xfermode xfermode;
  39 +
  40 + public ClipView(Context context) {
  41 + this(context, null);
  42 + }
  43 +
  44 + public ClipView(Context context, AttributeSet attrs) {
  45 + this(context, attrs, 0);
  46 + }
  47 +
  48 + public ClipView(Context context, AttributeSet attrs, int defStyle) {
  49 + super(context, attrs, defStyle);
  50 + //去锯齿
  51 + paint.setAntiAlias(true);
  52 + borderPaint.setStyle(Paint.Style.STROKE);
  53 + borderPaint.setColor(Color.WHITE);
  54 + borderPaint.setStrokeWidth(clipBorderWidth);
  55 + borderPaint.setAntiAlias(true);
  56 + xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
  57 + }
  58 +
  59 + @Override
  60 + protected void onDraw(Canvas canvas) {
  61 + super.onDraw(canvas);
  62 + int LAYER_FLAGS = Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG
  63 + | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG
  64 + | Canvas.CLIP_TO_LAYER_SAVE_FLAG;
  65 + //通过Xfermode的DST_OUT来产生中间的透明裁剪区域,一定要另起一个Layer(层)
  66 + canvas.saveLayer(0, 0, this.getWidth(), this.getHeight(), null, LAYER_FLAGS);
  67 + //设置背景
  68 + canvas.drawColor(Color.parseColor("#a8000000"));
  69 + paint.setXfermode(xfermode);
  70 + //绘制圆形裁剪框
  71 + if (clipType == ClipType.CIRCLE) {
  72 + //中间的透明的圆
  73 + canvas.drawCircle(this.getWidth() / 2, this.getHeight() / 2, clipRadiusWidth, paint);
  74 + //白色的圆边框
  75 + canvas.drawCircle(this.getWidth() / 2, this.getHeight() / 2, clipRadiusWidth, borderPaint);
  76 + } else if (clipType == ClipType.RECTANGLE) { //绘制矩形裁剪框
  77 + //绘制中间的矩形
  78 + canvas.drawRect(mHorizontalPadding, this.getHeight() / 2 - clipWidth / 2,
  79 + this.getWidth() - mHorizontalPadding, this.getHeight() / 2 + clipWidth / 2, paint);
  80 + //绘制白色的矩形边框
  81 + canvas.drawRect(mHorizontalPadding, this.getHeight() / 2 - clipWidth / 2,
  82 + this.getWidth() - mHorizontalPadding, this.getHeight() / 2 + clipWidth / 2, borderPaint);
  83 + }
  84 + //出栈,恢复到之前的图层,意味着新建的图层会被删除,新建图层上的内容会被绘制到canvas (or the previous layer)
  85 + canvas.restore();
  86 + }
  87 +
  88 + /**
  89 + * 获取裁剪区域的Rect
  90 + *
  91 + * @return
  92 + */
  93 + public Rect getClipRect() {
  94 + Rect rect = new Rect();
  95 + //宽度的一半 - 圆的半径
  96 + rect.left = (this.getWidth() / 2 - clipRadiusWidth);
  97 + //宽度的一半 + 圆的半径
  98 + rect.right = (this.getWidth() / 2 + clipRadiusWidth);
  99 + //高度的一半 - 圆的半径
  100 + rect.top = (this.getHeight() / 2 - clipRadiusWidth);
  101 + //高度的一半 + 圆的半径
  102 + rect.bottom = (this.getHeight() / 2 + clipRadiusWidth);
  103 + return rect;
  104 + }
  105 +
  106 + /**
  107 + * 设置裁剪框边框宽度
  108 + *
  109 + * @param clipBorderWidth
  110 + */
  111 + public void setClipBorderWidth(int clipBorderWidth) {
  112 + this.clipBorderWidth = clipBorderWidth;
  113 + borderPaint.setStrokeWidth(clipBorderWidth);
  114 + invalidate();
  115 + }
  116 +
  117 + /**
  118 + * 设置裁剪框水平间距
  119 + *
  120 + * @param mHorizontalPadding
  121 + */
  122 + public void setmHorizontalPadding(float mHorizontalPadding) {
  123 + this.mHorizontalPadding = mHorizontalPadding;
  124 + this.clipRadiusWidth = (int) (getScreenWidth(getContext()) - 2 * mHorizontalPadding) / 2;
  125 + this.clipWidth = clipRadiusWidth * 2;
  126 + }
  127 +
  128 + /**
  129 + * 获得屏幕高度
  130 + *
  131 + * @param context
  132 + * @return
  133 + */
  134 + public static int getScreenWidth(Context context) {
  135 + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
  136 + DisplayMetrics outMetrics = new DisplayMetrics();
  137 + wm.getDefaultDisplay().getMetrics(outMetrics);
  138 + return outMetrics.widthPixels;
  139 + }
  140 +
  141 +
  142 + /**
  143 + * 设置裁剪框类别
  144 + *
  145 + * @param clipType
  146 + */
  147 + public void setClipType(ClipType clipType) {
  148 + this.clipType = clipType;
  149 + }
  150 +
  151 + /**
  152 + * 裁剪框类别,圆形、矩形
  153 + */
  154 + public enum ClipType {
  155 + CIRCLE, RECTANGLE
  156 + }
  157 +}
0 \ No newline at end of file 158 \ No newline at end of file
mvpsdk/src/main/java/com/share/mvpsdk/widgets/headclip/ClipViewLayout.java 0 → 100644
@@ -0,0 +1,485 @@ @@ -0,0 +1,485 @@
  1 +package com.share.mvpsdk.widgets.headclip;
  2 +
  3 +/**
  4 + * Created by Horrarndoo on 2017/9/25.
  5 + * <p>
  6 + */
  7 +
  8 +import android.content.Context;
  9 +import android.content.res.TypedArray;
  10 +import android.graphics.Bitmap;
  11 +import android.graphics.BitmapFactory;
  12 +import android.graphics.Matrix;
  13 +import android.graphics.PointF;
  14 +import android.graphics.Rect;
  15 +import android.graphics.RectF;
  16 +import android.graphics.drawable.Drawable;
  17 +import android.media.ExifInterface;
  18 +import android.net.Uri;
  19 +import android.text.TextUtils;
  20 +import android.util.AttributeSet;
  21 +import android.util.TypedValue;
  22 +import android.view.MotionEvent;
  23 +import android.view.ViewTreeObserver;
  24 +import android.widget.ImageView;
  25 +import android.widget.RelativeLayout;
  26 +
  27 +
  28 +import com.share.mvpsdk.R;
  29 +import com.share.mvpsdk.utils.LogUtils;
  30 +
  31 +import java.io.IOException;
  32 +
  33 +import static com.share.mvpsdk.utils.FileUtils.getRealFilePathFromUri;
  34 +
  35 +
  36 +/**
  37 + * 头像上传原图裁剪容器
  38 + */
  39 +public class ClipViewLayout extends RelativeLayout {
  40 + //裁剪原图
  41 + private ImageView imageView;
  42 + //裁剪框
  43 + private ClipView clipView;
  44 + //裁剪框水平方向间距,xml布局文件中指定
  45 + private float mHorizontalPadding;
  46 + //裁剪框垂直方向间距,计算得出
  47 + private float mVerticalPadding;
  48 + //图片缩放、移动操作矩阵
  49 + private Matrix matrix = new Matrix();
  50 + //图片原来已经缩放、移动过的操作矩阵
  51 + private Matrix savedMatrix = new Matrix();
  52 + //动作标志:无
  53 + private static final int NONE = 0;
  54 + //动作标志:拖动
  55 + private static final int DRAG = 1;
  56 + //动作标志:缩放
  57 + private static final int ZOOM = 2;
  58 + //初始化动作标志
  59 + private int mode = NONE;
  60 + //记录起始坐标
  61 + private PointF start = new PointF();
  62 + //记录缩放时两指中间点坐标
  63 + private PointF mid = new PointF();
  64 + private float oldDist = 1f;
  65 + //用于存放矩阵的9个值
  66 + private final float[] matrixValues = new float[9];
  67 + //最小缩放比例
  68 + private float minScale;
  69 + //最大缩放比例
  70 + private float maxScale = 4;
  71 +
  72 +
  73 + public ClipViewLayout(Context context) {
  74 + this(context, null);
  75 + }
  76 +
  77 + public ClipViewLayout(Context context, AttributeSet attrs) {
  78 + this(context, attrs, 0);
  79 + }
  80 +
  81 + public ClipViewLayout(Context context, AttributeSet attrs, int defStyleAttr) {
  82 + super(context, attrs, defStyleAttr);
  83 + init(context, attrs);
  84 + }
  85 +
  86 + //初始化控件自定义的属性
  87 + public void init(Context context, AttributeSet attrs) {
  88 + TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ClipViewLayout);
  89 +
  90 + //获取剪切框距离左右的边距, 默认为50dp
  91 + mHorizontalPadding = array.getDimensionPixelSize(R.styleable.ClipViewLayout_mHorizontalPadding,
  92 + (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, getResources().getDisplayMetrics()));
  93 + //获取裁剪框边框宽度,默认1dp
  94 + int clipBorderWidth = array.getDimensionPixelSize(R.styleable.ClipViewLayout_clipBorderWidth,
  95 + (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics()));
  96 + //裁剪框类型(圆或者矩形)
  97 + int clipType = array.getInt(R.styleable.ClipViewLayout_clipType, 1);
  98 +
  99 + //回收
  100 + array.recycle();
  101 + clipView = new ClipView(context);
  102 + //设置裁剪框类型
  103 + clipView.setClipType(clipType == 1 ? ClipView.ClipType.CIRCLE : ClipView.ClipType.RECTANGLE);
  104 + //设置剪切框边框
  105 + clipView.setClipBorderWidth(clipBorderWidth);
  106 + //设置剪切框水平间距
  107 + clipView.setmHorizontalPadding(mHorizontalPadding);
  108 + imageView = new ImageView(context);
  109 + //相对布局布局参数
  110 + android.view.ViewGroup.LayoutParams lp = new LayoutParams(
  111 + android.view.ViewGroup.LayoutParams.MATCH_PARENT,
  112 + android.view.ViewGroup.LayoutParams.MATCH_PARENT);
  113 + this.addView(imageView, lp);
  114 + this.addView(clipView, lp);
  115 + }
  116 +
  117 +
  118 + /**
  119 + * 初始化图片
  120 + */
  121 + public void setImageSrc(final Uri uri) {
  122 + //需要等到imageView绘制完毕再初始化原图
  123 + ViewTreeObserver observer = imageView.getViewTreeObserver();
  124 + observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
  125 + public void onGlobalLayout() {
  126 + initSrcPic(uri);
  127 + imageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
  128 + }
  129 + });
  130 + }
  131 +
  132 + /**
  133 + * 初始化图片
  134 + * step 1: decode 出 720*1280 左右的照片 因为原图可能比较大 直接加载出来会OOM
  135 + * step 2: 将图片缩放 移动到imageView 中间
  136 + */
  137 + public void initSrcPic(Uri uri) {
  138 + if (uri == null) {
  139 + return;
  140 + }
  141 + LogUtils.d("**********clip_view uri******* " + uri);
  142 + String path = getRealFilePathFromUri(getContext(), uri);
  143 + LogUtils.d("**********clip_view path******* " + path);
  144 + if (TextUtils.isEmpty(path)) {
  145 + return;
  146 + }
  147 +
  148 + //这里decode出720*1280 左右的照片,防止OOM
  149 + Bitmap bitmap = decodeSampledBitmap(path, 720, 1280);
  150 + if (bitmap == null) {
  151 + return;
  152 + }
  153 +
  154 + //竖屏拍照的照片,直接使用的话,会旋转90度,下面代码把角度旋转过来
  155 + int rotation = getExifOrientation(path); //查询旋转角度
  156 + Matrix m = new Matrix();
  157 + m.setRotate(rotation);
  158 + bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true);
  159 +
  160 + //图片的缩放比
  161 + float scale;
  162 + if (bitmap.getWidth() >= bitmap.getHeight()) {//宽图
  163 + scale = (float) imageView.getWidth() / bitmap.getWidth();
  164 + //如果高缩放后小于裁剪区域 则将裁剪区域与高的缩放比作为最终的缩放比
  165 + Rect rect = clipView.getClipRect();
  166 + //高的最小缩放比
  167 + minScale = rect.height() / (float) bitmap.getHeight();
  168 + if (scale < minScale) {
  169 + scale = minScale;
  170 + }
  171 + } else {//高图
  172 + //高的缩放比
  173 + scale = (float) imageView.getHeight() / bitmap.getHeight();
  174 + //如果宽缩放后小于裁剪区域 则将裁剪区域与宽的缩放比作为最终的缩放比
  175 + Rect rect = clipView.getClipRect();
  176 + //宽的最小缩放比
  177 + minScale = rect.width() / (float) bitmap.getWidth();
  178 + if (scale < minScale) {
  179 + scale = minScale;
  180 + }
  181 + }
  182 + // 缩放
  183 + matrix.postScale(scale, scale);
  184 + // 平移,将缩放后的图片平移到imageview的中心
  185 + //imageView的中心x
  186 + int midX = imageView.getWidth() / 2;
  187 + //imageView的中心y
  188 + int midY = imageView.getHeight() / 2;
  189 + //bitmap的中心x
  190 + int imageMidX = (int) (bitmap.getWidth() * scale / 2);
  191 + //bitmap的中心y
  192 + int imageMidY = (int) (bitmap.getHeight() * scale / 2);
  193 + matrix.postTranslate(midX - imageMidX, midY - imageMidY);
  194 + imageView.setScaleType(ImageView.ScaleType.MATRIX);
  195 + imageView.setImageMatrix(matrix);
  196 + imageView.setImageBitmap(bitmap);
  197 + }
  198 +
  199 + /**
  200 + * 查询图片旋转角度
  201 + */
  202 + public static int getExifOrientation(String filepath) {// YOUR MEDIA PATH AS STRING
  203 + int degree = 0;
  204 + ExifInterface exif = null;
  205 + try {
  206 + exif = new ExifInterface(filepath);
  207 + } catch (IOException ex) {
  208 + ex.printStackTrace();
  209 + }
  210 + if (exif != null) {
  211 + int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
  212 + if (orientation != -1) {
  213 + switch (orientation) {
  214 + case ExifInterface.ORIENTATION_ROTATE_90:
  215 + degree = 90;
  216 + break;
  217 + case ExifInterface.ORIENTATION_ROTATE_180:
  218 + degree = 180;
  219 + break;
  220 + case ExifInterface.ORIENTATION_ROTATE_270:
  221 + degree = 270;
  222 + break;
  223 + }
  224 +
  225 + }
  226 + }
  227 + return degree;
  228 + }
  229 +
  230 +
  231 + @Override
  232 + public boolean onTouchEvent(MotionEvent event) {
  233 + switch (event.getAction() & MotionEvent.ACTION_MASK) {
  234 + case MotionEvent.ACTION_DOWN:
  235 + savedMatrix.set(matrix);
  236 + //设置开始点位置
  237 + start.set(event.getX(), event.getY());
  238 + mode = DRAG;
  239 + break;
  240 + case MotionEvent.ACTION_POINTER_DOWN:
  241 + //开始放下时候两手指间的距离
  242 + oldDist = spacing(event);
  243 + if (oldDist > 10f) {
  244 + savedMatrix.set(matrix);
  245 + midPoint(mid, event);
  246 + mode = ZOOM;
  247 + }
  248 + break;
  249 + case MotionEvent.ACTION_UP:
  250 + break;
  251 + case MotionEvent.ACTION_POINTER_UP:
  252 + mode = NONE;
  253 + break;
  254 + case MotionEvent.ACTION_MOVE:
  255 + if (mode == DRAG) { //拖动
  256 + matrix.set(savedMatrix);
  257 + float dx = event.getX() - start.x;
  258 + float dy = event.getY() - start.y;
  259 + mVerticalPadding = clipView.getClipRect().top;
  260 + matrix.postTranslate(dx, dy);
  261 + //检查边界
  262 + checkBorder();
  263 + } else if (mode == ZOOM) { //缩放
  264 + //缩放后两手指间的距离
  265 + float newDist = spacing(event);
  266 + if (newDist > 10f) {
  267 + //手势缩放比例
  268 + float scale = newDist / oldDist;
  269 + if (scale < 1) { //缩小
  270 + if (getScale() > minScale) {
  271 + matrix.set(savedMatrix);
  272 + mVerticalPadding = clipView.getClipRect().top;
  273 + matrix.postScale(scale, scale, mid.x, mid.y);
  274 + //缩放到最小范围下面去了,则返回到最小范围大小
  275 + while (getScale() < minScale) {
  276 + //返回到最小范围的放大比例
  277 + scale = 1 + 0.01F;
  278 + matrix.postScale(scale, scale, mid.x, mid.y);
  279 + }
  280 + }
  281 + //边界检查
  282 + checkBorder();
  283 + } else { //放大
  284 + if (getScale() <= maxScale) {
  285 + matrix.set(savedMatrix);
  286 + mVerticalPadding = clipView.getClipRect().top;
  287 + matrix.postScale(scale, scale, mid.x, mid.y);
  288 + }
  289 + }
  290 + }
  291 + }
  292 + imageView.setImageMatrix(matrix);
  293 + break;
  294 + }
  295 + return true;
  296 + }
  297 +
  298 + /**
  299 + * 根据当前图片的Matrix获得图片的范围
  300 + */
  301 + private RectF getMatrixRectF(Matrix matrix) {
  302 + RectF rect = new RectF();
  303 + Drawable d = imageView.getDrawable();
  304 + if (null != d) {
  305 + rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
  306 + matrix.mapRect(rect);
  307 + }
  308 + return rect;
  309 + }
  310 +
  311 + /**
  312 + * 边界检测
  313 + */
  314 + private void checkBorder() {
  315 + RectF rect = getMatrixRectF(matrix);
  316 + float deltaX = 0;
  317 + float deltaY = 0;
  318 + int width = imageView.getWidth();
  319 + int height = imageView.getHeight();
  320 + // 如果宽或高大于屏幕,则控制范围 ; 这里的0.001是因为精度丢失会产生问题,但是误差一般很小,所以我们直接加了一个0.01
  321 + if (rect.width() >= width - 2 * mHorizontalPadding) {
  322 + if (rect.left > mHorizontalPadding) {
  323 + deltaX = -rect.left + mHorizontalPadding;
  324 + }
  325 + if (rect.right < width - mHorizontalPadding) {
  326 + deltaX = width - mHorizontalPadding - rect.right;
  327 + }
  328 + }
  329 + if (rect.height() >= height - 2 * mVerticalPadding) {
  330 + if (rect.top > mVerticalPadding) {
  331 + deltaY = -rect.top + mVerticalPadding;
  332 + }
  333 + if (rect.bottom < height - mVerticalPadding) {
  334 + deltaY = height - mVerticalPadding - rect.bottom;
  335 + }
  336 + }
  337 + matrix.postTranslate(deltaX, deltaY);
  338 + }
  339 +
  340 + /**
  341 + * 获得当前的缩放比例
  342 + */
  343 + public final float getScale() {
  344 + matrix.getValues(matrixValues);
  345 + return matrixValues[Matrix.MSCALE_X];
  346 + }
  347 +
  348 +
  349 + /**
  350 + * 多点触控时,计算最先放下的两指距离
  351 + */
  352 + private float spacing(MotionEvent event) {
  353 + float x = event.getX(0) - event.getX(1);
  354 + float y = event.getY(0) - event.getY(1);
  355 + return (float) Math.sqrt(x * x + y * y);
  356 + }
  357 +
  358 + /**
  359 + * 多点触控时,计算最先放下的两指中心坐标
  360 + */
  361 + private void midPoint(PointF point, MotionEvent event) {
  362 + float x = event.getX(0) + event.getX(1);
  363 + float y = event.getY(0) + event.getY(1);
  364 + point.set(x / 2, y / 2);
  365 + }
  366 +
  367 +
  368 + /**
  369 + * 获取剪切图
  370 + */
  371 + public Bitmap clip() {
  372 + imageView.setDrawingCacheEnabled(true);
  373 + imageView.buildDrawingCache();
  374 + Rect rect = clipView.getClipRect();
  375 + Bitmap cropBitmap = null;
  376 + Bitmap zoomedCropBitmap = null;
  377 + try {
  378 + cropBitmap = Bitmap.createBitmap(imageView.getDrawingCache(), rect.left, rect.top, rect.width(), rect.height());
  379 + zoomedCropBitmap = zoomBitmap(cropBitmap, 200, 200);
  380 + } catch (Exception e) {
  381 + e.printStackTrace();
  382 + }
  383 + if (cropBitmap != null) {
  384 + cropBitmap.recycle();
  385 + }
  386 + // 释放资源
  387 + imageView.destroyDrawingCache();
  388 + return zoomedCropBitmap;
  389 + }
  390 +
  391 +
  392 + /**
  393 + * 图片等比例压缩
  394 + *
  395 + * @param filePath
  396 + * @param reqWidth 期望的宽
  397 + * @param reqHeight 期望的高
  398 + * @return
  399 + */
  400 + public static Bitmap decodeSampledBitmap(String filePath, int reqWidth,
  401 + int reqHeight) {
  402 +
  403 + // First decode with inJustDecodeBounds=true to check dimensions
  404 + final BitmapFactory.Options options = new BitmapFactory.Options();
  405 + options.inJustDecodeBounds = true;
  406 + options.inPreferredConfig = Bitmap.Config.RGB_565;
  407 + //bitmap is null
  408 + Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);
  409 +
  410 + // Calculate inSampleSize
  411 + options.inSampleSize = calculateInSampleSize(options, reqWidth,
  412 + reqHeight);
  413 +
  414 + // Decode bitmap with inSampleSize set
  415 + options.inJustDecodeBounds = false;
  416 + return BitmapFactory.decodeFile(filePath, options);
  417 + }
  418 +
  419 + /**
  420 + * 计算InSampleSize
  421 + * 宽的压缩比和高的压缩比的较小值 取接近的2的次幂的值
  422 + * 比如宽的压缩比是3 高的压缩比是5 取较小值3 而InSampleSize必须是2的次幂,取接近的2的次幂4
  423 + *
  424 + * @param options
  425 + * @param reqWidth
  426 + * @param reqHeight
  427 + * @return
  428 + */
  429 + public static int calculateInSampleSize(BitmapFactory.Options options,
  430 + int reqWidth, int reqHeight) {
  431 + // Raw height and width of image
  432 + final int height = options.outHeight;
  433 + final int width = options.outWidth;
  434 + int inSampleSize = 1;
  435 +
  436 + if (height > reqHeight || width > reqWidth) {
  437 +
  438 + // Calculate ratios of height and width to requested height and
  439 + // width
  440 + final int heightRatio = Math.round((float) height
  441 + / (float) reqHeight);
  442 + final int widthRatio = Math.round((float) width / (float) reqWidth);
  443 +
  444 + // Choose the smallest ratio as inSampleSize value, this will
  445 + // guarantee
  446 + // a final image with both dimensions larger than or equal to the
  447 + // requested height and width.
  448 + int ratio = heightRatio < widthRatio ? heightRatio : widthRatio;
  449 + // inSampleSize只能是2的次幂 将ratio就近取2的次幂的值
  450 + if (ratio < 3)
  451 + inSampleSize = ratio;
  452 + else if (ratio < 6.5)
  453 + inSampleSize = 4;
  454 + else if (ratio < 8)
  455 + inSampleSize = 8;
  456 + else
  457 + inSampleSize = ratio;
  458 + }
  459 +
  460 + return inSampleSize;
  461 + }
  462 +
  463 + /**
  464 + * 图片缩放到指定宽高
  465 + * <p/>
  466 + * 非等比例压缩,图片会被拉伸
  467 + *
  468 + * @param bitmap 源位图对象
  469 + * @param w 要缩放的宽度
  470 + * @param h 要缩放的高度
  471 + * @return 新Bitmap对象
  472 + */
  473 + public static Bitmap zoomBitmap(Bitmap bitmap, int w, int h) {
  474 + int width = bitmap.getWidth();
  475 + int height = bitmap.getHeight();
  476 + Matrix matrix = new Matrix();
  477 + float scaleWidth = ((float) w / width);
  478 + float scaleHeight = ((float) h / height);
  479 + matrix.postScale(scaleWidth, scaleHeight);
  480 + Bitmap newBmp = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);
  481 + return newBmp;
  482 + }
  483 +
  484 +
  485 +}
0 \ No newline at end of file 486 \ No newline at end of file
mvpsdk/src/main/res/anim/activity_finish_trans_in.xml 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +<set xmlns:android="http://schemas.android.com/apk/res/android"
  2 + android:zAdjustment="normal">
  3 + <alpha
  4 + android:duration="250"
  5 + android:fillAfter="true"
  6 + android:fillBefore="true"
  7 + android:fillEnabled="true"
  8 + android:fromAlpha="0.7"
  9 + android:interpolator="@android:anim/accelerate_interpolator"
  10 + android:toAlpha="1.0"/>
  11 +</set>
0 \ No newline at end of file 12 \ No newline at end of file
mvpsdk/src/main/res/anim/activity_finish_trans_out.xml 0 → 100644
@@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
  1 +<set xmlns:android="http://schemas.android.com/apk/res/android"
  2 + android:shareInterpolator="false"
  3 + android:zAdjustment="top">
  4 + <alpha
  5 + android:duration="150"
  6 + android:fillAfter="true"
  7 + android:fillBefore="false"
  8 + android:fillEnabled="true"
  9 + android:fromAlpha="1.0"
  10 + android:interpolator="@android:anim/linear_interpolator"
  11 + android:startOffset="100"
  12 + android:toAlpha="0.0"/>
  13 + <translate
  14 + android:duration="250"
  15 + android:fillAfter="true"
  16 + android:fillBefore="true"
  17 + android:fillEnabled="true"
  18 + android:fromYDelta="0%"
  19 + android:interpolator="@android:anim/accelerate_interpolator"
  20 + android:toYDelta="12%"/>
  21 +</set>
0 \ No newline at end of file 22 \ No newline at end of file
mvpsdk/src/main/res/anim/activity_finish_zoom_in.xml 0 → 100644
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set xmlns:Android="http://schemas.android.com/apk/res/android"
  3 + Android:interpolator="@android:anim/decelerate_interpolator">
  4 + <scale
  5 + Android:duration="300"
  6 + Android:fromXScale="2.0"
  7 + Android:fromYScale="2.0"
  8 + Android:pivotX="50%p"
  9 + Android:pivotY="50%p"
  10 + Android:toXScale="1.0"
  11 + Android:toYScale="1.0" />
  12 +</set>
0 \ No newline at end of file 13 \ No newline at end of file
mvpsdk/src/main/res/anim/activity_finish_zoom_out.xml 0 → 100644
@@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set xmlns:Android="http://schemas.android.com/apk/res/android"
  3 + Android:interpolator="@android:anim/decelerate_interpolator"
  4 + Android:zAdjustment="top">
  5 + <scale
  6 + Android:duration="300"
  7 + Android:fromXScale="1.0"
  8 + Android:fromYScale="1.0"
  9 + Android:pivotX="50%p"
  10 + Android:pivotY="50%p"
  11 + Android:toXScale="0.5"
  12 + Android:toYScale="0.5"/>
  13 +
  14 + <alpha
  15 + Android:duration="300"
  16 + Android:fromAlpha="1.0"
  17 + Android:toAlpha="0"/>
  18 +</set>
0 \ No newline at end of file 19 \ No newline at end of file
mvpsdk/src/main/res/anim/activity_start_trans_in.xml 0 → 100644
@@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
  1 +<set xmlns:android="http://schemas.android.com/apk/res/android"
  2 + android:shareInterpolator="false"
  3 + android:zAdjustment="top">
  4 + <alpha
  5 + android:duration="200"
  6 + android:fillAfter="true"
  7 + android:fillBefore="false"
  8 + android:fillEnabled="true"
  9 + android:fromAlpha="0.0"
  10 + android:interpolator="@android:anim/decelerate_interpolator"
  11 + android:toAlpha="1.0"/>
  12 +
  13 + <translate
  14 + android:duration="300"
  15 + android:fillAfter="true"
  16 + android:fillBefore="true"
  17 + android:fillEnabled="true"
  18 + android:fromYDelta="12%"
  19 + android:interpolator="@android:anim/decelerate_interpolator"
  20 + android:toYDelta="0"/>
  21 +</set>
0 \ No newline at end of file 22 \ No newline at end of file
mvpsdk/src/main/res/anim/activity_start_trans_out.xml 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +<set xmlns:android="http://schemas.android.com/apk/res/android"
  2 + android:zAdjustment="normal">
  3 + <alpha
  4 + android:duration="300"
  5 + android:fillAfter="true"
  6 + android:fillBefore="false"
  7 + android:fillEnabled="true"
  8 + android:fromAlpha="1.0"
  9 + android:interpolator="@android:anim/decelerate_interpolator"
  10 + android:toAlpha="0.9"/>
  11 +</set>
0 \ No newline at end of file 12 \ No newline at end of file
mvpsdk/src/main/res/anim/activity_start_zoom_in.xml 0 → 100644
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set xmlns:Android="http://schemas.android.com/apk/res/android"
  3 + Android:interpolator="@android:anim/decelerate_interpolator">
  4 + <scale
  5 + Android:duration="300"
  6 + Android:fromXScale="0.8"
  7 + Android:fromYScale="0.8"
  8 + Android:pivotX="50%p"
  9 + Android:pivotY="50%p"
  10 + Android:toXScale="1.0"
  11 + Android:toYScale="1.0"/>
  12 +</set>
0 \ No newline at end of file 13 \ No newline at end of file
mvpsdk/src/main/res/anim/activity_start_zoom_out.xml 0 → 100644
@@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<set xmlns:Android="http://schemas.android.com/apk/res/android"
  3 + Android:interpolator="@android:anim/decelerate_interpolator"
  4 + Android:zAdjustment="top">
  5 + <!--<scale-->
  6 + <!--Android:duration="300"-->
  7 + <!--Android:fromXScale="1.0"-->
  8 + <!--Android:fromYScale="1.0"-->
  9 + <!--Android:pivotX="50%p"-->
  10 + <!--Android:pivotY="50%p"-->
  11 + <!--Android:toXScale="2.0"-->
  12 + <!--Android:toYScale="2.0"/>-->
  13 + <alpha
  14 + Android:duration="300"
  15 + Android:fromAlpha="1.0"
  16 + Android:toAlpha="0"/>
  17 +</set>
0 \ No newline at end of file 18 \ No newline at end of file
mvpsdk/src/main/res/drawable/ic_vector_empty.xml 0 → 100644
@@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
  1 +<vector xmlns:android="http://schemas.android.com/apk/res/android"
  2 + android:width="344dp"
  3 + android:height="200dp"
  4 + android:viewportWidth="1762.0"
  5 + android:viewportHeight="1024.0">
  6 + <path
  7 + android:pathData="M1592.9,920.6c0,57.5 -46.7,103.4 -104.3,103.4H306.2c-57.6,0 -106.2,-45.9 -106.2,-103.4V244c0,-57.5 48.5,-104 106.2,-104H1488.6c57.6,0 104.3,46.6 104.3,104v676.7z"
  8 + android:fillColor="#F4F4F4"/>
  9 + <path
  10 + android:pathData="M1472.1,585.1v-470.2c0,-57.5 -48.7,-102.2 -106.3,-102.2H183.4c-57.6,0 -104.2,44.7 -104.2,102.2V345.7c50.9,6.4 95.6,52.1 95.6,107.6s-44.8,101.1 -95.6,107.6v230.7c0,57.5 46.6,105.2 69.4,105.2h999.1z"
  11 + android:fillColor="#FFFFFF"/>
  12 + <path
  13 + android:pathData="M1147.3,903.2H148.6c-30.5,0 -88.5,-50 -88.5,-111.6V560.8c0,-5.8 8.1,-10.7 13.8,-11.4 48.8,-5.8 87.4,-47.2 87.4,-96.2 0,-49 -39.6,-90.4 -88.3,-96.2 -5.8,-0.7 -12.9,-5.6 -12.9,-11.4V114.9C60.1,51.2 119.5,0 183.4,0h1182.4c63.8,0 119,51.2 119,114.9V585.7c0,6.3 -6.4,11.4 -12.7,11.4s-12.7,-5.1 -12.7,-11.4V114.9c0,-51.1 -42.4,-89.5 -93.6,-89.5H183.4c-51.2,0 -97.8,38.4 -97.8,89.5v221c57.2,11.4 95.6,60.1 95.6,117.3 0,57.2 -38.4,105.9 -95.6,117.3v221c0,54.2 49,92.5 63,92.5h998.7c6.3,0 11.5,3.2 11.5,9.5 0,6.3 -5.1,9.5 -11.5,9.5z"
  14 + android:fillColor="#BABABA"/>
  15 + <path
  16 + android:pathData="M1162.6,764.1c0,95.8 77.8,173.5 173.9,173.5s173.9,-77.7 173.9,-173.5 -77.8,-173.5 -173.9,-173.5 -173.9,77.7 -173.9,173.5z"
  17 + android:fillColor="#FFFFFF"/>
  18 + <path
  19 + android:pathData="M1336.4,949c-102.2,0 -185.3,-83 -185.3,-184.9 0,-102 83.1,-184.9 185.3,-184.9s185.3,83 185.3,184.9c-0,102 -83.2,184.9 -185.3,184.9zM1336.4,602c-89.6,0 -162.4,72.7 -162.4,162.1 0,89.4 72.9,162.1 162.4,162.1s162.4,-72.7 162.4,-162.1c0,-89.4 -72.9,-162.1 -162.4,-162.1z"
  20 + android:fillColor="#BABABA"/>
  21 + <path
  22 + android:pathData="M1188.7,764.1c0,81.4 66.2,147.5 147.8,147.5s147.8,-66 147.8,-147.5 -66.2,-147.5 -147.8,-147.5 -147.8,66 -147.8,147.5z"
  23 + android:fillColor="#F4F4F4"/>
  24 + <path
  25 + android:pathData="M1163.6,273.5c0,7.2 -4.6,12.7 -10.2,12.7L919.7,286.2c-5.6,0 -10.2,-5.5 -10.2,-12.7 0,-7.2 4.5,-12.7 10.2,-12.7h233.8c5.6,0 10.2,5.5 10.2,12.7zM642.8,636c0,7.2 -4.6,12.7 -10.2,12.7L398.9,648.7c-5.6,0 -10.2,-5.5 -10.2,-12.7 0,-7.2 4.6,-12.7 10.2,-12.7h233.7c5.6,0 10.2,5.5 10.2,12.7zM1147.8,391.2c0,4.8 -2.8,9.5 -6.4,9.5L391.9,400.7c-3.5,0 -6.4,-4.8 -6.4,-9.5s2.8,-9.5 6.4,-9.5h749.5c3.5,0 6.4,4.8 6.4,9.5zM1147.8,515.2c0,4.8 -2.8,12.7 -6.4,12.7L391.9,527.9c-3.5,0 -6.4,-7.9 -6.4,-12.7s2.8,-12.7 6.4,-12.7h749.5c3.5,0 6.4,7.9 6.4,12.7z"
  26 + android:fillColor="#E8E8E8"/>
  27 + <path
  28 + android:pathData="M1360.8,773.1c12.5,0 23.7,-0.4 33.4,-1.4v14.6c-9.3,-0.9 -20.4,-1.4 -33.4,-1.4h-15.3v41.6h42.4c13.4,0 24.3,-0.5 32.7,-1.4v14.6c-7.9,-0.9 -18.3,-1.4 -31.3,-1.4h-91.8c-18.1,0 -31.1,0.5 -38.9,1.4v-14.6c8.8,0.9 22.3,1.4 40.3,1.4h31.3v-41.6h-17.4c-12.5,0 -23.4,0.5 -32.7,1.4v-14.6c8.8,0.9 20.4,1.4 34.8,1.4h45.9zM1302.8,750.5c-9,6.7 -19.4,13.5 -30.9,20.5 -3.2,-4.7 -6.6,-8.8 -10.4,-12.5 9.8,-4.2 18.3,-9 26.2,-14.5a115.7,115.7 0,0 0,21 -18.7c4.7,4 9.8,8 15.4,11.7 -5.1,2.3 -12.2,6.8 -21.2,13.5zM1394.9,736.3v-18.7h-114v20.8h-15.3c0.5,-4.6 0.7,-9.9 0.7,-16 0,-6.5 -0.2,-12.3 -0.7,-17.4h69.5c-3.4,-7.8 -6.6,-14.2 -10.2,-20.3 5.1,-1.4 10.2,-3.5 15.8,-5.3 8.3,19.5 11.5,26.5 14.8,33.6 -9.7,-10.7 -14.1,-9.3 -18.3,-7.9h73.7c-0.5,4.2 -0.7,9.7 -0.7,16.7 0,6.5 0.2,11.3 0.7,14.6h-16zM1381.3,738.4c9,4.2 19.8,9.9 32.3,17.3 -4.6,5.1 -7.9,9.5 -9.7,13.2 -6.1,-4 -14.5,-9.1 -23.1,-13.9a492,492 0,0 0,-26.8 -14c-0.6,-4.1 2.1,-7.8 5.4,-12.4 5.6,2.3 12.9,5.5 21.9,9.7z"
  29 + android:fillColor="#BABABA"/>
  30 +</vector>
mvpsdk/src/main/res/drawable/ic_vector_loading.xml 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +<vector android:height="24dp" android:viewportHeight="1024.0"
  2 + android:viewportWidth="1024.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
  3 + <path android:fillColor="#707070" android:pathData="M390.2,438.8c-17.3,0 -31.3,14 -31.3,31.3l0,30.6c0,17.3 14,31.3 31.3,31.3 17.3,0 31.3,-14 31.3,-31.3l0,-30.6C421.5,452.8 407.5,438.8 390.2,438.8z"/>
  4 + <path android:fillColor="#707070" android:pathData="M634.8,438.8c-17.3,0 -31.3,14 -31.3,31.3l0,30.6c0,17.3 14,31.3 31.3,31.3 17.3,0 31.3,-14 31.3,-31.3l0,-30.6C666.1,452.8 652.1,438.8 634.8,438.8z"/>
  5 + <path android:fillColor="#707070" android:pathData="M589.8,580.7c-14.3,-9.4 -33.7,-5.4 -43.3,8.8 -0.1,0.2 -13.7,19.8 -34.3,19.8 -20.1,0 -32.5,-18.2 -33.4,-19.4 -9.2,-14.5 -28.4,-18.9 -43,-9.8 -14.7,9.1 -19.2,28.4 -10.1,43.1 11.2,18.1 42.1,48.7 86.4,48.7 44.1,0 75.4,-30.4 86.9,-48.4C608.3,609.1 604.1,590.1 589.8,580.7z"/>
  6 + <path android:fillColor="#707070" android:pathData="M94.4,554c4.4,2.1 9,3.1 13.6,3.1 11.7,0 22.9,-6.5 28.3,-17.7 25.1,-52.1 61.9,-89.8 96.2,-98.6 11.2,-2.9 19.9,-11.7 22.7,-22.9 28.3,-115.7 116.8,-184.8 236.8,-184.8 85.3,0 168,51.1 184.3,113.8 3.7,14.2 16.8,24.3 31.3,23.4 1.8,-0.1 3.5,-0.1 5.2,-0.1 94.3,0 158.5,80.3 173.4,161.1 3.1,17 19.5,28.3 36.5,25.1 17,-3.1 28.3,-19.5 25.1,-36.5 -21.8,-118.1 -111.8,-203.8 -218.8,-211.8 -34,-80 -131.2,-137.8 -237.1,-137.8 -142.7,0 -253.5,82.2 -293.2,215.7 -46,19 -89.5,64.8 -119,126.1C72.2,527.7 78.8,546.5 94.4,554z"/>
  7 + <path android:fillColor="#707070" android:pathData="M934.4,598.6c-17,-3.7 -33.6,6 -37.3,22.9 -22,100.7 -104.7,171.8 -196.7,171.8L280,793.3c-82.1,0 -151.4,-76.5 -151.4,-168.8 0,-17.3 -14,-29.8 -31.3,-29.8s-31.3,13 -31.3,30.3c0,126.3 98,231 214,231L700.4,856c121.2,0 229.7,-92.3 257.9,-221.6C962,617.5 951.3,602.3 934.4,598.6z"/>
  8 +</vector>
mvpsdk/src/main/res/drawable/ic_vector_net_error.xml 0 → 100644
@@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
  1 +<vector xmlns:android="http://schemas.android.com/apk/res/android"
  2 + android:width="308dp"
  3 + android:height="200dp"
  4 + android:viewportWidth="1581.0"
  5 + android:viewportHeight="1024.0">
  6 + <path
  7 + android:pathData="M1074.7,709.8c20,3.1 38.7,-10.6 41.8,-30.5 3.1,-20 -10.6,-38.7 -30.5,-41.8l-260.6,-40.5 -14.2,71.9 263.6,41z"
  8 + android:fillColor="#8a8a8a"/>
  9 + <path
  10 + android:pathData="M1522.5,927.7l56.2,-361.8c9.3,-60 -31.7,-116.1 -91.7,-125.4l-434.1,-67.5c-60,-9.3 -116.1,31.7 -125.4,91.6l-11.2,72.4 72.3,11.2 11.2,-72.3c3.1,-20 21.8,-33.7 41.8,-30.6l434.1,67.5c20,3.1 33.7,21.9 30.6,41.8l-56.2,361.8c-3.1,19.9 -21.8,33.6 -41.8,30.5l-434.2,-67.5c-19.9,-3.2 -33.6,-21.9 -30.6,-41.8l11.2,-72.3 -72.4,-11.3 -11.2,72.4c-9.3,60 31.7,116.1 91.7,125.4l434.2,67.5c60,9.3 116.1,-31.7 125.4,-91.6zM494.8,638.4c-19.9,3.2 -33.5,22.1 -30.2,42 3.3,20 22.1,33.5 42,30.2l260.3,-42.5 -8.9,-72.8 -263.2,43z"
  11 + android:fillColor="#8a8a8a"/>
  12 + <path
  13 + android:pathData="M710.9,825.6l-11.8,-72.3 -72.3,11.8 11.8,72.2c3.2,19.9 -10.3,38.8 -30.2,42l-433.6,70.8c-19.9,3.3 -38.8,-10.3 -42,-30.2L73.7,558.7c-3.2,-19.9 10.3,-38.8 30.2,-42.1l433.6,-70.8c19.9,-3.2 38.8,10.3 42,30.2l11.8,72.2 72.3,-11.8 -11.8,-72.3c-9.8,-59.9 -66.2,-100.5 -126.1,-90.7L92.1,444.4c-59.9,9.8 -100.5,66.2 -90.7,126.1L60.5,931.9c9.8,59.9 66.2,100.4 126.1,90.7l433.6,-70.8c59.9,-9.8 100.5,-66.2 90.7,-126.1zM518,215.3s0,0 0,0l-95.3,-90.4c-10.2,-9.7 -10.6,-25.8 -0.9,-36.1 9.7,-10.2 25.8,-10.6 36.1,-0.9 0,0 0,0 0,0l95.3,90.4c10.2,9.7 10.6,25.8 0.9,36.1 -9.7,10.2 -25.8,10.6 -36.1,0.9zM780.6,175.4a25.4,25.4 0,0 1,-7.9 -17.8l-3.4,-131.3C768.8,12.1 779.9,0.4 794,0c14.1,-0.4 25.8,10.8 26.2,24.8l3.4,131.3c0.4,14.1 -10.8,25.8 -24.8,26.2a25.4,25.4 0,0 1,-18.2 -7zM1027.6,210.6c-10.2,-9.7 -10.6,-25.8 -0.9,-36.1l90.4,-95.3c9.7,-10.2 25.8,-10.6 36.1,-0.9 10.2,9.7 10.6,25.8 0.9,36.1l-90.4,95.3c-9.7,10.2 -25.8,10.6 -36.1,0.9z"
  14 + android:fillColor="#8a8a8a"/>
  15 +</vector>
mvpsdk/src/main/res/drawable/indoor_temp.png 0 → 100644

617 Bytes

mvpsdk/src/main/res/drawable/item_touch_bg.xml 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<selector xmlns:android="http://schemas.android.com/apk/res/android">
  3 + <item android:drawable="@color/md_grey_500" android:state_pressed="true"/>
  4 + <item android:drawable="@color/md_grey_500" android:state_focused="true"/>
  5 +</selector>
mvpsdk/src/main/res/drawable/stackblur_default.png 0 → 100644

32.1 KB

mvpsdk/src/main/res/drawable/week_normal.png 0 → 100644

904 Bytes

mvpsdk/src/main/res/drawable/week_selector.png 0 → 100644

3.03 KB

mvpsdk/src/main/res/drawable/week_status.xml 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<selector xmlns:android="http://schemas.android.com/apk/res/android">
  3 +
  4 + <item android:drawable="@drawable/week_selector" android:state_checked="true"/>
  5 + <item android:drawable="@drawable/week_selector" android:state_pressed="true"/>
  6 + <item android:drawable="@drawable/week_selector" android:state_selected="true"/>
  7 + <item android:drawable="@drawable/week_normal"/>
  8 +
  9 +</selector>
0 \ No newline at end of file 10 \ No newline at end of file
mvpsdk/src/main/res/drawable/week_tv_status.xml 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<selector xmlns:android="http://schemas.android.com/apk/res/android">
  3 +
  4 + <item android:drawable="@color/light_yellow" android:state_selected="true"/>
  5 + <item android:drawable="@color/white"/>
  6 +
  7 +</selector>
0 \ No newline at end of file 8 \ No newline at end of file
mvpsdk/src/main/res/layout/sub_history_click_view.xml 0 → 100644
@@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:layout_width="match_parent"
  4 + android:layout_height="match_parent"
  5 + android:gravity="center_horizontal"
  6 + android:orientation="vertical" >
  7 +
  8 + <ImageView
  9 + android:id="@+id/iv_click_view"
  10 + android:layout_width="wrap_content"
  11 + android:layout_height="0dp"
  12 + android:src="@drawable/week_status"
  13 + android:layout_weight="1" />
  14 +
  15 + <TextView
  16 + android:id="@+id/tv_click_view"
  17 + android:layout_width="match_parent"
  18 + android:layout_height="wrap_content"
  19 + android:text="@string/history_day"
  20 + android:gravity="center_horizontal"
  21 + android:textColor="@color/light_grey"
  22 + android:paddingTop="5dp"
  23 + android:paddingBottom="8dp"/>
  24 +
  25 +</LinearLayout>
0 \ No newline at end of file 26 \ No newline at end of file
mvpsdk/src/main/res/layout/sub_history_tips.xml 0 → 100644
@@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + android:layout_width="wrap_content"
  4 + android:layout_height="match_parent"
  5 + android:orientation="horizontal" >
  6 +
  7 + <ImageView
  8 + android:id="@+id/iv_tip"
  9 + android:layout_width="30dp"
  10 + android:layout_height="match_parent"
  11 + android:paddingRight="5dp"
  12 + android:src="@drawable/indoor_temp" />
  13 +
  14 + <LinearLayout
  15 + android:layout_width="match_parent"
  16 + android:layout_height="match_parent"
  17 + android:gravity="center_vertical"
  18 + android:orientation="vertical" >
  19 +
  20 + <TextView
  21 + android:id="@+id/tv_tip1"
  22 + android:layout_width="match_parent"
  23 + android:layout_height="wrap_content"
  24 + android:text="tip1"
  25 + android:textColor="@color/light_grey2" />
  26 +
  27 + <TextView
  28 + android:id="@+id/tv_tip2"
  29 + android:layout_width="match_parent"
  30 + android:layout_height="wrap_content"
  31 + android:text="tip2"
  32 + android:textColor="@color/light_grey2" />
  33 + </LinearLayout>
  34 +
  35 +</LinearLayout>
0 \ No newline at end of file 36 \ No newline at end of file
mvpsdk/src/main/res/layout/view_empty.xml 0 → 100644
@@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + xmlns:app="http://schemas.android.com/apk/res-auto"
  4 + style="@style/bg"
  5 + android:gravity="center"
  6 + android:orientation="vertical">
  7 +
  8 + <android.support.v7.widget.AppCompatImageView
  9 + style="@style/empty_img"
  10 + app:srcCompat = "@drawable/ic_vector_empty"/>
  11 +
  12 + <TextView
  13 + android:layout_width="wrap_content"
  14 + android:layout_height="wrap_content"
  15 + android:layout_marginBottom="30dp"
  16 + android:layout_marginTop="5dp"
  17 + android:text="@string/empty_no_data"
  18 + android:textColor="@color/txt_color"/>
  19 +</LinearLayout>
0 \ No newline at end of file 20 \ No newline at end of file
mvpsdk/src/main/res/layout/view_loading.xml 0 → 100644
@@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + xmlns:app="http://schemas.android.com/apk/res-auto"
  4 + style="@style/bg"
  5 + android:gravity="center"
  6 + android:orientation="vertical">
  7 +
  8 + <android.support.v7.widget.AppCompatImageView
  9 + style="@style/loading_img"
  10 + app:srcCompat="@drawable/ic_vector_loading"/>
  11 +
  12 + <LinearLayout
  13 + android:layout_width="wrap_content"
  14 + android:layout_height="60dp"
  15 + android:gravity="center_vertical"
  16 + android:orientation="horizontal">
  17 +
  18 + <ProgressBar
  19 + android:id="@+id/progressBar"
  20 + style="?android:attr/progressBarStyle"
  21 + android:layout_width="35dp"
  22 + android:layout_height="35dp"/>
  23 +
  24 + <TextView
  25 + android:layout_width="wrap_content"
  26 + android:layout_height="wrap_content"
  27 + android:layout_marginLeft="8dp"
  28 + android:text="@string/loading"
  29 + android:textColor="@color/txt_color"
  30 + android:textSize="16sp"/>
  31 + </LinearLayout>
  32 +</LinearLayout>
0 \ No newline at end of file 33 \ No newline at end of file
mvpsdk/src/main/res/layout/view_network_error.xml 0 → 100644
@@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 + xmlns:app="http://schemas.android.com/apk/res-auto"
  4 + style="@style/bg"
  5 + android:gravity="center"
  6 + android:orientation="vertical">
  7 +
  8 + <android.support.v7.widget.AppCompatImageView
  9 + style="@style/net_error_img"
  10 + app:srcCompat="@drawable/ic_vector_net_error"/>
  11 +
  12 + <TextView
  13 + android:layout_width="wrap_content"
  14 + android:layout_height="wrap_content"
  15 + android:layout_marginBottom="30dp"
  16 + android:layout_marginTop="5dp"
  17 + android:text="@string/empty_network_error"
  18 + android:textColor="@color/txt_color"/>
  19 +</LinearLayout>
0 \ No newline at end of file 20 \ No newline at end of file
mvpsdk/src/main/res/mipmap-xhdpi/ic_arrow_back_white.png 0 → 100644

233 Bytes

mvpsdk/src/main/res/mipmap-xxhdpi/ic_arrow_back_white.png 0 → 100644

374 Bytes

mvpsdk/src/main/res/values-v21/styles.xml 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<resources>
  3 +
  4 + <style name="CompatAppTheme" parent="AppBaseTheme">
  5 + <item name="android:windowNoTitle">true</item>
  6 + <item name="android:windowFullscreen">false</item>
  7 + <item name="android:windowActionBar">false</item>
  8 + <item name="windowActionModeOverlay">true</item>
  9 + <item name="android:windowDrawsSystemBarBackgrounds">true</item>
  10 + <item name="android:statusBarColor">@android:color/transparent</item>
  11 + </style>
  12 +
  13 +</resources>
mvpsdk/src/main/res/values-zh-rCN/strings.xml 0 → 100644
@@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
  1 +<resources>
  2 + <string name="dialog_positive">确定</string>
  3 + <string name="dialog_negative">取消</string>
  4 + <string name="loading">正在加载中……</string>
  5 + <string name="load_failed">加载失败,请点我重试</string>
  6 + <string name="press_again">再按一次退出</string>
  7 +
  8 + <!--历史数据界面-->
  9 + <string name="history_day">天</string>
  10 + <string name="history_week">周</string>
  11 + <string name="history_month">月</string>
  12 + <string name="history_year">年</string>
  13 + <string name="history_Indoor">室内</string>
  14 + <string name="history_Temp">温度</string>
  15 + <string name="history_Setpoint">目标</string>
  16 + <string name="history_On">加热</string>
  17 + <string name="history_Time">时间</string>
  18 + <string name="history_x_unit_day">(天)</string>
  19 + <string name="history_x_unit_hour">(小时)</string>
  20 + <string name="history_x_unit_month">(月)</string>
  21 + <string name="history_y1_unit">(℃)</string>
  22 + <string name="history_y2_unit">(%)</string>
  23 +
  24 + <!--能耗单位-->
  25 + <string name="y_unit_day">(分)</string>
  26 + <string name="y_unit_week">(小时)</string>
  27 + <string name="y_unit_month">(小时)</string>
  28 + <string name="x_unit_day">(小时)</string>
  29 + <string name="x_unit_week">(天)</string>
  30 + <string name="x_unit_month">(天)</string>
  31 + <string name="y_unit_degree">(千瓦/时)</string>
  32 + <string name="energy_consumption_day">天</string>
  33 + <string name="energy_consumption_week">周</string>
  34 + <string name="energy_consumption_month">月</string>
  35 +
  36 + <string name="empty_network_error">网络异常,点击重试</string>
  37 + <string name="empty_no_data">没有数据,点击重试</string>
  38 +</resources>
mvpsdk/src/main/res/values/arrays.xml 0 → 100644
@@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<resources>
  3 + <string-array name="permissions">
  4 + <item>@string/permission_recode_audio_hint</item>
  5 + <item>@string/permission_get_accounts_hint</item>
  6 + <item>@string/permission_read_phone_hint</item>
  7 + <item>@string/permission_call_phone_hint</item>
  8 + <item>@string/permission_camera_hint</item>
  9 + <item>@string/permission_access_fine_location_hint</item>
  10 + <item>@string/permission_access_coarse_location_hint</item>
  11 + <item>@string/permission_read_external_hint</item>
  12 + <item>@string/permission_white_external_hint</item>
  13 + </string-array>
  14 + <string name="permission_get_accounts_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_GET_ACCOUNTS</string>
  15 + <string name="permission_read_phone_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_READ_PHONE_STATE</string>
  16 + <string name="permission_call_phone_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_CALL_PHONE</string>
  17 + <string name="permission_camera_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_CAMERA</string>
  18 + <string name="permission_access_fine_location_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_ACCESS_FINE_LOCATION</string>
  19 + <string name="permission_access_coarse_location_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_ACCESS_COARSE_LOCATION</string>
  20 + <string name="permission_read_external_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_READ_EXTERNAL_STORAGE</string>
  21 + <string name="permission_white_external_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_WRITE_EXTERNAL_STORAGE</string>
  22 + <string name="permission_recode_audio_hint">没有此权限,无法开启这个功能,请开启权限。PERMISSION_RECORD_AUDIO</string>
  23 +
  24 +</resources>
0 \ No newline at end of file 25 \ No newline at end of file
mvpsdk/src/main/res/values/attrs.xml 0 → 100644
@@ -0,0 +1,81 @@ @@ -0,0 +1,81 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<resources>
  3 + <attr name="themeColor" format="color|reference"/>
  4 + <attr name="widgetBackground" format="color|reference"/>
  5 + <attr name="widgetBackgroundDark" format="color|reference"/>
  6 + <attr name="widgetBackgroundTitle" format="color|reference"/>
  7 +
  8 + <declare-styleable name="RecyclerViewPager">
  9 + <attr name="rvp_triggerOffset" format="float"/>
  10 + <attr name="rvp_flingFactor" format="float"/>
  11 + <attr name="rvp_singlePageFling" format="boolean"/>
  12 + </declare-styleable>
  13 +
  14 + <declare-styleable name="SlideSwitchView">
  15 + <attr name="slide_button" format="reference"/>
  16 + <attr name="android:text"/>
  17 + <attr name="android:textSize"/>
  18 + <attr name="android:textColor"/>
  19 + </declare-styleable>
  20 +
  21 + <declare-styleable name="HistoryModeView">
  22 + <attr name="android:textColor"/>
  23 + <attr name="android:text"/>
  24 + <attr name="select_text_size" format="dimension"/>
  25 + <attr name="un_select_text_size" format="dimension"/>
  26 + </declare-styleable>
  27 +
  28 + <declare-styleable name="HistoryTipsView">
  29 + <attr name="android:textColor"/>
  30 + <attr name="android:textSize"/>
  31 + <attr name="android:src"/>
  32 + <attr name="tip_one_text" format="string"/>
  33 + <attr name="tip_two_text" format="string"/>
  34 + </declare-styleable>
  35 +
  36 + <declare-styleable name="HistoryChartView">
  37 + <attr name="ylabel_text_size" format="dimension"/>
  38 + <attr name="xlabel_text_size" format="dimension"/>
  39 + <attr name="margin_top" format="dimension"/>
  40 + <attr name="margin_bottom" format="dimension"/>
  41 + <attr name="margin_left" format="dimension"/>
  42 + <attr name="margin_right" format="dimension"/>
  43 + <attr name="line_stroke_width" format="dimension"/>
  44 + <attr name="data_stroke_width" format="dimension"/>
  45 + <attr name="circle_radius" format="dimension"/>
  46 + <attr name="line_color" format="color"/>
  47 + <attr name="unit_color" format="color"/>
  48 + <attr name="x_unit_text" format="string"/>
  49 + <attr name="y1_unit_text" format="string"/>
  50 + <attr name="y2_unit_text" format="string"/>
  51 + <attr name="y_unit_text_size" format="dimension"/>
  52 + <attr name="x_unit_text_size" format="dimension"/>
  53 + <attr name="first_data_line_color" format="color"/>
  54 + <attr name="second_data_line_color" format="color"/>
  55 + <attr name="rect_background_color" format="color"/>
  56 + <attr name="x_first_point_offset" format="dimension"/>
  57 + </declare-styleable>
  58 +
  59 + <declare-styleable name="MovingImageView">
  60 + <attr name="miv_speed" format="integer"/>
  61 + <attr name="miv_repetitions" format="integer"/>
  62 + <attr name="miv_max_relative_size" format="float"/>
  63 + <attr name="miv_min_relative_offset" format="float"/>
  64 + <attr name="miv_start_delay" format="integer"/>
  65 + <attr name="miv_load_on_create" format="boolean"/>
  66 + </declare-styleable>
  67 +
  68 + <declare-styleable name="MovingImageViewTheme">
  69 + <attr name="movingImageViewStyle" format="reference"/>
  70 + </declare-styleable>
  71 +
  72 +
  73 + <declare-styleable name="ClipViewLayout">
  74 + <attr name="clipType" format="enum">
  75 + <enum name="circle" value="1" />
  76 + <enum name="rectangle" value="2" />
  77 + </attr>
  78 + <attr name="mHorizontalPadding" format="dimension" />
  79 + <attr name="clipBorderWidth" format="dimension" />
  80 + </declare-styleable>
  81 +</resources>
0 \ No newline at end of file 82 \ No newline at end of file
mvpsdk/src/main/res/values/colors.xml 0 → 100644
@@ -0,0 +1,78 @@ @@ -0,0 +1,78 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<resources>
  3 + <!-- basic -->
  4 + <!-- 主色调 -->
  5 + <color name="colorPrimary">#ffeeeeee</color>
  6 + <color name="titleColor">#C6DAFF</color>
  7 + <!-- 主题相关颜色 -->
  8 + <color name="window_background_light">#ffeeeeee</color>
  9 + <color name="window_background_dark">#ff303030</color>
  10 + <color name="text_color_light">#b3ffffff</color>
  11 + <color name="text_color_dark">#de000000</color>
  12 + <color name="list_divider_light">#ffe0e0e0</color>
  13 + <color name="list_divider_dark">#ff666666</color>
  14 + <color name="selectable_item_background_general_light_normal">@android:color/white</color>
  15 + <color name="selectable_item_background_general_light_pressed">#ffeeeeee</color>
  16 + <color name="selectable_item_background_general_light_accent">#ffcccccc</color>
  17 + <color name="selectable_item_background_general_dark_normal">#ff3c3c3c</color>
  18 + <color name="selectable_item_background_general_dark_pressed">#ff444444</color>
  19 + <color name="selectable_item_background_general_dark_accent">#ff666666</color>
  20 + <!-- 主体文字,标题/标签 -->
  21 + <color name="txt_black">#212121</color>
  22 + <!-- 内容文字,正文 -->
  23 + <color name="txt_gray">#808080</color>
  24 + <!-- 辅助文字,提示 -->
  25 + <color name="txt_light_gray">#CCCCCC</color>
  26 + <!-- 背景色 -->
  27 + <color name="bg_gray">#f1f1f1</color>
  28 + <!-- 按下灰色 -->
  29 + <color name="bg_gray_pressed">#e8e8e8</color>
  30 + <!-- 高亮,红棕色 -->
  31 + <color name="brown">#d54c1c</color>
  32 + <!-- 分割线 -->
  33 + <color name="divider_gray">#cbcbcb</color>
  34 + <!-- other -->
  35 + <color name="txt_link_blue">#1ea5ff</color>
  36 + <color name="button_bg">#98f5ff</color>
  37 +
  38 + <!-- wheel -->
  39 + <color name="province_line_border">#C7C7C7</color>
  40 +
  41 + <!-- drop down menu -->
  42 + <color name="white">#ffffff</color>
  43 + <color name="gray">#cccccc</color>
  44 +
  45 + <color name="drop_down_selected">#8BC34A</color>
  46 + <color name="drop_down_unselected">#808080</color>
  47 +
  48 + <color name="mask_color">#88888888</color>
  49 + <color name="check_bg">#f1f1f1</color>
  50 + <color name="un_press_color">#8BC34A</color>
  51 +
  52 + <!-- position bar -->
  53 + <color name="bg_position_bar_up">#0D8BC34A</color>
  54 + <color name="bg_position_bar_down">#1A8BC34A</color>
  55 + <color name="theme_black_7f">#8f000000</color>
  56 +
  57 + <color name="light_yellow">#FF9500</color>
  58 + <color name="light_grey">#808080</color>
  59 + <color name="dark_grey">#333333</color>
  60 +
  61 + <color name="yellow_translucent">#80FF9500</color>
  62 +
  63 + <color name="grey_line">#808080</color>
  64 + <color name="setpoint_temp">#FF9500</color>
  65 + <color name="indoor_temp">#ffffff</color>
  66 + <color name="power_time">#4a2317</color>
  67 + <color name="light_grey2">#AAAAAA</color>
  68 +
  69 + <color name="shape_count_down_bg">#88000000</color>
  70 + <color name="text_translucent">#88000000</color>
  71 + <color name="gankio_text_type_grey">#707070</color>
  72 +
  73 + <color name="bg">#F0F0F0</color>
  74 + <color name="txt_color">#48495F</color>
  75 +
  76 + <!--电影评分-->
  77 + <color name="colorRateRed">#FB5B81</color>
  78 +</resources>
mvpsdk/src/main/res/values/dimens.xml 0 → 100644
@@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
  1 +<resources>
  2 +
  3 + <!-- Default screen margins, per the Android Design guidelines. -->
  4 + <dimen name="activity_horizontal_margin">16dp</dimen>
  5 + <dimen name="activity_vertical_margin">16dp</dimen>
  6 +
  7 + <!-- margin -->
  8 + <dimen name="margin_tiny">4dp</dimen>
  9 + <dimen name="margin_small">8dp</dimen>
  10 + <dimen name="margin_medium">16dp</dimen>
  11 + <dimen name="margin_20">20dp</dimen>
  12 + <dimen name="margin_24">24dp</dimen>
  13 + <dimen name="margin_large">32dp</dimen>
  14 + <dimen name="margin_huge">64dp</dimen>
  15 + <dimen name="margin_only_txt">48dp</dimen>
  16 +
  17 + <!-- txtsize -->
  18 + <dimen name="txtsize_display1">34sp</dimen>
  19 + <dimen name="txtsize_headline">24sp</dimen>
  20 + <dimen name="txtsize_title">20sp</dimen>
  21 + <dimen name="txtsize_subhead">16sp</dimen>
  22 + <dimen name="txtsize_body">14sp</dimen>
  23 + <dimen name="txtsize_caption">12sp</dimen>
  24 +
  25 + <!-- other size -->
  26 + <dimen name="corner_radius">2dp</dimen>
  27 + <dimen name="banner_height">136dp</dimen>
  28 +
  29 + <dimen name="def_height">50dp</dimen>
  30 + <dimen name="avatarSize">50dp</dimen>
  31 + <dimen name="smallSpace">6dp</dimen>
  32 +
  33 + <dimen name="dp_066">0.66dp</dimen>
  34 + <dimen name="dp_4">4dp</dimen>
  35 + <dimen name="dp_5">5dp</dimen>
  36 + <dimen name="dp_8">8dp</dimen>
  37 + <dimen name="dp_10">10dp</dimen>
  38 + <dimen name="dp_14">14dp</dimen>
  39 + <dimen name="dp_22">22dp</dimen>
  40 + <dimen name="dp_30">30dp</dimen>
  41 + <dimen name="dp_36">36dp</dimen>
  42 + <dimen name="dp_40">40dp</dimen>
  43 + <dimen name="dp_60">60dp</dimen>
  44 + <dimen name="dp_72">72dp</dimen>
  45 +
  46 + <dimen name="sp_12">12sp</dimen>
  47 + <dimen name="sp_14">14sp</dimen>
  48 + <dimen name="sp_16">16sp</dimen>
  49 + <dimen name="sp_18">18sp</dimen>
  50 + <dimen name="sp_20">20sp</dimen>
  51 +</resources>
0 \ No newline at end of file 52 \ No newline at end of file
mvpsdk/src/main/res/values/strings.xml 0 → 100644
@@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
  1 +<resources>
  2 + <string name="dialog_positive">Confirm</string>
  3 + <string name="dialog_negative">Cancel</string>
  4 + <string name="loading">Loading……</string>
  5 + <string name="load_failed">Load failed. Please click me again</string>
  6 + <string name="press_again">Press again to exit</string>
  7 + <string name="report">报告</string>
  8 + <!--历史数据界面-->
  9 + <string name="history_day">Day</string>
  10 + <string name="history_week">Week</string>
  11 + <string name="history_month">Month</string>
  12 + <string name="history_year">Year</string>
  13 + <string name="history_Indoor">Indoor</string>
  14 + <string name="history_Temp">Temp</string>
  15 + <string name="history_Setpoint">Setpoint</string>
  16 + <string name="history_On">Cumulative</string>
  17 + <string name="history_Time">Time</string>
  18 + <string name="history_x_unit_day">(DAY)</string>
  19 + <string name="history_x_unit_hour">(HOUR)</string>
  20 + <string name="history_x_unit_month">(MONTH)</string>
  21 + <string name="history_y1_unit">(℃)</string>
  22 + <string name="history_y2_unit">(%)</string>
  23 +
  24 + <!--能耗单位-->
  25 + <string name="y_unit_day">(min)</string>
  26 + <string name="y_unit_week">(hour)</string>
  27 + <string name="y_unit_month">(hour)</string>
  28 + <string name="x_unit_day">(hour)</string>
  29 + <string name="x_unit_week">(day)</string>
  30 + <string name="x_unit_month">(day)</string>
  31 + <string name="y_unit_degree">(KW/H)</string>
  32 + <string name="energy_consumption_day">DAY</string>
  33 + <string name="energy_consumption_week">WEEK</string>
  34 + <string name="energy_consumption_month">MONTH</string>
  35 +
  36 + <string name="empty_network_error">Network error, Click Retry</string>
  37 + <string name="empty_no_data">There is no data, Click Retry</string>
  38 +</resources>
mvpsdk/src/main/res/values/styles.xml 0 → 100644
@@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<resources>
  3 + <style name="AppBaseTheme" parent="AppThemeLight">
  4 +
  5 + </style>
  6 +
  7 + <style name="CompatAppTheme" parent="AppBaseTheme">
  8 + <item name="android:windowNoTitle">true</item>
  9 + <item name="android:windowFullscreen">false</item>
  10 + <item name="android:windowActionBar">false</item>
  11 + <item name="windowActionModeOverlay">true</item>
  12 + </style>
  13 +
  14 + <style name="TextViewTitle" parent="TextAppearance.AppCompat.Title">
  15 + <item name="android:layout_width">wrap_content</item>
  16 + <item name="android:layout_height">wrap_content</item>
  17 + <item name="android:singleLine">true</item>
  18 + <item name="android:textColor">@color/txt_black</item>
  19 + </style>
  20 +
  21 + <style name="TextViewSubhead" parent="TextAppearance.AppCompat.Subhead">
  22 + <item name="android:layout_width">wrap_content</item>
  23 + <item name="android:layout_height">wrap_content</item>
  24 + <item name="android:textColor">@color/txt_black</item>
  25 + </style>
  26 +
  27 + <style name="bg">
  28 + <item name="android:layout_width">match_parent</item>
  29 + <item name="android:layout_height">match_parent</item>
  30 + <item name="android:background">@color/bg</item>
  31 + <item name="android:orientation">vertical</item>
  32 + </style>
  33 +
  34 + <style name="net_error_img">
  35 + <item name="android:layout_width">80dp</item>
  36 + <item name="android:layout_height">80dp</item>
  37 + <item name="android:layout_marginBottom">10dp</item>
  38 + </style>
  39 +
  40 + <style name="loading_img">
  41 + <item name="android:layout_width">80dp</item>
  42 + <item name="android:layout_height">80dp</item>
  43 + </style>
  44 +
  45 + <style name="empty_img">
  46 + <item name="android:layout_width">80dp</item>
  47 + <item name="android:layout_height">80dp</item>
  48 + <item name="android:layout_marginBottom">10dp</item>
  49 + </style>
  50 +
  51 +</resources>
0 \ No newline at end of file 52 \ No newline at end of file
mvpsdk/src/main/res/values/themes.xml 0 → 100644
@@ -0,0 +1,265 @@ @@ -0,0 +1,265 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<resources>
  3 + <!-- App Theme Light -->
  4 + <style name="BaseAppThemeLight" parent="Theme.AppCompat.Light.NoActionBar">
  5 + <item name="android:windowNoTitle">true</item>
  6 + <item name="android:windowFullscreen">false</item>
  7 + <item name="android:windowActionBar">false</item>
  8 + <item name="colorPrimary">?attr/themeColor</item>
  9 + <item name="colorPrimaryDark">?attr/themeColor</item>
  10 + <item name="colorAccent">?attr/themeColor</item>
  11 + <item name="windowActionModeOverlay">true</item>
  12 + <item name="android:windowBackground">@color/window_background_light</item>
  13 + <item name="android:listDivider">@color/list_divider_light</item>
  14 + <item name="widgetBackground">@color/selectable_item_background_general_light_normal</item>
  15 + <item name="widgetBackgroundDark">@color/selectable_item_background_general_light_pressed
  16 + </item>
  17 + <item name="widgetBackgroundTitle">@android:color/white</item>
  18 + </style>
  19 +
  20 + <style name="AppThemeLight" parent="BaseAppThemeLight">
  21 + <item name="themeColor">@color/md_light_blue_500</item>
  22 + </style>
  23 +
  24 + <style name="AppThemeLight.NoTranslucent" parent="BaseAppThemeLight">
  25 + <item name="android:windowIsTranslucent">false</item>
  26 + </style>
  27 +
  28 + <style name="AppThemeLight.FitsStatusBar" />
  29 +
  30 + <!-- App Theme Dark -->
  31 + <style name="BaseAppThemeDark" parent="Theme.AppCompat.NoActionBar">
  32 + <item name="android:windowNoTitle">true</item>
  33 + <item name="android:windowFullscreen">false</item>
  34 + <item name="android:windowActionBar">false</item>
  35 + <item name="colorPrimary">?attr/themeColor</item>
  36 + <item name="colorPrimaryDark">?attr/themeColor</item>
  37 + <item name="colorAccent">?attr/themeColor</item>
  38 + <item name="windowActionModeOverlay">true</item>
  39 + <item name="android:windowBackground">@color/window_background_dark</item>
  40 + <item name="android:listDivider">@color/list_divider_dark</item>
  41 + <item name="widgetBackground">@color/selectable_item_background_general_dark_normal</item>
  42 + <item name="widgetBackgroundDark">@color/selectable_item_background_general_dark_pressed
  43 + </item>
  44 + <item name="widgetBackgroundTitle">?attr/colorPrimary</item>
  45 + <item name="android:windowIsTranslucent">true</item>
  46 + </style>
  47 +
  48 + <style name="AppThemeDark" parent="BaseAppThemeDark">
  49 + <item name="themeColor">@color/theme_night_blue</item>
  50 + </style>
  51 +
  52 + <style name="AppThemeDark.NoTranslucent" parent="BaseAppThemeDark">
  53 + <item name="android:windowIsTranslucent">false</item>
  54 + </style>
  55 +
  56 + <style name="AppThemeDark.FitsStatusBar" />
  57 +
  58 + <!-- App Theme Launch -->
  59 + <style name="AppThemeLaunch" parent="BaseAppThemeLight">
  60 + <item name="android:windowBackground">?attr/colorPrimary</item>
  61 + </style>
  62 +
  63 + <style name="AppWidget" parent="Theme.AppCompat.Light" />
  64 +
  65 + <style name="AppWidget.DeepLine">
  66 + <item name="android:layout_width">match_parent</item>
  67 + <item name="android:layout_height">1dp</item>
  68 + <item name="android:background">?android:attr/listDivider</item>
  69 + </style>
  70 +
  71 + <style name="AppWidget.DeepLine.Vertical">
  72 + <item name="android:layout_width">1dp</item>
  73 + <item name="android:layout_height">match_parent</item>
  74 + </style>
  75 +
  76 +
  77 + <!-- red -->
  78 + <style name="AppThemeLight.Red">
  79 + <item name="themeColor">@color/md_red_500</item>
  80 + </style>
  81 +
  82 + <style name="AppThemeDark.Red">
  83 + <item name="themeColor">@color/md_red_700</item>
  84 + </style>
  85 +
  86 +
  87 + <!-- pink -->
  88 + <style name="AppThemeLight.Pink">
  89 + <item name="themeColor">@color/md_pink_500</item>
  90 + </style>
  91 +
  92 + <style name="AppThemeDark.Pink">
  93 + <item name="themeColor">@color/md_pink_700</item>
  94 + </style>
  95 +
  96 +
  97 + <!-- purple -->
  98 + <style name="AppThemeLight.Purple">
  99 + <item name="themeColor">@color/md_purple_500</item>
  100 + </style>
  101 +
  102 + <style name="AppThemeDark.Purple">
  103 + <item name="themeColor">@color/md_purple_700</item>
  104 + </style>
  105 +
  106 +
  107 + <!-- deep_purple -->
  108 + <style name="AppThemeLight.DeepPurple">
  109 + <item name="themeColor">@color/md_deep_purple_500</item>
  110 + </style>
  111 +
  112 + <style name="AppThemeDark.DeepPurple">
  113 + <item name="themeColor">@color/md_deep_purple_700</item>
  114 + </style>
  115 +
  116 +
  117 + <!-- indigo -->
  118 + <style name="AppThemeLight.Indigo">
  119 + <item name="themeColor">@color/md_indigo_500</item>
  120 + </style>
  121 +
  122 + <style name="AppThemeDark.Indigo">
  123 + <item name="themeColor">@color/md_indigo_700</item>
  124 + </style>
  125 +
  126 +
  127 + <!-- blue -->
  128 + <style name="AppThemeLight.Blue">
  129 + <item name="themeColor">@color/theme_day_blue</item>
  130 + </style>
  131 +
  132 + <style name="AppThemeDark.Blue">
  133 + <item name="themeColor">@color/theme_night_blue</item>
  134 + </style>
  135 +
  136 +
  137 + <!-- light_blue -->
  138 + <style name="AppThemeLight.LightBlue">
  139 + <item name="themeColor">@color/md_light_blue_500</item>
  140 + </style>
  141 +
  142 + <style name="AppThemeDark.LightBlue">
  143 + <item name="themeColor">@color/md_light_blue_700</item>
  144 + </style>
  145 +
  146 +
  147 + <!-- cyan -->
  148 + <style name="AppThemeLight.Cyan">
  149 + <item name="themeColor">@color/md_cyan_500</item>
  150 + </style>
  151 +
  152 + <style name="AppThemeDark.Cyan">
  153 + <item name="themeColor">@color/md_cyan_700</item>
  154 + </style>
  155 +
  156 +
  157 + <!-- teal -->
  158 + <style name="AppThemeLight.Teal">
  159 + <item name="themeColor">@color/md_teal_500</item>
  160 + </style>
  161 +
  162 + <style name="AppThemeDark.Teal">
  163 + <item name="themeColor">@color/md_teal_700</item>
  164 + </style>
  165 +
  166 +
  167 + <!-- green -->
  168 + <style name="AppThemeLight.Green">
  169 + <item name="themeColor">@color/md_green_500</item>
  170 + </style>
  171 +
  172 + <style name="AppThemeDark.Green">
  173 + <item name="themeColor">@color/md_green_700</item>
  174 + </style>
  175 +
  176 +
  177 + <!-- light_green -->
  178 + <style name="AppThemeLight.LightGreen">
  179 + <item name="themeColor">@color/md_light_green_500</item>
  180 + </style>
  181 +
  182 + <style name="AppThemeDark.LightGreen">
  183 + <item name="themeColor">@color/md_light_green_700</item>
  184 + </style>
  185 +
  186 +
  187 + <!-- lime -->
  188 + <style name="AppThemeLight.Lime">
  189 + <item name="themeColor">@color/md_lime_500</item>
  190 + </style>
  191 +
  192 + <style name="AppThemeDark.Lime">
  193 + <item name="themeColor">@color/md_lime_700</item>
  194 + </style>
  195 +
  196 +
  197 + <!-- yellow -->
  198 + <style name="AppThemeLight.Yellow">
  199 + <item name="themeColor">@color/md_yellow_500</item>
  200 + </style>
  201 +
  202 + <style name="AppThemeDark.Yellow">
  203 + <item name="themeColor">@color/md_yellow_700</item>
  204 + </style>
  205 +
  206 +
  207 + <!-- amber -->
  208 + <style name="AppThemeLight.Amber">
  209 + <item name="themeColor">@color/md_amber_500</item>
  210 + </style>
  211 +
  212 + <style name="AppThemeDark.Amber">
  213 + <item name="themeColor">@color/md_amber_700</item>
  214 + </style>
  215 +
  216 +
  217 + <!-- orange -->
  218 + <style name="AppThemeLight.Orange">
  219 + <item name="themeColor">@color/md_orange_500</item>
  220 + </style>
  221 +
  222 + <style name="AppThemeDark.Orange">
  223 + <item name="themeColor">@color/md_orange_700</item>
  224 + </style>
  225 +
  226 +
  227 + <!-- deep_orange -->
  228 + <style name="AppThemeLight.DeepOrange">
  229 + <item name="themeColor">@color/md_deep_orange_500</item>
  230 + </style>
  231 +
  232 + <style name="AppThemeDark.DeepOrange">
  233 + <item name="themeColor">@color/md_deep_orange_700</item>
  234 + </style>
  235 +
  236 +
  237 + <!-- brown -->
  238 + <style name="AppThemeLight.Brown">
  239 + <item name="themeColor">@color/md_brown_500</item>
  240 + </style>
  241 +
  242 + <style name="AppThemeDark.Brown">
  243 + <item name="themeColor">@color/md_brown_700</item>
  244 + </style>
  245 +
  246 +
  247 + <!-- grey -->
  248 + <style name="AppThemeLight.Grey">
  249 + <item name="themeColor">@color/md_grey_500</item>
  250 + </style>
  251 +
  252 + <style name="AppThemeDark.Grey">
  253 + <item name="themeColor">@color/md_grey_700</item>
  254 + </style>
  255 +
  256 +
  257 + <!-- blue_grey -->
  258 + <style name="AppThemeLight.BlueGrey">
  259 + <item name="themeColor">@color/md_blue_grey_500</item>
  260 + </style>
  261 +
  262 + <style name="AppThemeDark.BlueGrey">
  263 + <item name="themeColor">@color/md_blue_grey_700</item>
  264 + </style>
  265 +</resources>
0 \ No newline at end of file 266 \ No newline at end of file
mvpsdk/src/main/res/values/themes_colors.xml 0 → 100644
@@ -0,0 +1,85 @@ @@ -0,0 +1,85 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<resources>
  3 + <!-- red -->
  4 + <color name="md_red_500">#e51c23</color>
  5 + <color name="md_red_700">#d01716</color>
  6 +
  7 + <!-- pink -->
  8 + <color name="md_pink_500">#e91e63</color>
  9 + <color name="md_pink_700">#c2185b</color>
  10 +
  11 + <!-- purple -->
  12 + <color name="md_purple_500">#9c27b0</color>
  13 + <color name="md_purple_700">#7b1fa2</color>
  14 +
  15 + <!-- deep_purple -->
  16 + <color name="md_deep_purple_500">#673ab7</color>
  17 + <color name="md_deep_purple_700">#512da8</color>
  18 +
  19 + <!-- indigo -->
  20 + <color name="md_indigo_500">#3f51b5</color>
  21 + <color name="md_indigo_700">#303f9f</color>
  22 +
  23 + <!-- blue -->
  24 + <color name="md_blue_500">#5677fc</color>
  25 + <color name="md_blue_700">#455ede</color>
  26 +
  27 + <!-- light_blue -->
  28 + <color name="md_light_blue_500">#03a9f4</color>
  29 + <color name="md_light_blue_700">#0288d1</color>
  30 +
  31 + <!-- cyan -->
  32 + <color name="md_cyan_500">#00bcd4</color>
  33 + <color name="md_cyan_700">#0097a7</color>
  34 +
  35 + <!-- teal -->
  36 + <color name="md_teal_500">#009688</color>
  37 + <color name="md_teal_700">#00796b</color>
  38 +
  39 + <!-- green -->
  40 + <color name="md_green_500">#259b24</color>
  41 + <color name="md_green_700">#0a7e07</color>
  42 + <!--<color name="md_green_700">#ff3c3c3c</color>-->
  43 +
  44 + <!-- light_green -->
  45 + <color name="md_light_green_500">#8bc34a</color>
  46 + <color name="md_light_green_700">#689f38</color>
  47 +
  48 + <!-- lime -->
  49 + <color name="md_lime_500">#cddc39</color>
  50 + <color name="md_lime_700">#afb42b</color>
  51 +
  52 + <!-- yellow -->
  53 + <color name="md_yellow_500">#ffeb3b</color>
  54 + <color name="md_yellow_700">#fbc02d</color>
  55 +
  56 + <!-- amber -->
  57 + <color name="md_amber_500">#ffc107</color>
  58 + <color name="md_amber_700">#ffa000</color>
  59 +
  60 + <!-- orange -->
  61 + <color name="md_orange_500">#ff9800</color>
  62 + <color name="md_orange_700">#f57c00</color>
  63 +
  64 + <!-- deep_orange -->
  65 + <color name="md_deep_orange_500">#ff5722</color>
  66 + <color name="md_deep_orange_700">#e64a19</color>
  67 +
  68 + <!-- brown -->
  69 + <color name="md_brown_500">#795548</color>
  70 + <color name="md_brown_700">#5d4037</color>
  71 +
  72 + <!-- grey -->
  73 + <color name="md_grey_500">#9e9e9e</color>
  74 + <color name="md_grey_700">#616161</color>
  75 + <!-- <color name="md_grey_1000">#000000</color> -->
  76 + <!-- <color name="md_grey_1000">#ffffff</color> -->
  77 + <color name="md_white">#ffffff</color>
  78 +
  79 + <!-- blue_grey -->
  80 + <color name="md_blue_grey_500">#607d8b</color>
  81 + <color name="md_blue_grey_700">#455a64</color>
  82 +
  83 + <color name="theme_day_blue">#03a9f4</color>
  84 + <color name="theme_night_blue">#ff3c3c3c</color>
  85 +</resources>
0 \ No newline at end of file 86 \ No newline at end of file
mvpsdk/src/test/java/com/share/mvpsdk/ExampleUnitTest.java 0 → 100644
@@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
  1 +package com.share.mvpsdk;
  2 +
  3 +import org.junit.Test;
  4 +
  5 +import static org.junit.Assert.*;
  6 +
  7 +/**
  8 + * Example local unit test, which will execute on the development machine (host).
  9 + *
  10 + * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
  11 + */
  12 +public class ExampleUnitTest {
  13 + @Test
  14 + public void addition_isCorrect() throws Exception {
  15 + assertEquals(4, 2 + 2);
  16 + }
  17 +}
0 \ No newline at end of file 18 \ No newline at end of file
settings.gradle
1 -include ':app' 1 +include ':app', ':mvpsdk'