Commit e47f8554b12ecef9419fe96acf2461ab8a2f97c6

Authored by 韩亚云
2 parents e9d55089 d6c3ecde

Merge branch 'master' of bj.gitlab.cnlive.com:cnlive-team/newModuleStrike

Showing 37 changed files with 3571 additions and 457 deletions

Too many changes to show.

To preserve performance only 37 of 470 files are displayed.

app/strike/build.gradle
... ... @@ -159,6 +159,7 @@ dependencies {
159 159 implementation project(path: ':cloud:user')
160 160  
161 161 implementation project(path: ':core:imageload')
  162 + compile project(path: ':module:xiaojiasoundbox')
162 163 // implementation project(path: ':core:util')
163 164 // implementation project(path: ':core:encipher')
164 165 // implementation project(path: ':cloud:user')
... ...
cloud/user/src/main/java/com/cnlive/strike/user/network/api/BaseRequest.java renamed to app/strike/src/BaseRequest.java
app/strike/src/main/java/com/cnlive/strike/MainActivity.java
... ... @@ -9,7 +9,9 @@ import android.util.AttributeSet;
9 9 import android.util.Log;
10 10 import android.view.View;
11 11  
  12 +import com.cnlive.strike.demo.activity.DemoActivity;
12 13 import com.cnlive.strike.imgutil.ImgActivity;
  14 +import com.cnlive.strike.user.ui.activity.LoginActivity;
13 15  
14 16 import androidx.annotation.NonNull;
15 17 import androidx.annotation.Nullable;
... ... @@ -22,6 +24,7 @@ public class MainActivity extends AppCompatActivity {
22 24 protected void onCreate(@Nullable Bundle savedInstanceState) {
23 25 super.onCreate(savedInstanceState);
24 26 setContentView(R.layout.activity_main);
  27 + findViewById(R.id.go_to).setOnClickListener(view -> startActivity(new Intent(this, DemoActivity.class)) );
25 28 findViewById(R.id.to_img).setOnClickListener(view -> startActivity(new Intent(this, ImgActivity.class)) );
26 29 }
27 30  
... ...
app/strike/src/main/java/com/cnlive/strike/MyActivity.java
1 1 package com.cnlive.strike;
2 2  
3 3  
  4 +import android.content.Intent;
  5 +import android.text.TextUtils;
  6 +
4 7 import com.cnlive.core.libs.base.frame.activity.BaseActivity;
  8 +import com.cnlive.strike.user.auth.UserService;
  9 +import com.cnlive.strike.xiaojiaspeaker.commonInfo.XiaoJIaCommInfo;
  10 +import com.cnlive.strike.xiaojiaspeaker.ui.activity.AllDeviceActivity;
5 11  
6 12  
7 13 public class MyActivity extends BaseActivity {
... ... @@ -13,11 +19,35 @@ public class MyActivity extends BaseActivity {
13 19  
14 20 @Override
15 21 protected void initView() {
16   - setOpenSwipBack(true);
17   - getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new MyFragment()).commitAllowingStateLoss();
  22 +// getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new MyFragment()).commitAllowingStateLoss();
  23 + initXiaoJiaSoundBoxData();
  24 + startActivity(new Intent(MyActivity.this,AllDeviceActivity.class));
18 25 }
19 26  
20 27 @Override
21 28 protected void initData() {
22 29 }
  30 +
  31 + /**
  32 + * 初始化小家音箱数据
  33 + */
  34 + private void initXiaoJiaSoundBoxData() {
  35 +// XiaoJIaCommInfo.setUserId(this, "10514333");
  36 +// XiaoJIaCommInfo.setUserPhone(this, "18301489586");
  37 + if (!TextUtils.isEmpty(UserService.getUid(this))) {
  38 + XiaoJIaCommInfo.setUserId(this, UserService.getUid(this));
  39 + }
  40 + if (null == UserService.getInstance(this).getAppAccount()) {
  41 + return;
  42 + }
  43 + if (null != UserService.getInstance(this).getAppAccount().getMobile() && !TextUtils.isEmpty(UserService.getInstance(this).getAppAccount().getMobile())) {
  44 + XiaoJIaCommInfo.setUserPhone(this, UserService.getInstance(this).getAppAccount().getMobile());
  45 + }
  46 + if (!TextUtils.isEmpty(UserService.getInstance(this).getAppAccount().getFaceUrl())) {
  47 + XiaoJIaCommInfo.setUserIcon(this, UserService.getInstance(this).getAppAccount().getFaceUrl());
  48 + }
  49 + if (!TextUtils.isEmpty(UserService.getInstance(this).getAppAccount().getNickName())) {
  50 + XiaoJIaCommInfo.setUserNickName(this, UserService.getInstance(this).getAppAccount().getNickName());
  51 + }
  52 + }
23 53 }
... ...
app/strike/src/main/java/com/cnlive/strike/MyFragment.java
... ... @@ -4,9 +4,7 @@ package com.cnlive.strike;
4 4 import android.Manifest;
5 5 import android.os.Bundle;
6 6 import android.util.Log;
7   -import android.view.LayoutInflater;
8 7 import android.view.View;
9   -import android.view.ViewGroup;
10 8 import android.widget.TextView;
11 9  
12 10 import com.cnlive.core.libs.base.frame.fragment.BaseFragment;
... ... @@ -15,13 +13,12 @@ import com.cnlive.core.network.BaseResult;
15 13 import com.cnlive.core.network.HttpConn;
16 14 import com.cnlive.core.network.NetCallBack;
17 15 import com.cnlive.core.libs.base.util.StatusBarConfig;
18   -import com.cnlive.strike.network.BaseRequest;
  16 +import com.cnlive.core.network.request.BaseRequest;
19 17 import com.cnlive.strike.network.api.ApiService;
20 18 import com.cnlive.strike.network.bean.LetHimNoSeeBean;
21 19 import com.cnlive.strike.network.bean.TestBean;
22   -
23   -import androidx.annotation.NonNull;
24   -import androidx.annotation.Nullable;
  20 +import com.me.yokeyword.fragmentation.anim.DefaultVerticalAnimator;
  21 +import com.me.yokeyword.fragmentation.anim.FragmentAnimator;
25 22  
26 23 import java.util.HashMap;
27 24 import java.util.Map;
... ... @@ -31,23 +28,21 @@ import io.reactivex.functions.Function;
31 28  
32 29  
33 30 public class MyFragment extends BaseFragment<MyFragmentView, MyPresenter> {
34   - private View view;
35 31 public TextView textView;
36 32  
37   - @Nullable
38 33 @Override
39   - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
40   - view = inflater.inflate(R.layout.activity_main1, container, false);
41   - textView = view.findViewById(R.id.tv1);
42   - return view;
  34 + protected int getViewLayoutId() {
  35 + return R.layout.activity_main1;
43 36 }
44 37  
45 38 @Override
46 39 protected void initView() {
47 40 super.initView();
  41 + setSwipeBackEnable(true);
48 42 setStatusBarColor(R.color.green, 0);
49 43 setStatusBarTextColor(StatusBarConfig.BLACK);
50   - view.findViewById(R.id.btn_test2).setOnClickListener(new View.OnClickListener() {
  44 + textView = baseView.findViewById(R.id.tv1);
  45 + baseView.findViewById(R.id.btn_test2).setOnClickListener(new View.OnClickListener() {
51 46 @Override
52 47 public void onClick(View v) {
53 48 requestPermission(010001, "测试", new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, new OnPermissionResponseListener() {
... ... @@ -63,23 +58,24 @@ public class MyFragment extends BaseFragment&lt;MyFragmentView, MyPresenter&gt; {
63 58 });
64 59 }
65 60 });
66   - view.findViewById(R.id.btn_test1).setOnClickListener(new View.OnClickListener() {
  61 + baseView.findViewById(R.id.btn_test1).setOnClickListener(new View.OnClickListener() {
67 62 @Override
68 63 public void onClick(View v) {
69   - requestPermission(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, new OnPermissionResponseListener() {
70   - @Override
71   - public void onSuccess(String[] permissions) {
72   - Log.e(TAG, "onSuccess: ");
73   - }
74   -
75   - @Override
76   - public void onFail() {
77   - Log.e(TAG, "onFail: ");
78   - }
79   - });
  64 +// requestPermission(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, new OnPermissionResponseListener() {
  65 +// @Override
  66 +// public void onSuccess(String[] permissions) {
  67 +// Log.e(TAG, "onSuccess: ");
  68 +// }
  69 +//
  70 +// @Override
  71 +// public void onFail() {
  72 +// Log.e(TAG, "onFail: ");
  73 +// }
  74 +// });
  75 + startForResult(new MyFragment1(),1001);
80 76 }
81 77 });
82   - view.findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() {
  78 + baseView.findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() {
83 79 @Override
84 80 public void onClick(View v) {
85 81 //单个请求
... ... @@ -144,4 +140,17 @@ public class MyFragment extends BaseFragment&lt;MyFragmentView, MyPresenter&gt; {
144 140 getPresenter().setData("hha");
145 141 getMvpView().setData("test");
146 142 }
  143 +
  144 + @Override
  145 + public FragmentAnimator onCreateFragmentAnimator() {
  146 + return new DefaultVerticalAnimator();
  147 + }
  148 +
  149 + @Override
  150 + public void onFragmentResult(int requestCode, int resultCode, Bundle data) {
  151 + super.onFragmentResult(requestCode, resultCode, data);
  152 + if (requestCode==1001){
  153 + setStatusBarColor(R.color.green,0);
  154 + }
  155 + }
147 156 }
... ...
app/strike/src/main/java/com/cnlive/strike/MyFragment1.java
1 1 package com.cnlive.strike;
2 2  
3 3  
4   -import android.os.Bundle;
5   -import android.view.LayoutInflater;
  4 +import android.util.Log;
6 5 import android.view.View;
7   -import android.view.ViewGroup;
8   -
9   -import androidx.annotation.NonNull;
10   -import androidx.annotation.Nullable;
11 6  
12 7 import com.cnlive.core.libs.base.frame.fragment.BaseFragment;
13 8 import com.cnlive.core.libs.base.util.StatusBarConfig;
  9 +import com.cnlive.core.network.HttpConn;
  10 +import com.cnlive.core.network.NetCallBack;
  11 +import com.cnlive.core.network.request.BaseRequest;
  12 +import com.cnlive.strike.network.api.ApiService;
  13 +import com.cnlive.strike.network.bean.TestBean;
14 14  
15 15  
16 16 public class MyFragment1 extends BaseFragment {
17   - private View view;
18 17  
19   - @Nullable
  18 +
20 19 @Override
21   - public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
22   - view = inflater.inflate(R.layout.fragment_main1, container, false);
23   - return view;
  20 + protected int getViewLayoutId() {
  21 + return R.layout.fragment_main1;
24 22 }
25 23  
26 24 @Override
... ... @@ -28,5 +26,33 @@ public class MyFragment1 extends BaseFragment {
28 26 super.initView();
29 27 setStatusBarColor(R.color.qmui_config_color_red, 0);
30 28 setStatusBarTextColor(StatusBarConfig.BLACK);
  29 + baseView.findViewById(R.id.btn_test).setOnClickListener(new View.OnClickListener() {
  30 + @Override
  31 + public void onClick(View v) {
  32 + //单个请求
  33 + HttpConn.action(
  34 + BaseRequest
  35 + .init()
  36 + .setUrl("http://gank.io/api/data/")
  37 + .service(ApiService.class)
  38 + .getTest(), new NetCallBack<TestBean>() {
  39 + @Override
  40 + public void onRequestState(int state) {
  41 +
  42 + }
  43 +
  44 + @Override
  45 + public void onSuccess(TestBean data) {
  46 + Log.e(TAG, "onSuccess: " + data.getResults().size());
  47 + }
  48 +
  49 + @Override
  50 + public void onFailure(String errCode, String errMsg) {
  51 + Log.e(TAG, "onFailure: " + errMsg);
  52 + }
  53 +
  54 + });
  55 + }
  56 + });
31 57 }
32 58 }
... ...
app/strike/src/main/java/com/cnlive/strike/demo/activity/DemoActivity.java
... ... @@ -7,7 +7,9 @@ import android.view.View;
7 7 import com.cnlive.core.libs.base.frame.activity.BaseActivity;
8 8 import com.cnlive.core.libs.base.interfaces.OnPermissionResponseListener;
9 9 import com.cnlive.core.libs.base.util.StatusBarConfig;
  10 +import com.cnlive.strike.MyFragment;
10 11 import com.cnlive.strike.R;
  12 +import com.cnlive.strike.base.BuildConfig;
11 13  
12 14 /**
13 15 * 继承BaseActivity
... ... @@ -19,10 +21,10 @@ public class DemoActivity extends BaseActivity {
19 21 *
20 22 * @return
21 23 */
22   - @Override
23   - protected int getViewLayoutId() {
24   - return R.layout.activity_demo_main;
25   - }
  24 +// @Override
  25 +// protected int getViewLayoutId() {
  26 +// return R.layout.activity_demo_main;
  27 +// }
26 28  
27 29 /**
28 30 * 设置binding布局
... ... @@ -30,16 +32,16 @@ public class DemoActivity extends BaseActivity {
30 32 *
31 33 * @return
32 34 */
33   - @Override
34   - protected int getBindLayoutId() {
35   - return super.getBindLayoutId();
36   - }
  35 +// @Override
  36 +// protected int getBindLayoutId() {
  37 +// return super.getBindLayoutId();
  38 +// }
37 39  
38   - @Override
39   - protected void initBindingData() {
40   - super.initBindingData();
41   -// binding=(你的bingding)baseBinding;
42   - }
  40 +// @Override
  41 +// protected void initBindingData() {
  42 +// super.initBindingData();
  43 +//// binding=(你的bingding)baseBinding;
  44 +// }
43 45  
44 46 /**
45 47 * 初始化intent传递参数
... ... @@ -55,8 +57,8 @@ public class DemoActivity extends BaseActivity {
55 57 @Override
56 58 protected void initView() {
57 59 super.initView();
58   - //是指是否可以侧滑返回,默认禁用
59   - setOpenSwipBack(true);
  60 + //是指是否可以侧滑返回,默认禁用d
  61 +// setSwipeBackEnable(true);
60 62 //设置状态栏字体颜色
61 63 setStatusBarTextColor(StatusBarConfig.WHITE);
62 64 //设置状态栏颜色
... ... @@ -75,6 +77,8 @@ public class DemoActivity extends BaseActivity {
75 77 //px2dp
76 78 px2dp(10);
77 79  
  80 + loadRootFragment(new MyFragment());
  81 +
78 82 // String[] permissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION,
79 83 // Manifest.permission.ACCESS_COARSE_LOCATION};
80 84 // //请求权限(默认提示语的)
... ... @@ -114,39 +118,30 @@ public class DemoActivity extends BaseActivity {
114 118 // }
115 119 // });
116 120  
117   - findViewById(R.id.go_to1).setOnClickListener(new View.OnClickListener() {
118   - @Override
119   - public void onClick(View v) {
120   - logError("Ada");
121   - requestPermission(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, new OnPermissionResponseListener() {
122   - @Override
123   - public void onSuccess(String[] permissions) {
124   - Log.e(TAG, "onSuccess: ");
125   - }
126   -
127   - @Override
128   - public void onFail() {
129   - Log.e(TAG, "onFail: ");
130   - }
131   - });
132   - }
133   - });
134   - findViewById(R.id.go_to2).setOnClickListener(new View.OnClickListener() {
135   - @Override
136   - public void onClick(View v) {
137   - requestPermission(10010, "拒绝我了", new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, new OnPermissionResponseListener() {
138   - @Override
139   - public void onSuccess(String[] permissions) {
140   - Log.e(TAG, "onSuccess: ");
141   - }
142   -
143   - @Override
144   - public void onFail() {
145   - Log.e(TAG, "onFail: ");
146   - }
147   - });
148   - }
149   - });
  121 +// findViewById(R.id.go_to1).setOnClickListener(new View.OnClickListener() {
  122 +// @Override
  123 +// public void onClick(View v) {
  124 +// logError("Ada");
  125 +// loadRootFragment(R.id.fl_container,new MyFragment());
  126 +//// start(new MyFragment());
  127 +// }
  128 +// });
  129 +// findViewById(R.id.go_to2).setOnClickListener(new View.OnClickListener() {
  130 +// @Override
  131 +// public void onClick(View v) {
  132 +// requestPermission(10010, "拒绝我了", new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, new OnPermissionResponseListener() {
  133 +// @Override
  134 +// public void onSuccess(String[] permissions) {
  135 +// Log.e(TAG, "onSuccess: ");
  136 +// }
  137 +//
  138 +// @Override
  139 +// public void onFail() {
  140 +// Log.e(TAG, "onFail: ");
  141 +// }
  142 +// });
  143 +// }
  144 +// });
150 145 }
151 146  
152 147 /**
... ... @@ -157,5 +152,4 @@ public class DemoActivity extends BaseActivity {
157 152 super.initData();
158 153 }
159 154  
160   -
161 155 }
... ...
app/strike/src/main/res/values/styles.xml
... ... @@ -2,6 +2,7 @@
2 2  
3 3 <!-- Base application theme. -->
4 4 <style name="AppTheme" parent="QMUI.Compat.NoActionBar">
  5 + <item name="android:windowIsTranslucent">true</item>
5 6 <!-- Customize your theme here. -->
6 7 <item name="colorPrimary">@color/colorPrimary</item>
7 8 <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
... ...
build.gradle
... ... @@ -14,7 +14,6 @@ buildscript {
14 14 }
15 15 dependencies {
16 16 classpath 'com.android.tools.build:gradle:3.5.1'
17   -
18 17 // NOTE: Do not place your application dependencies here; they belong
19 18 // in the individual module build.gradle files
20 19 classpath "com.alibaba:arouter-register:1.0.2"
... ... @@ -110,6 +109,7 @@ allprojects {
110 109  
111 110 //Tripartite Base
112 111 for (String moudle : base_librarys) imput('implementation', project, moudle)
  112 +// for (String moudle : base_librarys) imput('api', project, moudle)
113 113 for (String moudle : base_compilers) imput('annotationProcessor', project, moudle)
114 114  
115 115 }
... ... @@ -118,13 +118,37 @@ allprojects {
118 118 google()
119 119 jcenter()
120 120 maven {
121   - url mixedUrl
122   - credentials { username = mavenUsername; password = mavenPassword }
  121 + url maven.mixedUrl
  122 + credentials { username = nexusId; password = nexusPw }
  123 + }
  124 + //------------------ 资源库配置 END------------------
  125 + maven {
  126 + url 'https://dl.bintray.com/granzon/cnlive'
  127 + }
  128 + maven {
  129 + url 'https://dl.bintray.com/granzon/cnliveLibs'
  130 + }
  131 + maven {
  132 + url "https://jitpack.io"
  133 + }
  134 + maven {
  135 + url 'http://developer.huawei.com/repo'
123 136 }
124   - maven { url 'https://jitpack.io' }
125   - maven { url 'http://developer.huawei.com/repo' }
126 137 }
127 138 }
128 139 task clean(type: Delete) {
129 140 delete rootProject.buildDir
130 141 }
  142 +
  143 +//配置全局变量
  144 +ext {
  145 + libEmoj = '2.0.9'
  146 + libMediaPicker = '1.5.8'
  147 + // loading动画
  148 + avi = "2.1.3"
  149 + //蓝牙
  150 + BleLib="2.3.4"
  151 + //动画大全
  152 + viewAnimationsEasing='2.0@aar'
  153 + viewAnimationsAndroid='2.3@aar'
  154 +}
... ...
cloud/user/build.gradle
... ... @@ -46,7 +46,8 @@ dependencies {
46 46 androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
47 47  
48 48 implementation project(path: ':core:network')
49   -// implementation project(path: ':core:base')
  49 + implementation "com.cnlive.libs:emoj:$rootProject.libEmoj"
  50 + //图片选择器
  51 + implementation "com.cnlive.libs:mediapicker:$rootProject.libMediaPicker"
50 52  
51   - implementation 'com.cnlive.libs:emoj:2.0.9'
52 53 }
... ...
cloud/user/src/main/java/com/cnlive/strike/user/UserUtilAction.java
... ... @@ -7,17 +7,21 @@ import android.text.TextUtils;
7 7 import com.cnlive.core.libs.base.application.AppConfig;
8 8 import com.cnlive.core.network.BaseResult;
9 9 import com.cnlive.core.network.HttpConn;
10   -import com.cnlive.strike.user.network.api.ApiBaseServiceOpen;
11   -import com.cnlive.strike.user.network.api.BaseRequest;
12   -import com.cnlive.strike.user.network.model.TokenData;
13   -import com.cnlive.strike.user.network.model.UserData;
  10 +import com.cnlive.core.network.UserData;
  11 +import com.cnlive.core.network.api.ApiBaseServiceOpen;
  12 +import com.cnlive.core.network.request.BaseRequest;
  13 +import com.cnlive.core.network.FaceData;
  14 +import com.cnlive.core.network.TokenData;
14 15  
15 16 import java.io.File;
  17 +import java.util.ArrayList;
16 18 import java.util.HashMap;
  19 +import java.util.List;
17 20 import java.util.Map;
18 21  
19 22 import io.reactivex.Observable;
20 23 import okhttp3.MediaType;
  24 +import okhttp3.MultipartBody;
21 25 import okhttp3.RequestBody;
22 26  
23 27  
... ... @@ -239,35 +243,34 @@ public class UserUtilAction {
239 243 return BaseRequest.init().service(ApiBaseServiceOpen.class).accessToken(map);
240 244 }
241 245  
242   -// /**
243   -// * 上传头像
244   -// *
245   -// * @param context
246   -// * @param uid 用户ID
247   -// * @param face 头像文件
248   -// * @param token 平台TOKEN
249   -// * @param access_token
250   -// * @return
251   -// */
252   -// public static Disposable updateUserFace(Context context, String uid, File face, String token, String access_token, DataCallback<BaseInfo<FaceData>> callback) {
253   -// Map<String, RequestBody> params = new HashMap<>();
254   -//
255   -// if (TextUtils.isEmpty(token)) {
256   -// callback.callback(TOKEN_ERROR_CODE, TOKEN_ERROR_MSG, null);
257   -// }
258   -//
259   -// params.put("uid", getRequestString(uid));
260   -// params.put("clientPlat", getRequestString("a"));
261   -// params.put("token", getRequestString(token));
262   -// params.put("access_token", getRequestString(access_token));
263   -//
264   -// RequestBody requestFace = RequestBody.create(MediaType.parse("multipart/form-data"), face);
265   -// MultipartBody.Part faceBody = MultipartBody.Part.createFormData("face", face.getName(), requestFace);
266   -//
267   -// List<MultipartBody.Part> parts = new ArrayList<>();
268   -// parts.add(faceBody);
269   -//
270   -//
  246 + /**
  247 + * 上传头像
  248 + *
  249 + * @param context
  250 + * @param uid 用户ID
  251 + * @param face 头像文件
  252 + * @param token 平台TOKEN
  253 + * @param access_token
  254 + * @return
  255 + */
  256 + public static Observable<BaseResult<FaceData>> updateUserFace(Context context, String uid, File face, String token, String access_token) {
  257 + Map<String, RequestBody> params = new HashMap<>();
  258 +
  259 + if (TextUtils.isEmpty(token)) {
  260 + HttpConn.error(TOKEN_ERROR_CODE, TOKEN_ERROR_MSG);
  261 + }
  262 + params.put("uid", getRequestString(uid));
  263 + params.put("clientPlat", getRequestString("a"));
  264 + params.put("token", getRequestString(token));
  265 + params.put("access_token", getRequestString(access_token));
  266 +
  267 + RequestBody requestFace = RequestBody.create(MediaType.parse("multipart/form-data"), face);
  268 + MultipartBody.Part faceBody = MultipartBody.Part.createFormData("face", face.getName(), requestFace);
  269 +
  270 + List<MultipartBody.Part> parts = new ArrayList<>();
  271 + parts.add(faceBody);
  272 +
  273 +
271 274 // Subscriber<BaseInfo<FaceData>> subscriber = new Subscriber<BaseInfo<FaceData>>(context, ApiBaseSubscriber.subscriberBuild) {
272 275 // @Override
273 276 // public void onCompleted(String s, String s1, BaseInfo<FaceData> faceDataBaseInfo) {
... ... @@ -287,10 +290,11 @@ public class UserUtilAction {
287 290 // }
288 291 // }
289 292 // };
290   -//
291   -// return ApiBaseRequest.subscribe(ApiBaseRequest.service(ApiBaseServiceOpen.class).updateUserFace(params, parts), subscriber);
292   -//// return ApiBaseRequest.service(ApiBaseServiceOpen.class, service -> service.updateUserFace(params, parts)).subscribe(context, callback);
293   -// }
  293 +
  294 + return BaseRequest.init().service(ApiBaseServiceOpen.class).updateUserFace(params, parts);
  295 +// ApiBaseRequest.subscribe(ApiBaseRequest.service(ApiBaseServiceOpen.class).updateUserFace(params, parts), subscriber);
  296 +// return ApiBaseRequest.service(ApiBaseServiceOpen.class, service -> service.updateUserFace(params, parts)).subscribe(context, callback);
  297 + }
294 298  
295 299 private static RequestBody getRequestString(String value) {
296 300 RequestBody requestString = RequestBody.create(MediaType.parse("text/plain"), value);
... ...
cloud/user/src/main/java/com/cnlive/strike/user/auth/UserService.java
... ... @@ -13,7 +13,7 @@ import com.cnlive.core.libs.base.util.SharedPreferencesHelper;
13 13 import com.cnlive.strike.user.R;
14 14 import com.cnlive.strike.user.model.CNLiveUserInfo;
15 15 import com.cnlive.strike.user.model.CNLiveUserInfoExt;
16   -import com.cnlive.strike.user.network.model.UserData;
  16 +import com.cnlive.core.network.UserData;
17 17 import com.google.gson.Gson;
18 18  
19 19 import java.util.HashMap;
... ...
cloud/user/src/main/java/com/cnlive/strike/user/frame/data/LoginData.java deleted 100644 → 0
1   -package com.cnlive.strike.user.frame.data;
2   -
3   -import androidx.databinding.BaseObservable;
4   -import androidx.databinding.Bindable;
5   -
6   -import com.cnlive.core.network.HttpConn;
7   -import com.cnlive.core.network.NetCallBack;
8   -import com.cnlive.strike.user.BR;
9   -
10   -import static android.view.View.GONE;
11   -import static android.view.View.VISIBLE;
12   -
13   -/**
14   - * Created by xiansong on 2018/1/2.
15   - */
16   -@Deprecated
17   -public class LoginData extends BaseObservable implements NetCallBack {
18   - private String name = "";
19   - private String password = "";
20   - private int loadVisibility = GONE;
21   -
22   - @Bindable
23   - public String getName() {
24   - return name;
25   - }
26   -
27   - public void setName(String name) {
28   - this.name = name;
29   - notifyPropertyChanged(BR.name);
30   - }
31   -
32   - @Bindable
33   - public String getPassword() {
34   - return password;
35   - }
36   -
37   - public void setPassword(String password) {
38   - this.password = password;
39   - notifyPropertyChanged(BR.password);
40   - }
41   -
42   - @Bindable
43   - public int getLoadVisibility() {
44   - return loadVisibility;
45   - }
46   -
47   - public void setLoadVisibility(int loadVisibility) {
48   - this.loadVisibility = loadVisibility;
49   - notifyPropertyChanged(BR.loadVisibility);
50   - }
51   -
52   -// @Override
53   -// public void onState(int state) {
54   -// loadVisibility = state == Config.STATE_LOAD ? VISIBLE : GONE;
55   -// }
56   -
57   - @Override
58   - public void onRequestState(int state) {
59   - loadVisibility = state == HttpConn.ON_START ? VISIBLE : GONE;
60   - }
61   -
62   - @Override
63   - public void onSuccess(Object data) {
64   -
65   - }
66   -
67   - @Override
68   - public void onFailure(String errCode, String errMsg) {
69   -
70   - }
71   -}
cloud/user/src/main/java/com/cnlive/strike/user/frame/presenter/FirstLoginPresenter.java
... ... @@ -11,11 +11,15 @@ import com.cnlive.strike.user.R;
11 11 import com.cnlive.strike.user.UserUtilAction;
12 12 import com.cnlive.strike.user.auth.UserService;
13 13 import com.cnlive.strike.user.frame.view.FirstLoginView;
14   -import com.cnlive.strike.user.network.model.UserData;
  14 +import com.cnlive.core.network.FaceData;
  15 +import com.cnlive.core.network.TokenData;
  16 +import com.cnlive.core.network.UserData;
  17 +import com.cnlive.strike.user.router.user.UserOfflineUtil;
15 18  
16 19 import java.io.File;
17 20  
18 21 import io.reactivex.ObservableSource;
  22 +import io.reactivex.disposables.Disposable;
19 23 import io.reactivex.functions.Function;
20 24  
21 25  
... ... @@ -24,6 +28,7 @@ import io.reactivex.functions.Function;
24 28 */
25 29  
26 30 public class FirstLoginPresenter extends BasePresenter<FirstLoginView> {
  31 + private Disposable updateFaceEvent;
27 32  
28 33 public void loadUserInfo(Context context) {
29 34 UserService userService = UserService.getInstance(context);
... ... @@ -112,52 +117,60 @@ public class FirstLoginPresenter extends BasePresenter&lt;FirstLoginView&gt; {
112 117 );
113 118 }
114 119  
115   -// public void uploadFile(Context context, String filePath) {
116   -// if (updateFaceEvent != null) updateFaceEvent.cencel();
117   -// if (getView() == null) return;
118   -// getView().showProgress(R.string.upload_image_dialog);
119   -// File file = new File(filePath);
120   -// UserService userService = UserService.getInstance(context);
121   -// if (file.exists()) {
122   -//
123   -// updateFaceEvent = Logic.create()
124   -// .action(UserUtilAction.accessToken(context))
125   -// .action((BaseInfo<TokenData> data, DataCallback<BaseInfo<FaceData>> callback) -> {
126   -// UserUtilAction.updateUserFace(context, UserService.getUid(context), file, userService.getAppAccount().getToken(), data.getData().getAccess_token(), callback);
127   -// return null;
128   -// })
129   -// .<BaseInfo<FaceData>>event()
130   -// .setStateCallback(state -> {
131   -// if (getView() == null) return;
132   -// if (state == STATE_LOAD) {
133   -//
134   -// } else if (state == STATE_IDLE) {
135   -// getView().hideProgress();
136   -// }
137   -// })
138   -// .setFailureCallback((state, message) -> {
139   -// if (getView() == null) return;
140   -// if (state == 8 || state == 9) {
141   -//// UserOfflineUtil.userInvalid(context);
142   -// HelperUtil.userInvalid(context);
143   -// } else if (state == UserUtilAction.TOKEN_ERROR_CODE) {
144   -// getView().showTokenErrorDialog();
145   -// } else {
146   -// getView().showToast(message);
147   -// }
148   -// })
149   -// .setSuccessCallback(data -> {
150   -// HelperUtil.modifyUserImage(context, data.getData().getFaceUrl());
151   -//// LoginManager.modifyUserImage( UserService.getUid(context), data.getData().getFaceUrl());
152   -// userService.setUserFaceUrl(data.getData().getFaceUrl(), data.getData().getBigFaceUrl());
153   -// if (getView() == null) return;
154   -// getView().photoChange(data.getData().getFaceUrl());
155   -// })
156   -// .start();
157   -// } else {
158   -// if (getView() != null) getView().showToast("文件不存在");
159   -// }
160   -// }
  120 + public void uploadFile(Context context, String filePath) {
  121 + if (updateFaceEvent != null) {
  122 + updateFaceEvent.dispose();
  123 + updateFaceEvent = null;
  124 + }
  125 + ifViewAttached(view -> view.showProgress(R.string.upload_image_dialog));
  126 + File file = new File(filePath);
  127 + UserService userService = UserService.getInstance(context);
  128 + if (file.exists()) {
  129 + updateFaceEvent =
  130 + HttpConn.action(
  131 + UserUtilAction.accessToken(context)
  132 + .concatMap(new Function<BaseResult<TokenData>, ObservableSource<BaseResult<FaceData>>>() {
  133 + @Override
  134 + public ObservableSource<BaseResult<FaceData>> apply(BaseResult<TokenData> tokenDataBaseResult) throws Exception {
  135 + if (tokenDataBaseResult.isSuccess()) {
  136 + return UserUtilAction.updateUserFace(context, UserService.getUid(context), file, userService.getAppAccount().getToken(), tokenDataBaseResult.getData().getAccess_token());
  137 + }
  138 + return HttpConn.error(tokenDataBaseResult);
  139 + }
  140 + }), new NetCallBack<BaseResult<FaceData>>() {
  141 + @Override
  142 + public void onRequestState(int state) {
  143 + if (HttpConn.ON_END == state) {
  144 + ifViewAttached(view -> view.hideProgress());
  145 + }
  146 + }
  147 +
  148 + @Override
  149 + public void onSuccess(BaseResult<FaceData> data) {
  150 +// HelperUtil.modifyUserImage(context, data.getData().getFaceUrl());
  151 +// LoginManager.modifyUserImage( UserService.getUid(context), data.getData().getFaceUrl());
  152 + userService.setUserFaceUrl(data.getData().getFaceUrl(), data.getData().getBigFaceUrl());
  153 + ifViewAttached(view -> view.photoChange(data.getData().getFaceUrl()));
  154 + }
  155 +
  156 + @Override
  157 + public void onFailure(String errCode, String errMsg) {
  158 + if ("8".equals(errCode) || "9".equals(errCode)) {
  159 + UserOfflineUtil.userInvalid(context);
  160 +// HelperUtil.userInvalid(context);
  161 + } else if (UserUtilAction.TOKEN_ERROR_CODE.equals(errCode)) {
  162 + ifViewAttached(view -> view.showTokenErrorDialog());
  163 + } else {
  164 + ifViewAttached(view -> view.showToast(errMsg));
  165 + }
  166 + }
  167 + }
  168 + );
  169 +
  170 + } else {
  171 + ifViewAttached(view -> view.showToast("文件不存在"));
  172 + }
  173 + }
161 174  
162 175 }
163 176  
... ...
cloud/user/src/main/java/com/cnlive/strike/user/frame/presenter/QuickLoginPresenter.java
... ... @@ -39,19 +39,18 @@ import io.reactivex.disposables.Disposable;
39 39 public class QuickLoginPresenter extends BasePresenter<QuickLoginView> {
40 40 private TimerUtil timerUtil; //计时工具类
41 41  
42   - // private Event<CNLiveUserInfo> event;
  42 + private Disposable event;
43 43 private Disposable sendMsgBefQuickLogin;
44 44 // private Event otherEvent;
45 45  
46 46 public void deleteUserInfo(Context context, String userName) {
47 47 UserService.getInstance(context).removeUser(userName, future -> {
48   - if (getView() == null) return;
49 48 //获取已登录用户列表
50 49 Account[] accounts = UserService.getInstance(context).getUserList();
51 50 //倒序输出最近登录用户
52 51  
53 52 Collections.reverse(Arrays.asList(accounts));
54   - getView().uploadListData(accounts);
  53 + ifViewAttached(view -> view.uploadListData(accounts));
55 54 });
56 55 }
57 56  
... ... @@ -67,10 +66,10 @@ public class QuickLoginPresenter extends BasePresenter&lt;QuickLoginView&gt; {
67 66 String name = account == null ? "" : account.name;
68 67 //页面填充数据
69 68 if (!TextUtils.isEmpty(name)) {
70   - getView().uploadInputData(name);
  69 + ifViewAttached(view -> view.uploadInputData(name));
71 70 }
72 71 if (null != accounts) {
73   - getView().uploadListData(accounts);
  72 + ifViewAttached(view -> view.uploadListData(accounts));
74 73 }
75 74 }
76 75  
... ... @@ -84,29 +83,28 @@ public class QuickLoginPresenter extends BasePresenter&lt;QuickLoginView&gt; {
84 83 timerUtil.setTimerLiener(new TimerUtil.TimeListener() {
85 84 @Override
86 85 public void onFinish() {
87   - if (getView() != null) getView().onTimerFinish();
  86 + ifViewAttached(view -> view.onTimerFinish());
88 87 }
89 88  
90 89 @Override
91 90 public void onInterval(long remainTime) {
92   - if (getView() != null) getView().onTimerInterval(remainTime / 1000);
  91 + ifViewAttached(view -> view.onTimerInterval(remainTime / 1000));
93 92 }
94 93 });
95 94 }
96 95  
97 96 public void sendCode(Context context, String phone, String countryCode) {
98   - if (getView() == null) return;
99 97 if (TimeEvent.debounce(2_000)) return;
100 98 if (TextUtils.isEmpty(phone)) {
101   - getView().showToast(context.getString(R.string.user_toast_quick_login_empty_phone));
  99 + ifViewAttached(view -> view.showToast(context.getString(R.string.user_toast_quick_login_empty_phone)));
102 100 return;
103 101 }
104 102 if ("86".equals(countryCode) && !RegexUtils.isMobileSimple(phone)) {
105   - getView().showToast(context.getString(R.string.user_toast_quick_login_error_phone));
  103 + ifViewAttached(view -> view.showToast(context.getString(R.string.user_toast_quick_login_error_phone)));
106 104 return;
107 105 }
108 106 if (sendMsgBefQuickLogin != null && !sendMsgBefQuickLogin.isDisposed()) {
109   - getView().showToast("处理中请稍后...");
  107 + ifViewAttached(view -> view.showToast("处理中请稍后..."));
110 108 } else {
111 109 sendMsgBefQuickLogin = HttpConn.action(UserUtilAction.sendMsgBefQuickLoginAction(context, phone, countryCode), new NetCallBack<BaseResult>() {
112 110 @Override
... ... @@ -137,7 +135,7 @@ public class QuickLoginPresenter extends BasePresenter&lt;QuickLoginView&gt; {
137 135 } else {
138 136 context.isLogin = true;
139 137 // UserAction.mobileLogin(context.getActivity(), data.getPhone(), data.getCode(), countryCode, initLoginEvent(context, true));
140   - UserAction.mobileLogin(context.getActivity(), data.getPhone(), data.getCode(), countryCode, new UserAction.CallBack() {
  138 + event = UserAction.mobileLogin(context.getActivity(), data.getPhone(), data.getCode(), countryCode, new UserAction.CallBack() {
141 139 @Override
142 140 public void callback(int state, String msg, Object object) {
143 141 initLoginEvent(context, state, msg, true, null);
... ... @@ -229,7 +227,7 @@ public class QuickLoginPresenter extends BasePresenter&lt;QuickLoginView&gt; {
229 227 // }
230 228  
231 229  
232   -//
  230 + //
233 231 // private Event<CNLiveUserInfo> initLoginEvent(QuickLoginFragment context, Boolean retry, OtherUserInfo otherUserInfo) {
234 232 // return event = new Event<CNLiveUserInfo>()
235 233 // .setStateCallback(state -> {
... ... @@ -304,5 +302,12 @@ public class QuickLoginPresenter extends BasePresenter&lt;QuickLoginView&gt; {
304 302 // if (context != null) context.isLogin = false;
305 303 // });
306 304 // }
307   -
  305 + public void cancelLoad() {
  306 + if (event != null) {
  307 + if (!event.isDisposed()) {
  308 + event.dispose();
  309 + }
  310 + event = null;
  311 + }
  312 + }
308 313 }
... ...
cloud/user/src/main/java/com/cnlive/strike/user/frame/view/FirstLoginView.java
... ... @@ -63,8 +63,6 @@ public class FirstLoginView extends BaseView {
63 63 successInfo.setTagMsg(fragment.tagMsg);
64 64 EventBus.getDefault().post(new UserEventMsg(UserEventMsg.LOGIN_SUCCESS, successInfo));
65 65  
66   -
67   -
68 66 // Intent intent = new Intent(getContext(), MainTestActivity.class);
69 67 // if (!TextUtils.isEmpty(fragment.tagMsg))
70 68 // intent.putExtra("classifyTagMsg", fragment.tagMsg);
... ...
cloud/user/src/main/java/com/cnlive/strike/user/router/user/UserAction.java
... ... @@ -5,21 +5,17 @@ import android.app.Activity;
5 5 import android.content.Context;
6 6 import android.net.Uri;
7 7 import android.text.TextUtils;
8   -import android.util.Log;
9 8  
10 9 import com.cnlive.core.network.BaseResult;
11 10 import com.cnlive.core.network.HttpConn;
12 11 import com.cnlive.core.network.NetCallBack;
13   -import com.cnlive.core.network.ServerException;
  12 +import com.cnlive.core.network.UserData;
14 13 import com.cnlive.strike.user.UserUtilAction;
15 14 import com.cnlive.strike.user.auth.UserService;
16 15 import com.cnlive.strike.user.model.CNLiveUserInfo;
17   -import com.cnlive.strike.user.network.api.BaseRequest;
18   -import com.cnlive.strike.user.network.model.UserData;
19 16  
20 17 import io.reactivex.Observable;
21   -import io.reactivex.ObservableSource;
22   -import io.reactivex.functions.Function;
  18 +import io.reactivex.disposables.Disposable;
23 19  
24 20  
25 21 public class UserAction {
... ... @@ -49,13 +45,13 @@ public class UserAction {
49 45 // .start(event);
50 46 // }
51 47  
52   - public static void mobileLogin(Context context, String phone, String code, String countryCode, CallBack callBack) {
  48 + public static Disposable mobileLogin(Context context, String phone, String code, String countryCode, CallBack callBack) {
53 49 // Logic.create()
54 50 // .action(UserUtilAction.quickLoginAction(context, phone, code, countryCode))
55 51 // .action(loginAppAction(context, phone, code))
56 52 //// .action(loginIMAction())
57 53 // .start(event);
58   - HttpConn.action(
  54 + return HttpConn.action(
59 55 UserUtilAction.quickLoginAction(context, phone, code, countryCode)
60 56 , new NetCallBack<BaseResult<UserData>>() {
61 57 @Override
... ... @@ -86,7 +82,7 @@ public class UserAction {
86 82 if (null != callBack) {
87 83 callBack.callback(-5, "获取账户信息失败 请重试.", null);
88 84 }
89   - } else if (TextUtils.isEmpty(data.getData().getMobile())) {
  85 + } else if (TextUtils.isEmpty(data.getData().getMobile())) {
90 86 callBack.callback(-5, "绑定手机号已失效..", null);
91 87 } else {
92 88 //更新登录用户信息
... ...
cloud/user/src/main/java/com/cnlive/strike/user/router/user/UserOfflineUtil.java
... ... @@ -5,9 +5,14 @@ import android.content.Context;
5 5  
6 6 import androidx.appcompat.app.AppCompatActivity;
7 7  
  8 +import com.cnlive.core.libs.base.ui.widget.BottomSheet;
8 9 import com.cnlive.core.libs.base.util.AlertUtil;
  10 +import com.cnlive.core.libs.base.util.AppManager;
9 11 import com.cnlive.strike.user.auth.UserService;
  12 +import com.cnlive.strike.user.ui.activity.LoginActivity;
10 13 import com.kongzue.dialog.interfaces.OnMenuItemClickListener;
  14 +import com.kongzue.dialog.util.DialogSettings;
  15 +import com.kongzue.dialog.util.TextInfo;
11 16 import com.kongzue.dialog.v3.BottomMenu;
12 17  
13 18 import org.greenrobot.eventbus.EventBus;
... ... @@ -37,40 +42,44 @@ public class UserOfflineUtil {
37 42 }
38 43  
39 44 public static void userInvalid(Context context) {
40   - AlertUtil.showDeftToast(context, "用户 已失效.");
  45 + AlertUtil.showDeftToast(context, "用户已失效.");
41 46 appLogout(context);
42 47 }
43 48  
44 49 //todo BottomSheet
45 50 public static void logout(Context context) {
46   -
47   - BottomMenu.show((AppCompatActivity) context, new String[]{"菜单1", "菜单2", "菜单3"}, new OnMenuItemClickListener() {
48   - @Override
49   - public void onClick(String text, int index) {
50   - //返回参数 text 即菜单名称,index 即菜单索引
51   - }
52   - });
53   -// new BottomSheet.BottomListSheetBuilder(context)
54   -// .addItem("退出登录", "", true)
55   -// .addItem("取消")
56   -// .setOnSheetItemClickListener((dialog, itemView, position, tag) -> {
57   -// switch (position) {
58   -// case 0:
59   -// appLogout(context);
60   -// break;
61   -// }
62   -// dialog.dismiss(false);
63   -// }).build().show();
  51 + DialogSettings.style = (DialogSettings.STYLE.STYLE_IOS);
  52 + TextInfo textInfo = new TextInfo();
  53 + textInfo.setFontSize(15);
  54 + DialogSettings.menuTextInfo = textInfo;
  55 +// BottomMenu.show((AppCompatActivity) context, new String[]{"退出登录"}, new OnMenuItemClickListener() {
  56 +// @Override
  57 +// public void onClick(String text, int index) {
  58 +// //返回参数 text 即菜单名称,index 即菜单索引
  59 +// }
  60 +// }).setCancelable(false);
  61 + new BottomSheet.BottomListSheetBuilder(context)
  62 + .addItem("退出登录", "", true)
  63 + .addItem("取消")
  64 + .setOnSheetItemClickListener((dialog, itemView, position, tag) -> {
  65 + switch (position) {
  66 + case 0:
  67 + appLogout(context);
  68 + break;
  69 + }
  70 + dialog.dismiss(false);
  71 + }).build().show();
64 72 }
65 73  
66 74 public static void appLogout(Context context) {
67 75 String uid = UserService.getUid(context);
68 76 UserService.getInstance(context).logoutAppAccount();
69 77 //退出登录
70   -
  78 + AppManager.getInstance().killAllActivity();
  79 + LoginActivity.start(context);
71 80 // LoginManager.logout(uid, null, context);
72 81 // if (ActivityLifecycle.isActive()) {
73   -// LoginActivity.start(context);
  82 +
74 83 // } else {
75 84 // Log.e("FinishAllActivity", "FinishAllActivity-----logout");
76 85 // FinishAllActivity.finish(context);
... ...
cloud/user/src/main/java/com/cnlive/strike/user/ui/activity/LoginActivity.java
... ... @@ -19,8 +19,11 @@ import com.cnlive.strike.user.ui.fragment.QuickLoginFragment;
19 19 * @author Lynn
20 20 * @date 2017/12/22
21 21 */
22   -@Route(path = "/cnmain/LoginActivity")
  22 +//@Route(path = "/cnmain/LoginActivity")
  23 +@Route(path = LoginActivity.PATH)
23 24 public class LoginActivity extends BaseActivity {
  25 + public static final String PATH = "/cloud/user/ui/activity/login";
  26 +
24 27 public static String FROM_TOKEN_ERROR = "from_token_error";
25 28 public static String TAG_MSG = "tagMsg";
26 29 public static String TAG_SHARE = "tagValue";
... ...
cloud/user/src/main/java/com/cnlive/strike/user/ui/fragment/FirstLoginFragment.java
... ... @@ -5,6 +5,7 @@ import android.app.Activity;
5 5 import android.app.Dialog;
6 6 import android.app.ProgressDialog;
7 7 import android.content.Intent;
  8 +import android.os.Environment;
8 9 import android.text.Editable;
9 10 import android.text.TextUtils;
10 11 import android.text.TextWatcher;
... ... @@ -14,9 +15,13 @@ import androidx.annotation.NonNull;
14 15 import androidx.appcompat.app.AppCompatActivity;
15 16  
16 17 import com.cnlive.core.libs.base.frame.fragment.BaseFragment;
  18 +import com.cnlive.core.libs.base.interfaces.OnPermissionResponseListener;
17 19 import com.cnlive.core.libs.base.util.AlertUtil;
18 20 import com.cnlive.core.libs.base.util.GlideUtil;
19 21 import com.cnlive.core.libs.base.util.StatusBarConfig;
  22 +import com.cnlive.media.picker.ImagePicker;
  23 +import com.cnlive.media.picker.PickerConfig;
  24 +import com.cnlive.media.picker.entity.Media;
20 25 import com.cnlive.strike.user.R;
21 26 import com.cnlive.strike.user.auth.UserService;
22 27 import com.cnlive.strike.user.databinding.FragmentFirstLoginBinding;
... ... @@ -28,6 +33,10 @@ import com.cnlive.strike.user.router.user.UserOfflineUtil;
28 33 import com.cnlive.strike.user.ui.activity.FirstLoginActivity;
29 34 import com.cnlive.strike.user.ui.activity.LoginActivity;
30 35  
  36 +import java.util.List;
  37 +
  38 +import static com.cnlive.media.picker.ui.PickerActivity.REQUEST_CODE_PERMISSION_CAMERA;
  39 +
31 40  
32 41 /**
33 42 * Created by xiansong on 2018/1/19.
... ... @@ -128,31 +137,37 @@ public class FirstLoginFragment extends BaseFragment&lt;FirstLoginView, FirstLoginP
128 137  
129 138  
130 139 public void selectPhoto(boolean fromResult) {
131   -// boolean hasPermission = fromResult ? AppUtil.checkPermissions(getActivity(), PERMISSION) : PermissionChecker.checkPermissions(getActivity()
132   -// , PERMISSION, REQUEST_CODE_PERMISSION_CAMERA, com.cnlive.media.picker.R.string.dialog_imagepicker_permission_sdcard_message);
133   -//
134   -// if (hasPermission) {
135   -// ImagePicker imagePicker = new ImagePicker.Builder()
136   -// //最大选择图片数目,默认40张
137   -// .maxNum(1)
138   -// .setSelectGif(false)
139   -// //是否需要相机(默认false)
140   -// .needCamera(true)
141   -// //选择模式(默认PICKER_IMAGE_VIDEO) PICKER_IMAGE-->图片 PICKER_VIDEO-->视频 PICKER_IMAGE_VIDEO-->图片&视频
142   -// .selectMode(PickerConfig.PICKER_IMAGE)
143   -// //拍照或录像存储位置 默认Environment.getExternalStorageDirectory().getPath() + File.separator + "JCamera"
144   -// .cachePath(Environment.getExternalStorageDirectory() + "/strike/file/")
145   -// //是否为发朋友圈模式(默认false) true-->图片与视频不能同时选择
146   -// .isFriendCircle(false)
147   -// //裁剪 只有在单选模式下才可以使用
148   -// .doCrop(1, 1, 300, 300)
149   -// //是否开启单选模式(默认false)
150   -// .isSinglePick(true)
151   -// .builder();
152   -//
153   -// //跳转到图片选择页面 activity 请求码 结果码
154   -// imagePicker.start(getActivity(), PickerConfig.PICKER_IMAGE, PickerConfig.DEFAULT_RESULT_CODE);
155   -// }
  140 + requestPermission(REQUEST_CODE_PERMISSION_CAMERA,
  141 + R.string.dialog_imagepicker_permission_sdcard_message,
  142 + PERMISSION, new OnPermissionResponseListener() {
  143 + @Override
  144 + public void onSuccess(String[] permissions) {
  145 + ImagePicker imagePicker = new ImagePicker.Builder()
  146 + //最大选择图片数目,默认40张
  147 + .maxNum(1)
  148 + .setSelectGif(false)
  149 + //是否需要相机(默认false)
  150 + .needCamera(true)
  151 + //选择模式(默认PICKER_IMAGE_VIDEO) PICKER_IMAGE-->图片 PICKER_VIDEO-->视频 PICKER_IMAGE_VIDEO-->图片&视频
  152 + .selectMode(PickerConfig.PICKER_IMAGE)
  153 + //拍照或录像存储位置 默认Environment.getExternalStorageDirectory().getPath() + File.separator + "JCamera"
  154 + .cachePath(Environment.getExternalStorageDirectory() + "/strike/file/")
  155 + //是否为发朋友圈模式(默认false) true-->图片与视频不能同时选择
  156 + .isFriendCircle(false)
  157 + //裁剪 只有在单选模式下才可以使用
  158 + .doCrop(1, 1, 300, 300)
  159 + //是否开启单选模式(默认false)
  160 + .isSinglePick(true)
  161 + .builder();
  162 + //跳转到图片选择页面 activity 请求码 结果码
  163 + imagePicker.start(getActivity(), PickerConfig.PICKER_IMAGE, PickerConfig.DEFAULT_RESULT_CODE);
  164 + }
  165 +
  166 + @Override
  167 + public void onFail() {
  168 +
  169 + }
  170 + });
156 171  
157 172 }
158 173  
... ... @@ -163,31 +178,17 @@ public class FirstLoginFragment extends BaseFragment&lt;FirstLoginView, FirstLoginP
163 178 if (tokenErrorDialog != null) tokenErrorDialog.dismiss();
164 179 }
165 180  
166   - @Override
167   - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
168   - super.onRequestPermissionsResult(requestCode, permissions, grantResults);
169   - Activity activity = getActivity();
170   - if (activity == null) return;
171   -// if (requestCode == REQUEST_CODE_PERMISSION_CAMERA) {
172   -// boolean hasPermission = PermissionChecker.onRequestPermissionsResult(
173   -// activity, requestCode, permissions, grantResults, false,
174   -// com.cnlive.media.picker.R.string.dialog_imagepicker_permission_sdcard_message)[0];
175   -// if (hasPermission) {
176   -// selectPhoto(true);
177   -// }
178   -// }
179   - }
180 181  
181 182 @Override
182 183 public void onActivityResult(int requestCode, int resultCode, Intent data) {
183 184 super.onActivityResult(requestCode, resultCode, data);
184   -// if (resultCode == PickerConfig.DEFAULT_RESULT_CODE) {
185   -// List<Media> list = data.getParcelableArrayListExtra(PickerConfig.EXTRA_RESULT);
186   -// if (list == null) return;
187   -// if (getPresenter() == null) return;
188   -// if (list.size() > 0 && list.get(0) != null && !TextUtils.isEmpty(list.get(0).path))
189   -// getPresenter().uploadFile(FirstLoginFragment.this.getActivity(), list.get(0).path);
190   -//
191   -// }
  185 + if (resultCode == PickerConfig.DEFAULT_RESULT_CODE) {
  186 + List<Media> list = data.getParcelableArrayListExtra(PickerConfig.EXTRA_RESULT);
  187 + if (list == null) return;
  188 + if (getPresenter() == null) return;
  189 + if (list.size() > 0 && list.get(0) != null && !TextUtils.isEmpty(list.get(0).path))
  190 + getPresenter().uploadFile(FirstLoginFragment.this.getActivity(), list.get(0).path);
  191 +
  192 + }
192 193 }
193 194 }
... ...
cloud/user/src/main/java/com/cnlive/strike/user/ui/fragment/QuickLoginFragment.java
... ... @@ -114,7 +114,7 @@ public class QuickLoginFragment extends BaseFragment&lt;QuickLoginView, QuickLoginP
114 114 mProgressDialog.setMessage(getResources().getString(R.string.login_dialog));
115 115 mProgressDialog.setCanceledOnTouchOutside(false);
116 116 mProgressDialog.setOnCancelListener(dialog -> {
117   -// getPresenter().cancelLoad();
  117 + getPresenter().cancelLoad();
118 118 });
119 119 getMvpView().setAgreementText();
120 120 binding.setClickListener(v -> onClick(v.getId()));
... ...
config.gradle
1 1 ext {
2   - mixedUrl = "http://android.nexus.cnlive.com/repository/cnlive-mixed/"
3   - mavenUsername = "developer"
4   - mavenPassword = "android_2019"
  2 + //Nexus 访问账号
  3 + nexusId = "developer"
  4 + nexusPw = "android_2019"
5 5  
6 6 //Nexus 发布配置
7 7 maven = [
... ... @@ -25,7 +25,7 @@ ext {
25 25 ]
26 26  
27 27 androidx = [
28   - appcompat : "androidx.appcompat:appcompat:1.1.0+",
  28 + appcompat : "androidx.appcompat:appcompat:1.1.0",
29 29 constraintlayout: "androidx.constraintlayout:constraintlayout:1.1.3",
30 30 multidex : "androidx.multidex:multidex:2.0.1"
31 31 ]
... ... @@ -46,17 +46,34 @@ ext {
46 46 espresso: 'androidx.test.espresso:espresso-core:3.2.0'
47 47 ]
48 48  
  49 + //Maven Base库配置
  50 + moudle_cnlive_base = [
  51 + //编译方式
  52 + debug : false,
  53 + //版本号
  54 + version: "0.0.2",
  55 + //Lib库前缀
  56 + packeg : "com.cnlive.core",
  57 + //Lib库名称
  58 + name : "base"
  59 + ]
49 60 library = [
  61 +
  62 + //fragment滑动返回( https://github.com/YoKeyword/Fragmentation ,源码导入修改)
  63 + fragmentation_swipeback : 'me.yokeyword:fragmentationx-swipeback:1.0.2',
  64 + //对fragment进行管理( https://github.com/YoKeyword/Fragmentation ,源码导入修改)
  65 + fragmentationx : 'me.yokeyword:fragmentationx:1.0.2',
  66 + //log日志
50 67 logger : 'com.orhanobut:logger:2.2.0',
51   -// //空祖对话框 https://github.com/kongzue/DialogV3
52   -// kongzueDailog : 'com.kongzue.dialog_v3x:dialog:3.1.6',
  68 + //空祖对话框 https://github.com/kongzue/DialogV3 (源码导入,修改)
  69 + kongzueDailog : 'com.kongzue.dialog_v3x:dialog:3.1.6',
53 70 //视讯云加密
54 71 libCnencipher : 'com.cnlive:lib-cnencipher:1.1.1',
55 72 //视频库
56 73 libVideoQiniu : 'com.cnlive.libs:video_qiniu:1.0.6',
57 74 //视讯云播放器
58 75 libCnVideo : 'com.cnlive:lib_cnvideo2.0:3.3.11',
59   - //权限
  76 +// //权限
60 77 easypermissions : 'pub.devrel:easypermissions:1.0.0',
61 78 //MVP
62 79 mvp : 'com.hannesdorfmann.mosby3:mvp:3.0.4',
... ... @@ -96,14 +113,9 @@ ext {
96 113 cardviewV7 : 'com.android.support:cardview-v7:28.0.0',
97 114 dataBinding : 'com.android.databinding.library:3.5.1'
98 115 ]
99   -// library_jar = [
100   -// pinyin4j: ('libs/pinyin4j-2.5.0.jar')
101   -// ]
102 116 //基础三方库
103 117 base_librarys = [
104 118 library.logger,
105   - //对话框
106   -// library.kongzueDailog,
107 119 //视讯云加密库
108 120 library.libCnencipher,
109 121 //视频库
... ... @@ -125,14 +137,6 @@ ext {
125 137 //图片加载Glide
126 138 glide.api,
127 139 glide.transformations,
128   - //兼容旧版
129   -// library.supportV4,
130   -// library.appcompatV7,
131   -// library.design,
132   -// library.supportV13,
133   -// library.recyclerviewV7,
134   -// library.cardviewV7,
135   -// library.dataBinding,
136 140 //使用androidx
137 141 androidx.appcompat,
138 142 androidx.constraintlayout,
... ... @@ -145,11 +149,9 @@ ext {
145 149 library.retrofitAdapterRxjava2,
146 150 library.okhttp,
147 151 library.okhttpLoggingInterceptor,
  152 + //数据库
148 153 library.greendao,
149   - //管理rxjava生命周期
150   -// library.rx
151 154 router.api,
152   -
153 155 test.junit,
154 156 test.runner,
155 157 test.espresso
... ... @@ -162,10 +164,6 @@ ext {
162 164 router.compiler
163 165 ]
164 166  
165   -// base_jar = [
166   -// library_jar.pinyin4j
167   -// ]
168   -
169 167 //正式签名配置
170 168 Properties properties = new Properties()
171 169 properties.load(project.rootProject.file('local.properties').newDataInputStream())
... ...
core/base/base_maven_push.gradle 0 → 100644
  1 +apply plugin: 'maven'
  2 +
  3 +uploadArchives() {
  4 + repositories {
  5 + mavenDeployer {
  6 + def lib = moudle_cnlive_base
  7 + //发布环境(正式/测试)
  8 + android.defaultPublishConfig lib.debug ? "debug" : "release"
  9 + //发布渠道(地址/账号)
  10 + repository(url: maven.mixedUrl) {
  11 + authentication(userName: maven.username, password: maven.password)
  12 + }
  13 + //发布信息(包名/别名/版本)
  14 + pom.project {
  15 + groupId lib.packeg
  16 + artifactId lib.name
  17 + version = lib.debug ? lib.version.concat("-SNAPSHOT") : lib.version
  18 + }
  19 + pom.whenConfigured { pom ->
  20 + pom.dependencies.clear()
  21 + }
  22 +
  23 + }
  24 + }
  25 +}
0 26 \ No newline at end of file
... ...
core/base/build.gradle
1 1 apply plugin: 'com.android.library'
2   -
  2 +apply from: './base_maven_push.gradle'
3 3 android {
4 4 // compileSdkVersion 29
5 5 // buildToolsVersion "29.0.2"
... ... @@ -27,6 +27,5 @@ android {
27 27 dependencies {
28 28 implementation fileTree(include: ['*.jar'], dir: 'libs')
29 29 api files('libs/pinyin4j-2.5.0.jar')
30   -
31 30 implementation 'androidx.legacy:legacy-support-v4:1.0.0'
32 31 }
... ...
core/base/src/main/java/androidx/fragment/app/FragmentationMagician.java 0 → 100644
  1 +package androidx.fragment.app;
  2 +
  3 +
  4 +import java.util.List;
  5 +
  6 +/**
  7 + * Created by YoKey on 16/1/22.
  8 + */
  9 +public class FragmentationMagician {
  10 +
  11 + public static boolean isStateSaved(FragmentManager fragmentManager) {
  12 + if (!(fragmentManager instanceof FragmentManagerImpl))
  13 + return false;
  14 + try {
  15 + FragmentManagerImpl fragmentManagerImpl = (FragmentManagerImpl) fragmentManager;
  16 + return fragmentManagerImpl.isStateSaved();
  17 + } catch (Exception e) {
  18 + e.printStackTrace();
  19 + }
  20 + return false;
  21 + }
  22 +
  23 + /**
  24 + * Like {@link FragmentManager#popBackStack()}} but allows the commit to be executed after an
  25 + * activity's state is saved. This is dangerous because the action can
  26 + * be lost if the activity needs to later be restored from its state, so
  27 + * this should only be used for cases where it is okay for the UI state
  28 + * to change unexpectedly on the user.
  29 + */
  30 + public static void popBackStackAllowingStateLoss(final FragmentManager fragmentManager) {
  31 + FragmentationMagician.hookStateSaved(fragmentManager, new Runnable() {
  32 + @Override
  33 + public void run() {
  34 + fragmentManager.popBackStack();
  35 + }
  36 + });
  37 + }
  38 +
  39 + /**
  40 + * Like {@link FragmentManager#popBackStackImmediate()}} but allows the commit to be executed after an
  41 + * activity's state is saved.
  42 + */
  43 + public static void popBackStackImmediateAllowingStateLoss(final FragmentManager fragmentManager) {
  44 + FragmentationMagician.hookStateSaved(fragmentManager, new Runnable() {
  45 + @Override
  46 + public void run() {
  47 + fragmentManager.popBackStackImmediate();
  48 + }
  49 + });
  50 + }
  51 +
  52 + /**
  53 + * Like {@link FragmentManager#popBackStackImmediate(String, int)}} but allows the commit to be executed after an
  54 + * activity's state is saved.
  55 + */
  56 + public static void popBackStackAllowingStateLoss(final FragmentManager fragmentManager, final String name, final int flags) {
  57 + FragmentationMagician.hookStateSaved(fragmentManager, new Runnable() {
  58 + @Override
  59 + public void run() {
  60 + fragmentManager.popBackStack(name, flags);
  61 + }
  62 + });
  63 + }
  64 +
  65 + /**
  66 + * Like {@link FragmentManager#executePendingTransactions()} but allows the commit to be executed after an
  67 + * activity's state is saved.
  68 + */
  69 + public static void executePendingTransactionsAllowingStateLoss(final FragmentManager fragmentManager) {
  70 + FragmentationMagician.hookStateSaved(fragmentManager, new Runnable() {
  71 + @Override
  72 + public void run() {
  73 + fragmentManager.executePendingTransactions();
  74 + }
  75 + });
  76 + }
  77 +
  78 + public static List<Fragment> getActiveFragments(FragmentManager fragmentManager) {
  79 + return fragmentManager.getFragments();
  80 + }
  81 +
  82 + private static void hookStateSaved(FragmentManager fragmentManager, Runnable runnable) {
  83 + if (!(fragmentManager instanceof FragmentManagerImpl)) return;
  84 +
  85 + FragmentManagerImpl fragmentManagerImpl = (FragmentManagerImpl) fragmentManager;
  86 + if (isStateSaved(fragmentManager)) {
  87 + boolean tempStateSaved = fragmentManagerImpl.mStateSaved;
  88 + boolean tempStopped = fragmentManagerImpl.mStopped;
  89 + fragmentManagerImpl.mStateSaved = false;
  90 + fragmentManagerImpl.mStopped = false;
  91 +
  92 + runnable.run();
  93 +
  94 + fragmentManagerImpl.mStopped = tempStopped;
  95 + fragmentManagerImpl.mStateSaved = tempStateSaved;
  96 + } else {
  97 + runnable.run();
  98 + }
  99 + }
  100 +}
0 101 \ No newline at end of file
... ...
core/base/src/main/java/com/cnlive/core/libs/base/arouter/QrService.java 0 → 100644
  1 +package com.cnlive.core.libs.base.arouter;
  2 +
  3 +import android.graphics.Bitmap;
  4 +
  5 +import androidx.annotation.Nullable;
  6 +
  7 +import com.alibaba.android.arouter.facade.template.IProvider;
  8 +
  9 +/**
  10 + * 作者: 吴奎庆
  11 + * <p>
  12 + * 时间: 2019/6/18
  13 + * <p>
  14 + * 简介: 生成二维码调用的服务
  15 + */
  16 +public interface QrService extends IProvider {
  17 + String PATH = "/app/qrservice";
  18 + String NAME = "app_qrservice";
  19 + String GROUP = "appqr";
  20 +
  21 + /**
  22 + * 生成二维码的逻辑(带图标)
  23 + *
  24 + * @param content
  25 + * @param size 宽高
  26 + * @param logoBitmap 图标的bitmap
  27 + * @param logoPercent 百分比
  28 + * @return
  29 + */
  30 + Bitmap createQrIconBitMap(String content, int size, @Nullable Bitmap logoBitmap, float logoPercent);
  31 +
  32 + /**
  33 + * 生成不带图标的二维码
  34 + *
  35 + * @param content 内容
  36 + * @param size 二维码大小 单位px
  37 + * @return
  38 + */
  39 + Bitmap createQRNoIconBitmap(@Nullable String content, int size);
  40 +
  41 +}
... ...
core/base/src/main/java/com/cnlive/core/libs/base/arouter/im/FriendListData.java 0 → 100644
  1 +package com.cnlive.core.libs.base.arouter.im;
  2 +
  3 +public class FriendListData {
  4 +
  5 + private String friendId;
  6 + private String friendFaceUrl;
  7 + private String friendNickName;
  8 + private String friendRemark;
  9 + private String friendCustomInfoJson;
  10 +
  11 + public String getFriendId() {
  12 + return friendId;
  13 + }
  14 +
  15 + public void setFriendId(String friendId) {
  16 + this.friendId = friendId;
  17 + }
  18 +
  19 + public String getFriendFaceUrl() {
  20 + return friendFaceUrl;
  21 + }
  22 +
  23 + public void setFriendFaceUrl(String friendFaceUrl) {
  24 + this.friendFaceUrl = friendFaceUrl;
  25 + }
  26 +
  27 + public String getFriendNickName() {
  28 + return friendNickName;
  29 + }
  30 +
  31 + public void setFriendNickName(String friendNickName) {
  32 + this.friendNickName = friendNickName;
  33 + }
  34 +
  35 + public String getFriendRemark() {
  36 + return friendRemark;
  37 + }
  38 +
  39 + public void setFriendRemark(String friendRemark) {
  40 + this.friendRemark = friendRemark;
  41 + }
  42 +
  43 + public String getFriendCustomInfoJson() {
  44 + return friendCustomInfoJson;
  45 + }
  46 +
  47 + public void setFriendCustomInfoJson(String friendCustomInfoJson) {
  48 + this.friendCustomInfoJson = friendCustomInfoJson;
  49 + }
  50 +}
... ...
core/base/src/main/java/com/cnlive/core/libs/base/arouter/im/ImOpenService.java 0 → 100644
  1 +package com.cnlive.core.libs.base.arouter.im;
  2 +
  3 +import com.alibaba.android.arouter.facade.template.IProvider;
  4 +
  5 +import java.util.List;
  6 +
  7 +/**
  8 + * IM相关的对外接口
  9 + */
  10 +public interface ImOpenService extends IProvider {
  11 + //获取好友列表
  12 + void getFriendList(CNValueCallBack<List<FriendListData>> callBack);
  13 +
  14 + //是否已经加入了群组,注:本地数据判断
  15 + boolean hasJoinGroup(String groupId);
  16 +
  17 + interface CNCallBack {
  18 + void onError(int errorCode, String errorMsg);
  19 +
  20 + void onSuccess();
  21 + }
  22 +
  23 + interface CNValueCallBack<T> {
  24 + void onError(int var1, String var2);
  25 +
  26 + void onSuccess(T var1);
  27 + }
  28 +
  29 +}
... ...
core/base/src/main/java/com/cnlive/core/libs/base/frame/activity/BaseActivity.java
1 1 package com.cnlive.core.libs.base.frame.activity;
2 2  
3 3  
  4 +import android.app.Activity;
4 5 import android.content.Context;
5 6 import android.content.DialogInterface;
6 7 import android.content.Intent;
... ... @@ -14,21 +15,26 @@ import android.provider.Settings;
14 15 import android.text.TextUtils;
15 16 import android.util.DisplayMetrics;
16 17 import android.view.Display;
  18 +import android.view.MotionEvent;
17 19 import android.view.View;
18 20 import android.view.Window;
19 21 import android.view.WindowManager;
20 22 import android.view.inputmethod.InputMethodManager;
21 23  
22 24 import androidx.annotation.ColorRes;
  25 +import androidx.annotation.DrawableRes;
23 26 import androidx.annotation.IntRange;
24 27 import androidx.annotation.NonNull;
25 28 import androidx.annotation.Nullable;
  29 +import androidx.annotation.StringRes;
26 30 import androidx.appcompat.app.AlertDialog;
27 31 import androidx.core.app.ActivityCompat;
28 32 import androidx.core.content.ContextCompat;
29 33 import androidx.databinding.DataBindingUtil;
30 34 import androidx.databinding.ViewDataBinding;
31 35  
  36 +import com.alibaba.android.arouter.launcher.ARouter;
  37 +import com.cnlive.core.libs.base.application.AppConfig;
32 38 import com.cnlive.core.libs.base.frame.presenter.BasePresenter;
33 39 import com.cnlive.core.libs.base.frame.view.BaseView;
34 40 import com.cnlive.core.libs.base.interfaces.OnPermissionResponseListener;
... ... @@ -37,27 +43,36 @@ import com.cnlive.core.libs.base.util.AppManager;
37 43 import com.cnlive.core.libs.base.util.ReflectUtil;
38 44 import com.cnlive.core.libs.base.util.StatusBarConfig;
39 45 import com.cnlive.core.libs.base.util.StatusBarUtil;
40   -import com.cnlive.core.libs.base.util.swipeback.util.SwipeBackActivityBase;
41   -import com.cnlive.core.libs.base.util.swipeback.util.SwipeBackActivityHelper;
42   -import com.cnlive.core.libs.base.util.swipeback.util.SwipeBackLayout;
43   -import com.cnlive.core.libs.base.util.swipeback.util.SwipeBackUtil;
  46 +import com.cnlive.strike.base.R;
44 47 import com.hannesdorfmann.mosby3.mvp.MvpActivity;
  48 +import com.me.yokeyword.fragmentation.ExtraTransaction;
  49 +import com.me.yokeyword.fragmentation.Fragmentation;
  50 +import com.me.yokeyword.fragmentation.ISupportActivity;
  51 +import com.me.yokeyword.fragmentation.ISupportFragment;
  52 +import com.me.yokeyword.fragmentation.SupportActivityDelegate;
  53 +import com.me.yokeyword.fragmentation.SupportHelper;
  54 +import com.me.yokeyword.fragmentation.SwipeBackLayout;
  55 +import com.me.yokeyword.fragmentation.anim.FragmentAnimator;
  56 +import com.me.yokeyword.fragmentation_swipeback.core.ISwipeBackActivity;
  57 +import com.me.yokeyword.fragmentation_swipeback.core.SwipeBackActivityDelegate;
45 58 import com.orhanobut.logger.Logger;
46 59  
47 60 import java.lang.reflect.Field;
48 61 import java.util.ArrayList;
49 62 import java.util.List;
50 63  
  64 +
51 65 /**
52 66 * @author ys
53 67 * 基类 activity
  68 + * SwipeBackActivityBase,
54 69 */
55   -public abstract class BaseActivity<V extends BaseView, P extends BasePresenter<V>> extends MvpActivity<V, P> implements SwipeBackActivityBase {
  70 +public abstract class BaseActivity<V extends BaseView, P extends BasePresenter<V>> extends MvpActivity<V, P> implements ISupportActivity, ISwipeBackActivity {
56 71 private V view;
57 72 private P presenter;
58 73 public ViewDataBinding baseBinding;
59 74 //获取TAG的activity名称
60   - protected final String TAG = this.getClass().getSimpleName();
  75 + public final String TAG = this.getClass().getSimpleName();
61 76 //是否显示标题栏
62 77 private boolean isShowTitle = true;
63 78 //是否显示状态栏
... ... @@ -74,9 +89,12 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
74 89 private int USER_SET_REQUEST_CODE_PERMISSION = -0x00099;//用户设置的权限请求码
75 90 private String defaultDefinePermissionTip = "需要必要的权限才可以正常使用该功能,您已拒绝获得该权限。\n如果需要重新授权,您可以点击“允许”按钮进入系统设置进行授权";//默认拒绝的权限提示语
76 91 private String userSetDefinePermissionTip = "";//用户设置的权限提示语
77   - private SwipeBackActivityHelper mHelper;//侧滑返回
  92 + // private SwipeBackActivityHelper mHelper;//侧滑返回
78 93 private boolean isOpenSwipBack = false;
79   - private AlertDialog alertDialog;
  94 + //fragmnet管理
  95 + private final SupportActivityDelegate mDelegate = new SupportActivityDelegate(this);
  96 + //fragment侧滑
  97 + private final SwipeBackActivityDelegate mSwipeDelegate = new SwipeBackActivityDelegate(this);
80 98  
81 99 @Override
82 100 protected void onCreate(@Nullable Bundle savedInstanceState) {
... ... @@ -86,9 +104,20 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
86 104 } else if (0 != getViewLayoutId()) {
87 105 setContentView(getViewLayoutId());
88 106 }
  107 + //两种视图都没有设置,就加载默认跟视图,用于fragment切换
  108 + if (0 == getBindLayoutId() && 0 == getViewLayoutId()) {
  109 + setContentView(R.layout.base_activity_main);
  110 + }
89 111 context = this;
90 112 me = this;
  113 + //fragment管理
  114 + mDelegate.onCreate(savedInstanceState);
  115 + mSwipeDelegate.onCreate(savedInstanceState);
  116 + //是否开启滑动返回
  117 + setSwipeBackEnable(isOpenSwipBack);
91 118 this.savedInstanceState = savedInstanceState;
  119 + //路由参数初始化
  120 + ARouter.getInstance().inject(this);
92 121 //activity管理
93 122 AppManager.getInstance().pushActivity(me);
94 123 //创建订阅映射
... ... @@ -114,16 +143,11 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
114 143 initView();
115 144 //设置数据
116 145 initData();
117   - //是否开启滑动返回
118   - if (isOpenSwipBack) {
119   - mHelper = new SwipeBackActivityHelper(this);
120   - mHelper.onActivityCreate();
121   - }
122   -
123   - }
124   -
125   - protected void setOpenSwipBack(boolean isOpen) {
126   - isOpenSwipBack = isOpen;
  146 +// if (isOpenSwipBack) {
  147 +// mHelper = new SwipeBackActivityHelper(this);
  148 +// mHelper.onActivityCreate();
  149 +//
  150 +// }
127 151 }
128 152  
129 153  
... ... @@ -147,6 +171,10 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
147 171  
148 172 }
149 173  
  174 + public boolean isOpenSwipBack() {
  175 + return isOpenSwipBack;
  176 + }
  177 +
150 178 /**
151 179 * 设置是否显示标题栏
152 180 *
... ... @@ -238,13 +266,14 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
238 266  
239 267 @Override
240 268 protected void onDestroy() {
  269 + mDelegate.onDestroy();
241 270 super.onDestroy();
242   - if (null != alertDialog) {
243   - alertDialog.dismiss();
  271 + if (null != baseBinding) {
  272 + baseBinding.unbind();
244 273 }
245 274 //activity管理
246 275 AppManager.getInstance().deleteActivity(me);
247   - //清除所有订阅
  276 + //清除当前订阅
248 277 SubscriptionManager.getInstance().cancel(TAG);
249 278 }
250 279  
... ... @@ -254,15 +283,23 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
254 283 * @param color
255 284 * @param statusBarAlpha
256 285 */
257   - protected void setStatusBarColor(@ColorRes int color,
258   - @IntRange(from = 0, to = 255) int statusBarAlpha) {
  286 + public void setStatusBarColor(@ColorRes int color,
  287 + @IntRange(from = 0, to = 255) int statusBarAlpha) {
259 288 StatusBarUtil.setColor(this, ContextCompat.getColor(this, color), statusBarAlpha);
260 289 }
261 290  
  291 + public void setTransparentForWindow(Activity activity) {
  292 + StatusBarUtil.setTransparentForWindow(activity);
  293 + }
  294 +
  295 + public void addTranslucentView(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha) {
  296 + StatusBarUtil.addTranslucentView(activity, statusBarAlpha);
  297 + }
  298 +
262 299 /**
263 300 * 设置状态栏字体颜色
264 301 */
265   - protected void setStatusBarTextColor(int type) {
  302 + public void setStatusBarTextColor(int type) {
266 303 if (type == StatusBarConfig.BLACK) {
267 304 StatusBarUtil.setStatusBarWrite(this);
268 305 } else if (type == StatusBarConfig.WHITE) {
... ... @@ -403,6 +440,29 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
403 440 }
404 441  
405 442 /**
  443 + * 请求权限
  444 + * <p>
  445 + * 警告:此处除了用户拒绝外,唯一可能出现无法获取权限或失败的情况是在AndroidManifest.xml中未声明权限信息
  446 + * Android6.0+即便需要动态请求权限(重点)但不代表着不需要在AndroidManifest.xml中进行声明。
  447 + *
  448 + * @param permissions 请求的权限
  449 + * @param onPermissionResponseListener 回调监听器
  450 + */
  451 + public void requestPermission(String[] permissions, String defineTip, OnPermissionResponseListener
  452 + onPermissionResponseListener) {
  453 + this.userSetDefinePermissionTip = defineTip;
  454 + this.onPermissionResponseListener = onPermissionResponseListener;
  455 + if (checkPermissions(permissions)) {
  456 + if (onPermissionResponseListener != null) {
  457 + onPermissionResponseListener.onSuccess(permissions);
  458 + }
  459 + } else {
  460 + List<String> needPermissions = getDeniedPermissions(permissions);
  461 + ActivityCompat.requestPermissions(this, needPermissions.toArray(new String[needPermissions.size()]), DEFAULT_REQUEST_CODE_PERMISSION);
  462 + }
  463 + }
  464 +
  465 + /**
406 466 * 自定义权限申请码
407 467 *
408 468 * @param requestCode
... ... @@ -446,6 +506,29 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
446 506 }
447 507  
448 508 /**
  509 + * 自定义权限申请码和提示信息
  510 + * 可传入string字符串
  511 + *
  512 + * @param requestCode
  513 + * @param permissions
  514 + * @param onPermissionResponseListener
  515 + */
  516 + public void requestPermission(int requestCode, @StringRes int defineTip, String[]
  517 + permissions, OnPermissionResponseListener onPermissionResponseListener) {
  518 + this.onPermissionResponseListener = onPermissionResponseListener;
  519 + this.USER_SET_REQUEST_CODE_PERMISSION = requestCode;
  520 + this.userSetDefinePermissionTip = getResources().getString(defineTip);
  521 + if (checkPermissions(permissions)) {
  522 + if (onPermissionResponseListener != null) {
  523 + onPermissionResponseListener.onSuccess(permissions);
  524 + }
  525 + } else {
  526 + List<String> needPermissions = getDeniedPermissions(permissions);
  527 + ActivityCompat.requestPermissions(this, needPermissions.toArray(new String[needPermissions.size()]), USER_SET_REQUEST_CODE_PERMISSION);
  528 + }
  529 + }
  530 +
  531 + /**
449 532 * 获取权限集中需要申请权限的列表
450 533 *
451 534 * @param permissions
... ... @@ -588,33 +671,36 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
588 671 @Override
589 672 protected void onPostCreate(Bundle savedInstanceState) {
590 673 super.onPostCreate(savedInstanceState);
591   - if (null != mHelper) {
592   - mHelper.onPostCreate();
593   - }
594   - }
595   -
596   - @Override
597   - public SwipeBackLayout getSwipeBackLayout() {
598   - if (null != mHelper) {
599   - return mHelper.getSwipeBackLayout();
600   - }
601   - return null;
602   - }
603   -
604   - @Override
605   - public void setSwipeBackEnable(boolean enable) {
606   - if (null != getSwipeBackLayout()) {
607   - getSwipeBackLayout().setEnableGesture(enable);
608   - }
609   - }
610   -
611   - @Override
612   - public void scrollToFinishActivity() {
613   - if (null != mHelper) {
614   - SwipeBackUtil.convertActivityToTranslucent(this);
615   - getSwipeBackLayout().scrollToFinishActivity();
616   - }
617   - }
  674 +// if (null != mHelper) {
  675 +// mHelper.onPostCreate();
  676 +// }
  677 + mDelegate.onPostCreate(savedInstanceState);
  678 + mSwipeDelegate.onPostCreate(savedInstanceState);
  679 +
  680 + }
  681 +
  682 +// @Override
  683 +// public SwipeBackLayout getSwipeBackLayout() {
  684 +// if (null != mHelper) {
  685 +// return mHelper.getSwipeBackLayout();
  686 +// }
  687 +// return null;
  688 +// }
  689 +//
  690 +// @Override
  691 +// public void setSwipeBackEnable(boolean enable) {
  692 +// if (null != getSwipeBackLayout()) {
  693 +// getSwipeBackLayout().setEnableGesture(enable);
  694 +// }
  695 +// }
  696 +
  697 +// @Override
  698 +// public void scrollToFinishActivity() {
  699 +// if (null != mHelper) {
  700 +// SwipeBackUtil.convertActivityToTranslucent(this);
  701 +// getSwipeBackLayout().scrollToFinishActivity();
  702 +// }
  703 +// }
618 704  
619 705  
620 706 public void logError(Object info) {
... ... @@ -644,4 +730,288 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
644 730 public void logXml(String xml) {
645 731 Logger.xml(xml);
646 732 }
  733 +
  734 + /*****************************fragment管理****************************************/
  735 + @Override
  736 + public SupportActivityDelegate getSupportDelegate() {
  737 + return mDelegate;
  738 + }
  739 +
  740 + /**
  741 + * Perform some extra transactions.
  742 + * 额外的事务:自定义Tag,添加SharedElement动画,操作非回退栈Fragment
  743 + */
  744 + @Override
  745 + public ExtraTransaction extraTransaction() {
  746 + return mDelegate.extraTransaction();
  747 + }
  748 +
  749 + /**
  750 + * Note: return mDelegate.dispatchTouchEvent(ev) || super.dispatchTouchEvent(ev);
  751 + */
  752 + @Override
  753 + public boolean dispatchTouchEvent(MotionEvent ev) {
  754 + return mDelegate.dispatchTouchEvent(ev) || super.dispatchTouchEvent(ev);
  755 + }
  756 +
  757 + /**
  758 + * 不建议复写该方法,请使用 {@link #onBackPressedSupport} 代替
  759 + */
  760 + @Override
  761 + public void onBackPressed() {
  762 + mDelegate.onBackPressed();
  763 + }
  764 +
  765 + /**
  766 + * 该方法回调时机为,Activity回退栈内Fragment的数量 小于等于1 时,默认finish Activity
  767 + * 请尽量复写该方法,避免复写onBackPress(),以保证SupportFragment内的onBackPressedSupport()回退事件正常执行
  768 + */
  769 + @Override
  770 + public void onBackPressedSupport() {
  771 + mDelegate.onBackPressedSupport();
  772 + }
  773 +
  774 + /**
  775 + * 获取设置的全局动画 copy
  776 + *
  777 + * @return FragmentAnimator
  778 + */
  779 + @Override
  780 + public FragmentAnimator getFragmentAnimator() {
  781 + return mDelegate.getFragmentAnimator();
  782 + }
  783 +
  784 + /**
  785 + * Set all fragments animation.
  786 + * 设置Fragment内的全局动画
  787 + */
  788 + @Override
  789 + public void setFragmentAnimator(FragmentAnimator fragmentAnimator) {
  790 + mDelegate.setFragmentAnimator(fragmentAnimator);
  791 + }
  792 +
  793 + /**
  794 + * Set all fragments animation.
  795 + * 构建Fragment转场动画
  796 + * <p/>
  797 + * 如果是在Activity内实现,则构建的是Activity内所有Fragment的转场动画,
  798 + * 如果是在Fragment内实现,则构建的是该Fragment的转场动画,此时优先级 > Activity的onCreateFragmentAnimator()
  799 + *
  800 + * @return FragmentAnimator对象
  801 + */
  802 + @Override
  803 + public FragmentAnimator onCreateFragmentAnimator() {
  804 + return mDelegate.onCreateFragmentAnimator();
  805 + }
  806 +
  807 + @Override
  808 + public void post(Runnable runnable) {
  809 + mDelegate.post(runnable);
  810 + }
  811 +
  812 + /****************************************以下为可选方法(Optional methods)******************************************************/
  813 + /**
  814 + * 加载根Fragment, 即Activity内的第一个Fragment 或 Fragment内的第一个子Fragment
  815 + * <p>
  816 + * root_container 容器id
  817 + *
  818 + * @param toFragment 目标Fragment
  819 + */
  820 + public void loadRootFragment(@NonNull ISupportFragment toFragment) {
  821 + mDelegate.loadRootFragment(R.id.root_container, toFragment);
  822 + }
  823 +
  824 + /**
  825 + * 加载根Fragment, 即Activity内的第一个Fragment 或 Fragment内的第一个子Fragment
  826 + *
  827 + * @param containerId 容器id
  828 + * @param toFragment 目标Fragment
  829 + */
  830 + public void loadRootFragment(int containerId, @NonNull ISupportFragment toFragment) {
  831 + mDelegate.loadRootFragment(containerId, toFragment);
  832 + }
  833 +
  834 + public void loadRootFragment(int containerId, ISupportFragment toFragment, boolean addToBackStack, boolean allowAnimation) {
  835 + mDelegate.loadRootFragment(containerId, toFragment, addToBackStack, allowAnimation);
  836 + }
  837 +
  838 + /**
  839 + * 加载多个同级根Fragment,类似Wechat, QQ主页的场景
  840 + */
  841 + public void loadMultipleRootFragment(int containerId, int showPosition, ISupportFragment... toFragments) {
  842 + mDelegate.loadMultipleRootFragment(containerId, showPosition, toFragments);
  843 + }
  844 +
  845 + /**
  846 + * show一个Fragment,hide其他同栈所有Fragment
  847 + * 使用该方法时,要确保同级栈内无多余的Fragment,(只有通过loadMultipleRootFragment()载入的Fragment)
  848 + * <p>
  849 + * 建议使用更明确的{@link #showHideFragment(ISupportFragment, ISupportFragment)}
  850 + *
  851 + * @param showFragment 需要show的Fragment
  852 + */
  853 + public void showHideFragment(ISupportFragment showFragment) {
  854 + mDelegate.showHideFragment(showFragment);
  855 + }
  856 +
  857 + /**
  858 + * show一个Fragment,hide一个Fragment ; 主要用于类似微信主页那种 切换tab的情况
  859 + */
  860 + public void showHideFragment(ISupportFragment showFragment, ISupportFragment hideFragment) {
  861 + mDelegate.showHideFragment(showFragment, hideFragment);
  862 + }
  863 +
  864 + /**
  865 + * It is recommended to use {@link SupportFragment#start(ISupportFragment)}.
  866 + */
  867 + public void start(ISupportFragment toFragment) {
  868 + mDelegate.start(toFragment);
  869 + }
  870 +
  871 + /**
  872 + * It is recommended to use {@link SupportFragment#start(ISupportFragment, int)}.
  873 + *
  874 + * @param launchMode Similar to Activity's LaunchMode.
  875 + */
  876 + public void start(ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode) {
  877 + mDelegate.start(toFragment, launchMode);
  878 + }
  879 +
  880 + /**
  881 + * It is recommended to use {@link SupportFragment#startForResult(ISupportFragment, int)}.
  882 + * Launch an fragment for which you would like a result when it poped.
  883 + */
  884 + public void startForResult(ISupportFragment toFragment, int requestCode) {
  885 + mDelegate.startForResult(toFragment, requestCode);
  886 + }
  887 +
  888 + /**
  889 + * It is recommended to use {@link SupportFragment#startWithPop(ISupportFragment)}.
  890 + * Start the target Fragment and pop itself
  891 + */
  892 + public void startWithPop(ISupportFragment toFragment) {
  893 + mDelegate.startWithPop(toFragment);
  894 + }
  895 +
  896 + /**
  897 + * It is recommended to use {@link SupportFragment#startWithPopTo(ISupportFragment, Class, boolean)}.
  898 + *
  899 + * @see #popTo(Class, boolean)
  900 + * +
  901 + * @see #start(ISupportFragment)
  902 + */
  903 + public void startWithPopTo(ISupportFragment toFragment, Class<?> targetFragmentClass, boolean includeTargetFragment) {
  904 + mDelegate.startWithPopTo(toFragment, targetFragmentClass, includeTargetFragment);
  905 + }
  906 +
  907 + /**
  908 + * It is recommended to use {@link SupportFragment#replaceFragment(ISupportFragment, boolean)}.
  909 + */
  910 + public void replaceFragment(ISupportFragment toFragment, boolean addToBackStack) {
  911 + mDelegate.replaceFragment(toFragment, addToBackStack);
  912 + }
  913 +
  914 + /**
  915 + * Pop the fragment.
  916 + */
  917 + public void pop() {
  918 + mDelegate.pop();
  919 + }
  920 +
  921 + /**
  922 + * Pop the last fragment transition from the manager's fragment
  923 + * back stack.
  924 + * <p>
  925 + * 出栈到目标fragment
  926 + *
  927 + * @param targetFragmentClass 目标fragment
  928 + * @param includeTargetFragment 是否包含该fragment
  929 + */
  930 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment) {
  931 + mDelegate.popTo(targetFragmentClass, includeTargetFragment);
  932 + }
  933 +
  934 + /**
  935 + * If you want to begin another FragmentTransaction immediately after popTo(), use this method.
  936 + * 如果你想在出栈后, 立刻进行FragmentTransaction操作,请使用该方法
  937 + */
  938 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable) {
  939 + mDelegate.popTo(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable);
  940 + }
  941 +
  942 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable, int popAnim) {
  943 + mDelegate.popTo(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable, popAnim);
  944 + }
  945 +
  946 + /**
  947 + * 当Fragment根布局 没有 设定background属性时,
  948 + * Fragmentation默认使用Theme的android:windowbackground作为Fragment的背景,
  949 + * 可以通过该方法改变其内所有Fragment的默认背景。
  950 + */
  951 + public void setDefaultFragmentBackground(@DrawableRes int backgroundRes) {
  952 + mDelegate.setDefaultFragmentBackground(backgroundRes);
  953 + }
  954 +
  955 + /**
  956 + * 得到位于栈顶Fragment
  957 + */
  958 + public ISupportFragment getTopFragment() {
  959 + return SupportHelper.getTopFragment(getSupportFragmentManager());
  960 + }
  961 +
  962 + /**
  963 + * 获取栈内的fragment对象
  964 + */
  965 + public <T extends ISupportFragment> T findFragment(Class<T> fragmentClass) {
  966 + return SupportHelper.findFragment(getSupportFragmentManager(), fragmentClass);
  967 + }
  968 +
  969 +
  970 + /**
  971 + * 显示fragment栈视图
  972 + */
  973 + public void showFragmetStackView() {
  974 + Fragmentation.builder()
  975 + // show stack view. Mode: BUBBLE, SHAKE, NONE
  976 + .stackViewMode(Fragmentation.BUBBLE)
  977 + .debug(AppConfig.isDebug())
  978 + .install();
  979 + }
  980 +/***********************************滑动返回********************************************/
  981 + /**
  982 + * 是否可滑动
  983 + *
  984 + * @param enable
  985 + */
  986 + @Override
  987 + public void setSwipeBackEnable(boolean enable) {
  988 + isOpenSwipBack = enable;
  989 + mSwipeDelegate.setSwipeBackEnable(enable);
  990 + }
  991 +
  992 + @Override
  993 + public void setEdgeLevel(SwipeBackLayout.EdgeLevel edgeLevel) {
  994 + mSwipeDelegate.setEdgeLevel(edgeLevel);
  995 + }
  996 +
  997 + @Override
  998 + public void setEdgeLevel(int widthPixel) {
  999 + mSwipeDelegate.setEdgeLevel(widthPixel);
  1000 + }
  1001 +
  1002 + /**
  1003 + * 限制SwipeBack的条件,默认栈内Fragment数 <= 1时 , 优先滑动退出Activity , 而不是Fragment
  1004 + *
  1005 + * @return true: Activity优先滑动退出; false: Fragment优先滑动退出
  1006 + */
  1007 + @Override
  1008 + public boolean swipeBackPriority() {
  1009 + return mSwipeDelegate.swipeBackPriority();
  1010 + }
  1011 +
  1012 + @Override
  1013 + public SwipeBackLayout getSwipeBackLayout() {
  1014 + return mSwipeDelegate.getSwipeBackLayout();
  1015 + }
  1016 +
647 1017 }
648 1018 \ No newline at end of file
... ...
core/base/src/main/java/com/cnlive/core/libs/base/frame/fragment/BaseFragment.java
1 1 package com.cnlive.core.libs.base.frame.fragment;
2 2  
  3 +import android.app.Activity;
  4 +import android.content.Intent;
3 5 import android.os.Bundle;
4 6 import android.view.LayoutInflater;
5 7 import android.view.View;
6 8 import android.view.ViewGroup;
  9 +import android.view.animation.Animation;
7 10 import android.view.inputmethod.InputMethodManager;
8 11  
9 12 import androidx.annotation.ColorRes;
  13 +import androidx.annotation.FloatRange;
10 14 import androidx.annotation.IntRange;
11 15 import androidx.annotation.NonNull;
12 16 import androidx.annotation.Nullable;
  17 +import androidx.annotation.StringRes;
13 18 import androidx.core.content.ContextCompat;
14 19 import androidx.databinding.DataBindingUtil;
15 20 import androidx.databinding.ViewDataBinding;
16 21  
  22 +import com.alibaba.android.arouter.launcher.ARouter;
17 23 import com.cnlive.core.libs.base.frame.activity.BaseActivity;
18 24 import com.cnlive.core.libs.base.frame.presenter.BasePresenter;
19 25 import com.cnlive.core.libs.base.interfaces.OnPermissionResponseListener;
  26 +import com.cnlive.core.libs.base.network.manager.SubscriptionManager;
20 27 import com.cnlive.core.libs.base.util.ParameterCache;
21 28 import com.cnlive.core.libs.base.util.ReflectUtil;
22 29 import com.cnlive.core.libs.base.frame.view.BaseView;
23 30 import com.cnlive.core.libs.base.util.StatusBarConfig;
24 31 import com.cnlive.core.libs.base.util.StatusBarUtil;
  32 +import com.me.yokeyword.fragmentation.ExtraTransaction;
  33 +import com.me.yokeyword.fragmentation.ISupportFragment;
  34 +import com.me.yokeyword.fragmentation.SupportFragmentDelegate;
  35 +import com.me.yokeyword.fragmentation.SupportHelper;
  36 +import com.me.yokeyword.fragmentation.SwipeBackLayout;
  37 +import com.me.yokeyword.fragmentation.anim.FragmentAnimator;
  38 +import com.me.yokeyword.fragmentation_swipeback.core.ISwipeBackFragment;
  39 +import com.me.yokeyword.fragmentation_swipeback.core.SwipeBackFragmentDelegate;
  40 +import com.orhanobut.logger.Logger;
  41 +
25 42  
26 43 import static android.content.Context.INPUT_METHOD_SERVICE;
27 44  
... ... @@ -32,19 +49,27 @@ import static android.content.Context.INPUT_METHOD_SERVICE;
32 49 * @param <P>
33 50 * @author ys
34 51 */
35   -public abstract class BaseFragment<V extends BaseView, P extends BasePresenter<V>> extends com.hannesdorfmann.mosby3.mvp.MvpFragment<V, P> {
  52 +public abstract class BaseFragment<V extends BaseView, P extends BasePresenter<V>> extends com.hannesdorfmann.mosby3.mvp.MvpFragment<V, P> implements ISupportFragment, ISwipeBackFragment {
36 53 private V view;
37 54 private P presenter;
38   - protected final String TAG = this.getClass().getSimpleName();
  55 + public final String TAG = this.getClass().getSimpleName();
39 56 public ViewDataBinding baseBinding;
40 57 public View baseView;
41 58 public BaseActivity me;
  59 + //fragment管理
  60 + private final SupportFragmentDelegate mDelegate = new SupportFragmentDelegate(this);
  61 + //fragment滑动返回
  62 + private final SwipeBackFragmentDelegate mSwipeDelegate = new SwipeBackFragmentDelegate(this);
42 63  
43 64 @Override
44 65 public void onCreate(Bundle savedInstanceState) {
45 66 super.onCreate(savedInstanceState);
46 67 if (getActivity() == null) return;
47 68 me = (BaseActivity) getActivity();
  69 + mDelegate.onCreate(savedInstanceState);
  70 + mSwipeDelegate.onCreate(savedInstanceState);
  71 + setSwipeBackEnable(me.isOpenSwipBack());
  72 + ARouter.getInstance().inject(this);
48 73 initFragmentStyle();
49 74 initParams();
50 75 }
... ... @@ -54,10 +79,18 @@ public abstract class BaseFragment&lt;V extends BaseView, P extends BasePresenter&lt;V
54 79 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
55 80 if (0 != getBindLayoutId()) {
56 81 baseBinding = DataBindingUtil.inflate(inflater, getBindLayoutId(), container, false);
57   - return baseBinding.getRoot();
  82 + if (me.isOpenSwipBack()) {
  83 + return attachToSwipeBack(baseBinding.getRoot());
  84 + } else {
  85 + return baseBinding.getRoot();
  86 + }
58 87 } else if (0 != getViewLayoutId()) {
59 88 baseView = inflater.inflate(getViewLayoutId(), container, false);
60   - return baseView;
  89 + if (me.isOpenSwipBack()) {
  90 + return attachToSwipeBack(baseView);
  91 + } else {
  92 + return baseView;
  93 + }
61 94 }
62 95 return super.onCreateView(inflater, container, savedInstanceState);
63 96 }
... ... @@ -65,6 +98,9 @@ public abstract class BaseFragment&lt;V extends BaseView, P extends BasePresenter&lt;V
65 98 @Override
66 99 public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
67 100 super.onViewCreated(view, savedInstanceState);
  101 + //创建订阅映射
  102 + SubscriptionManager.getInstance().setCurrentDisposables(TAG);
  103 + mSwipeDelegate.onViewCreated(view, savedInstanceState);
68 104 if (null != getMvpView() && null != getPresenter()) {
69 105 initBindingData();
70 106 initView();
... ... @@ -150,49 +186,51 @@ public abstract class BaseFragment&lt;V extends BaseView, P extends BasePresenter&lt;V
150 186 */
151 187 protected void setStatusBarColor(@ColorRes int color,
152 188 @IntRange(from = 0, to = 255) int statusBarAlpha) {
153   - StatusBarUtil.setColor(getActivity(), ContextCompat.getColor(getActivity(), color), statusBarAlpha);
  189 + me.setStatusBarColor(color, statusBarAlpha);
154 190 }
155 191  
156   - /**
157   - * 设置状态栏字体颜色
158   - */
159   - protected void setStatusBarTextColor(int type) {
160   - if (type == StatusBarConfig.BLACK) {
161   - StatusBarUtil.setStatusBarWrite(getActivity());
162   - } else if (type == StatusBarConfig.WHITE) {
163   - StatusBarUtil.setStatusBarDarkMode(getActivity());
164   - }
  192 + public void setTransparentForWindow(Activity activity) {
  193 + me.setTransparentForWindow(activity);
165 194 }
166 195  
167   - /**
168   - * 隐藏软键盘
169   - */
170   - public void hideSoftInput() {
171   - InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(INPUT_METHOD_SERVICE);
172   - if (getActivity().getCurrentFocus() != null && null != imm) {
173   - imm.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(), 0);
  196 + public void addTranslucentView(Activity activity, @IntRange(from = 0, to = 255) int statusBarAlpha) {
  197 + me.addTranslucentView(activity, statusBarAlpha);
  198 + }
  199 +
  200 + @Override
  201 + public void onDestroy() {
  202 + mDelegate.onDestroy();
  203 + mSwipeDelegate.onDestroyView();
  204 + //清除当前订阅
  205 + SubscriptionManager.getInstance().cancel(TAG);
  206 + super.onDestroy();
  207 + if (null != baseBinding) {
  208 + baseBinding.unbind();
174 209 }
175 210 }
176 211  
177 212 /**
178   - * 显示软键盘
  213 + * 设置状态栏字体颜色
179 214 */
180   - public void showSoftInput() {
181   - InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(INPUT_METHOD_SERVICE);
182   - if (getActivity().getCurrentFocus() != null && null != imm) {
183   - imm.showSoftInputFromInputMethod(getActivity().getCurrentFocus().getWindowToken(), 0);
184   - }
  215 + protected void setStatusBarTextColor(int type) {
  216 + me.setStatusBarTextColor(type);
185 217 }
186 218  
  219 +
187 220 /**
188 221 * 显示软键盘
189 222 */
190   - public void showSoftInput(View view) {
191   - // InputMethodManager.SHOW_FORCED);
192   - InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(INPUT_METHOD_SERVICE);
193   - imm.showSoftInput(view, InputMethodManager.SHOW_FORCED);
  223 + public void showSoftInput() {
  224 + me.showSoftInput();
194 225 }
195 226  
  227 +// /**
  228 +// * 显示软键盘
  229 +// */
  230 +// public void showSoftInput(View view) {
  231 +// me.showSoftInput(view);
  232 +// }
  233 +
196 234  
197 235 /*********************************************************/
198 236 //用于进行dip和px转换
... ... @@ -220,6 +258,16 @@ public abstract class BaseFragment&lt;V extends BaseView, P extends BasePresenter&lt;V
220 258 me.requestPermission(requestCode, defineTip, permissions, onPermissionResponseListener);
221 259 }
222 260  
  261 + public void requestPermission(String[] permissions, String defineTip, OnPermissionResponseListener
  262 + onPermissionResponseListener) {
  263 + me.requestPermission(permissions, defineTip, onPermissionResponseListener);
  264 + }
  265 +
  266 + public void requestPermission(int requestCode, @StringRes int defineTip, String[]
  267 + permissions, OnPermissionResponseListener onPermissionResponseListener) {
  268 + me.requestPermission(requestCode, defineTip, permissions, onPermissionResponseListener);
  269 + }
  270 +
223 271 //多权限检查
224 272 public boolean checkPermissions(String[] permissions) {
225 273 return me.checkPermissions(permissions);
... ... @@ -230,4 +278,481 @@ public abstract class BaseFragment&lt;V extends BaseView, P extends BasePresenter&lt;V
230 278 return me.checkPermissions(permission);
231 279 }
232 280  
  281 + /************************************fragment管理********************************************/
  282 + @Override
  283 + public SupportFragmentDelegate getSupportDelegate() {
  284 + return mDelegate;
  285 + }
  286 +
  287 + /**
  288 + * Perform some extra transactions.
  289 + * 额外的事务:自定义Tag,添加SharedElement动画,操作非回退栈Fragment
  290 + */
  291 + @Override
  292 + public ExtraTransaction extraTransaction() {
  293 + return mDelegate.extraTransaction();
  294 + }
  295 +
  296 + @Override
  297 + public void onAttach(Activity activity) {
  298 + super.onAttach(activity);
  299 + mDelegate.onAttach(activity);
  300 + me = (BaseActivity) mDelegate.getActivity();
  301 + }
  302 +
  303 + @Override
  304 + public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
  305 + return mDelegate.onCreateAnimation(transit, enter, nextAnim);
  306 + }
  307 +
  308 + @Override
  309 + public void onActivityCreated(@Nullable Bundle savedInstanceState) {
  310 + super.onActivityCreated(savedInstanceState);
  311 + mDelegate.onActivityCreated(savedInstanceState);
  312 + }
  313 +
  314 + @Override
  315 + public void onSaveInstanceState(Bundle outState) {
  316 + super.onSaveInstanceState(outState);
  317 + mDelegate.onSaveInstanceState(outState);
  318 + }
  319 +
  320 + @Override
  321 + public void onResume() {
  322 + super.onResume();
  323 + mDelegate.onResume();
  324 + }
  325 +
  326 + @Override
  327 + public void onPause() {
  328 + super.onPause();
  329 + mDelegate.onPause();
  330 + }
  331 +
  332 + @Override
  333 + public void onDestroyView() {
  334 + mDelegate.onDestroyView();
  335 + super.onDestroyView();
  336 + }
  337 +
  338 + @Override
  339 + public void onHiddenChanged(boolean hidden) {
  340 + super.onHiddenChanged(hidden);
  341 + mDelegate.onHiddenChanged(hidden);
  342 + mSwipeDelegate.onHiddenChanged(hidden);
  343 + }
  344 +
  345 + @Override
  346 + public void setUserVisibleHint(boolean isVisibleToUser) {
  347 + super.setUserVisibleHint(isVisibleToUser);
  348 + mDelegate.setUserVisibleHint(isVisibleToUser);
  349 + }
  350 +
  351 + public void finish() {
  352 + if (null != me) {
  353 + me.finish();
  354 + }
  355 + }
  356 +
  357 + /*************************************log******************************************/
  358 + public void logError(Object info) {
  359 + Logger.e(TAG, info);
  360 + }
  361 +
  362 + public void logDebug(Object info) {
  363 + Logger.d(TAG, info);
  364 + }
  365 +
  366 + public void logWarn(Object info) {
  367 + Logger.w(TAG, info);
  368 + }
  369 +
  370 + public void logInfo(Object info) {
  371 + Logger.i(TAG, info);
  372 + }
  373 +
  374 + public void logVerbose(Object info) {
  375 + Logger.v(TAG, info);
  376 + }
  377 +
  378 + public void logJson(String json) {
  379 + Logger.json(json);
  380 + }
  381 +
  382 + public void logXml(String xml) {
  383 + Logger.xml(xml);
  384 + }
  385 +/*********************************fragment 管理******************************************/
  386 + /**
  387 + * Causes the Runnable r to be added to the action queue.
  388 + * <p>
  389 + * The runnable will be run after all the previous action has been run.
  390 + * <p>
  391 + * 前面的事务全部执行后 执行该Action
  392 + *
  393 + * @deprecated Use {@link #post(Runnable)} instead.
  394 + */
  395 + @Deprecated
  396 + @Override
  397 + public void enqueueAction(Runnable runnable) {
  398 + mDelegate.enqueueAction(runnable);
  399 + }
  400 +
  401 + /**
  402 + * Causes the Runnable r to be added to the action queue.
  403 + * <p>
  404 + * The runnable will be run after all the previous action has been run.
  405 + * <p>
  406 + * 前面的事务全部执行后 执行该Action
  407 + */
  408 + @Override
  409 + public void post(Runnable runnable) {
  410 + mDelegate.post(runnable);
  411 + }
  412 +
  413 + /**
  414 + * Called when the enter-animation end.
  415 + * 入栈动画 结束时,回调
  416 + */
  417 + @Override
  418 + public void onEnterAnimationEnd(Bundle savedInstanceState) {
  419 + mDelegate.onEnterAnimationEnd(savedInstanceState);
  420 + }
  421 +
  422 +
  423 + /**
  424 + * Lazy initial,Called when fragment is first called.
  425 + * <p>
  426 + * 同级下的 懒加载 + ViewPager下的懒加载 的结合回调方法
  427 + */
  428 + @Override
  429 + public void onLazyInitView(@Nullable Bundle savedInstanceState) {
  430 + mDelegate.onLazyInitView(savedInstanceState);
  431 + }
  432 +
  433 + /**
  434 + * Called when the fragment is visible.
  435 + * 当Fragment对用户可见时回调
  436 + * <p>
  437 + * Is the combination of [onHiddenChanged() + onResume()/onPause() + setUserVisibleHint()]
  438 + */
  439 + @Override
  440 + public void onSupportVisible() {
  441 + mDelegate.onSupportVisible();
  442 + }
  443 +
  444 + /**
  445 + * Called when the fragment is invivible.
  446 + * <p>
  447 + * Is the combination of [onHiddenChanged() + onResume()/onPause() + setUserVisibleHint()]
  448 + */
  449 + @Override
  450 + public void onSupportInvisible() {
  451 + mDelegate.onSupportInvisible();
  452 + }
  453 +
  454 + /**
  455 + * Return true if the fragment has been supportVisible.
  456 + */
  457 + @Override
  458 + final public boolean isSupportVisible() {
  459 + return mDelegate.isSupportVisible();
  460 + }
  461 +
  462 + /**
  463 + * Set fragment animation with a higher priority than the ISupportActivity
  464 + * 设定当前Fragmemt动画,优先级比在SupportActivity里高
  465 + */
  466 + @Override
  467 + public FragmentAnimator onCreateFragmentAnimator() {
  468 + return mDelegate.onCreateFragmentAnimator();
  469 + }
  470 +
  471 + /**
  472 + * 获取设置的全局动画 copy
  473 + *
  474 + * @return FragmentAnimator
  475 + */
  476 + @Override
  477 + public FragmentAnimator getFragmentAnimator() {
  478 + return mDelegate.getFragmentAnimator();
  479 + }
  480 +
  481 + /**
  482 + * 设置Fragment内的全局动画
  483 + */
  484 + @Override
  485 + public void setFragmentAnimator(FragmentAnimator fragmentAnimator) {
  486 + mDelegate.setFragmentAnimator(fragmentAnimator);
  487 + }
  488 +
  489 + /**
  490 + * 按返回键触发,前提是SupportActivity的onBackPressed()方法能被调用
  491 + *
  492 + * @return false则继续向上传递, true则消费掉该事件
  493 + */
  494 + @Override
  495 + public boolean onBackPressedSupport() {
  496 + return mDelegate.onBackPressedSupport();
  497 + }
  498 +
  499 + /**
  500 + * 类似 {@link Activity#setResult(int, Intent)}
  501 + * <p>
  502 + * Similar to {@link Activity#setResult(int, Intent)}
  503 + *
  504 + * @see #startForResult(ISupportFragment, int)
  505 + */
  506 + @Override
  507 + public void setFragmentResult(int resultCode, Bundle bundle) {
  508 + mDelegate.setFragmentResult(resultCode, bundle);
  509 + }
  510 +
  511 + /**
  512 + * 类似 {@link Activity#onActivityResult(int, int, Intent)}
  513 + * <p>
  514 + * Similar to {@link Activity#onActivityResult(int, int, Intent)}
  515 + *
  516 + * @see #startForResult(ISupportFragment, int)
  517 + */
  518 + @Override
  519 + public void onFragmentResult(int requestCode, int resultCode, Bundle data) {
  520 + mDelegate.onFragmentResult(requestCode, resultCode, data);
  521 + }
  522 +
  523 + /**
  524 + * 在start(TargetFragment,LaunchMode)时,启动模式为SingleTask/SingleTop, 回调TargetFragment的该方法
  525 + * 类似 {@link Activity#onNewIntent(Intent)}
  526 + * <p>
  527 + * Similar to {@link Activity#onNewIntent(Intent)}
  528 + *
  529 + * @param args putNewBundle(Bundle newBundle)
  530 + * @see #start(ISupportFragment, int)
  531 + */
  532 + @Override
  533 + public void onNewBundle(Bundle args) {
  534 + mDelegate.onNewBundle(args);
  535 + }
  536 +
  537 + /**
  538 + * 添加NewBundle,用于启动模式为SingleTask/SingleTop时
  539 + *
  540 + * @see #start(ISupportFragment, int)
  541 + */
  542 + @Override
  543 + public void putNewBundle(Bundle newBundle) {
  544 + mDelegate.putNewBundle(newBundle);
  545 + }
  546 +
  547 +
  548 + /****************************************以下为可选方法(Optional methods)******************************************************/
  549 +
  550 + /**
  551 + * 隐藏软键盘
  552 + */
  553 + protected void hideSoftInput() {
  554 + mDelegate.hideSoftInput();
  555 + }
  556 +
  557 + /**
  558 + * 显示软键盘,调用该方法后,会在onPause时自动隐藏软键盘
  559 + */
  560 + protected void showSoftInput(final View view) {
  561 + mDelegate.showSoftInput(view);
  562 + }
  563 +
  564 + /**
  565 + * 加载根Fragment, 即Activity内的第一个Fragment 或 Fragment内的第一个子Fragment
  566 + *
  567 + * @param containerId 容器id
  568 + * @param toFragment 目标Fragment
  569 + */
  570 + public void loadRootFragment(int containerId, ISupportFragment toFragment) {
  571 + mDelegate.loadRootFragment(containerId, toFragment);
  572 + }
  573 +
  574 + public void loadRootFragment(int containerId, ISupportFragment toFragment, boolean addToBackStack, boolean allowAnim) {
  575 + mDelegate.loadRootFragment(containerId, toFragment, addToBackStack, allowAnim);
  576 + }
  577 +
  578 + /**
  579 + * 加载多个同级根Fragment,类似Wechat, QQ主页的场景
  580 + */
  581 + public void loadMultipleRootFragment(int containerId, int showPosition, ISupportFragment... toFragments) {
  582 + mDelegate.loadMultipleRootFragment(containerId, showPosition, toFragments);
  583 + }
  584 +
  585 + /**
  586 + * show一个Fragment,hide其他同栈所有Fragment
  587 + * 使用该方法时,要确保同级栈内无多余的Fragment,(只有通过loadMultipleRootFragment()载入的Fragment)
  588 + * <p>
  589 + * 建议使用更明确的{@link #showHideFragment(ISupportFragment, ISupportFragment)}
  590 + *
  591 + * @param showFragment 需要show的Fragment
  592 + */
  593 + public void showHideFragment(ISupportFragment showFragment) {
  594 + mDelegate.showHideFragment(showFragment);
  595 + }
  596 +
  597 + /**
  598 + * show一个Fragment,hide一个Fragment ; 主要用于类似微信主页那种 切换tab的情况
  599 + */
  600 + public void showHideFragment(ISupportFragment showFragment, ISupportFragment hideFragment) {
  601 + mDelegate.showHideFragment(showFragment, hideFragment);
  602 + }
  603 +
  604 + public void start(ISupportFragment toFragment) {
  605 + mDelegate.start(toFragment);
  606 + }
  607 +
  608 + /**
  609 + * @param launchMode Similar to Activity's LaunchMode.
  610 + */
  611 + public void start(final ISupportFragment toFragment, @LaunchMode int launchMode) {
  612 + mDelegate.start(toFragment, launchMode);
  613 + }
  614 +
  615 + /**
  616 + * Launch an fragment for which you would like a result when it poped.
  617 + */
  618 + public void startForResult(ISupportFragment toFragment, int requestCode) {
  619 + mDelegate.startForResult(toFragment, requestCode);
  620 + }
  621 +
  622 + /**
  623 + * Start the target Fragment and pop itself
  624 + */
  625 + public void startWithPop(ISupportFragment toFragment) {
  626 + mDelegate.startWithPop(toFragment);
  627 + }
  628 +
  629 + /**
  630 + * @see #popTo(Class, boolean)
  631 + * +
  632 + * @see #start(ISupportFragment)
  633 + */
  634 + public void startWithPopTo(ISupportFragment toFragment, Class<?> targetFragmentClass, boolean includeTargetFragment) {
  635 + mDelegate.startWithPopTo(toFragment, targetFragmentClass, includeTargetFragment);
  636 + }
  637 +
  638 +
  639 + public void replaceFragment(ISupportFragment toFragment, boolean addToBackStack) {
  640 + mDelegate.replaceFragment(toFragment, addToBackStack);
  641 + }
  642 +
  643 + public void pop() {
  644 + mDelegate.pop();
  645 + }
  646 +
  647 + /**
  648 + * Pop the child fragment.
  649 + */
  650 + public void popChild() {
  651 + mDelegate.popChild();
  652 + }
  653 +
  654 + /**
  655 + * Pop the last fragment transition from the manager's fragment
  656 + * back stack.
  657 + * <p>
  658 + * 出栈到目标fragment
  659 + *
  660 + * @param targetFragmentClass 目标fragment
  661 + * @param includeTargetFragment 是否包含该fragment
  662 + */
  663 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment) {
  664 + mDelegate.popTo(targetFragmentClass, includeTargetFragment);
  665 + }
  666 +
  667 + /**
  668 + * If you want to begin another FragmentTransaction immediately after popTo(), use this method.
  669 + * 如果你想在出栈后, 立刻进行FragmentTransaction操作,请使用该方法
  670 + */
  671 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable) {
  672 + mDelegate.popTo(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable);
  673 + }
  674 +
  675 + public void popTo(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable, int popAnim) {
  676 + mDelegate.popTo(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable, popAnim);
  677 + }
  678 +
  679 + public void popToChild(Class<?> targetFragmentClass, boolean includeTargetFragment) {
  680 + mDelegate.popToChild(targetFragmentClass, includeTargetFragment);
  681 + }
  682 +
  683 + public void popToChild(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable) {
  684 + mDelegate.popToChild(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable);
  685 + }
  686 +
  687 + public void popToChild(Class<?> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable, int popAnim) {
  688 + mDelegate.popToChild(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable, popAnim);
  689 + }
  690 +
  691 + /**
  692 + * 得到位于栈顶Fragment
  693 + */
  694 + public ISupportFragment getTopFragment() {
  695 + return SupportHelper.getTopFragment(getFragmentManager());
  696 + }
  697 +
  698 + public ISupportFragment getTopChildFragment() {
  699 + return SupportHelper.getTopFragment(getChildFragmentManager());
  700 + }
  701 +
  702 + /**
  703 + * @return 位于当前Fragment的前一个Fragment
  704 + */
  705 + public ISupportFragment getPreFragment() {
  706 + return SupportHelper.getPreFragment(this);
  707 + }
  708 +
  709 + /**
  710 + * 获取栈内的fragment对象
  711 + */
  712 + public <T extends ISupportFragment> T findFragment(Class<T> fragmentClass) {
  713 + return SupportHelper.findFragment(getFragmentManager(), fragmentClass);
  714 + }
  715 +
  716 + /**
  717 + * 获取栈内的fragment对象
  718 + */
  719 + public <T extends ISupportFragment> T findChildFragment(Class<T> fragmentClass) {
  720 + return SupportHelper.findFragment(getChildFragmentManager(), fragmentClass);
  721 + }
  722 +
  723 + /*****************************侧滑返回************************************/
  724 + @Override
  725 + public View attachToSwipeBack(View view) {
  726 + return mSwipeDelegate.attachToSwipeBack(view);
  727 + }
  728 +
  729 + public SwipeBackLayout getSwipeBackLayout() {
  730 + return mSwipeDelegate.getSwipeBackLayout();
  731 + }
  732 +
  733 + /**
  734 + * 是否可滑动
  735 + *
  736 + * @param enable
  737 + */
  738 + public void setSwipeBackEnable(boolean enable) {
  739 + mSwipeDelegate.setSwipeBackEnable(enable);
  740 + }
  741 +
  742 + @Override
  743 + public void setEdgeLevel(SwipeBackLayout.EdgeLevel edgeLevel) {
  744 + mSwipeDelegate.setEdgeLevel(edgeLevel);
  745 + }
  746 +
  747 + @Override
  748 + public void setEdgeLevel(int widthPixel) {
  749 + mSwipeDelegate.setEdgeLevel(widthPixel);
  750 + }
  751 +
  752 + /**
  753 + * Set the offset of the parallax slip.
  754 + */
  755 + public void setParallaxOffset(@FloatRange(from = 0.0f, to = 1.0f) float offset) {
  756 + mSwipeDelegate.setParallaxOffset(offset);
  757 + }
233 758 }
... ...
core/base/src/main/java/com/cnlive/core/libs/base/frame/presenter/BasePresenter.java
... ... @@ -2,6 +2,7 @@ package com.cnlive.core.libs.base.frame.presenter;
2 2  
3 3 import com.cnlive.core.libs.base.frame.view.BaseView;
4 4 import com.hannesdorfmann.mosby3.mvp.MvpBasePresenter;
  5 +import com.orhanobut.logger.Logger;
5 6  
6 7 public class BasePresenter<V extends BaseView> extends MvpBasePresenter<V> {
7 8 protected final String TAG = this.getClass().getSimpleName();
... ... @@ -17,4 +18,32 @@ public class BasePresenter&lt;V extends BaseView&gt; extends MvpBasePresenter&lt;V&gt; {
17 18 // public V getView() {
18 19 // return super.getView();
19 20 // }
  21 +
  22 + public void logError(Object info) {
  23 + Logger.e(TAG, info);
  24 + }
  25 +
  26 + public void logDebug(Object info) {
  27 + Logger.d(TAG, info);
  28 + }
  29 +
  30 + public void logWarn(Object info) {
  31 + Logger.w(TAG, info);
  32 + }
  33 +
  34 + public void logInfo(Object info) {
  35 + Logger.i(TAG, info);
  36 + }
  37 +
  38 + public void logVerbose(Object info) {
  39 + Logger.v(TAG, info);
  40 + }
  41 +
  42 + public void logJson(String json) {
  43 + Logger.json(json);
  44 + }
  45 +
  46 + public void logXml(String xml) {
  47 + Logger.xml(xml);
  48 + }
20 49 }
... ...
core/base/src/main/java/com/cnlive/core/libs/base/frame/view/BaseView.java
1 1 package com.cnlive.core.libs.base.frame.view;
2 2  
3 3 import com.hannesdorfmann.mosby3.mvp.MvpView;
  4 +import com.orhanobut.logger.Logger;
4 5  
5 6 /**
6 7 * @author ys
... ... @@ -22,4 +23,32 @@ public class BaseView implements MvpView {
22 23 }
23 24 return false;
24 25 }
  26 +
  27 + public void logError(Object info) {
  28 + Logger.e(TAG, info);
  29 + }
  30 +
  31 + public void logDebug(Object info) {
  32 + Logger.d(TAG, info);
  33 + }
  34 +
  35 + public void logWarn(Object info) {
  36 + Logger.w(TAG, info);
  37 + }
  38 +
  39 + public void logInfo(Object info) {
  40 + Logger.i(TAG, info);
  41 + }
  42 +
  43 + public void logVerbose(Object info) {
  44 + Logger.v(TAG, info);
  45 + }
  46 +
  47 + public void logJson(String json) {
  48 + Logger.json(json);
  49 + }
  50 +
  51 + public void logXml(String xml) {
  52 + Logger.xml(xml);
  53 + }
25 54 }
... ...
core/base/src/main/java/com/cnlive/core/libs/base/ui/widget/BottomSheet.java 0 → 100644
  1 +package com.cnlive.core.libs.base.ui.widget;
  2 +
  3 +import android.app.Dialog;
  4 +import android.content.Context;
  5 +import android.os.Bundle;
  6 +import android.text.TextUtils;
  7 +import android.util.Log;
  8 +import android.view.Gravity;
  9 +import android.view.LayoutInflater;
  10 +import android.view.View;
  11 +import android.view.ViewGroup;
  12 +import android.view.WindowManager;
  13 +import android.view.animation.AlphaAnimation;
  14 +import android.view.animation.Animation;
  15 +import android.view.animation.AnimationSet;
  16 +import android.view.animation.DecelerateInterpolator;
  17 +import android.view.animation.TranslateAnimation;
  18 +import android.widget.BaseAdapter;
  19 +import android.widget.ListView;
  20 +import android.widget.TextView;
  21 +
  22 +import androidx.annotation.NonNull;
  23 +
  24 +import com.cnlive.core.libs.base.util.DensityUtils;
  25 +import com.cnlive.strike.base.R;
  26 +import com.qmuiteam.qmui.QMUILog;
  27 +import com.qmuiteam.qmui.util.QMUIDisplayHelper;
  28 +import com.qmuiteam.qmui.util.QMUILangHelper;
  29 +import com.qmuiteam.qmui.util.QMUIResHelper;
  30 +
  31 +import java.util.ArrayList;
  32 +import java.util.List;
  33 +
  34 +/**
  35 + * QMUIBottomSheet 在 {@link Dialog} 的基础上重新定制了 {@link #show()} 和 {@link #hide()} 时的动画效果, 使 {@link Dialog} 在界面底部升起和降下。
  36 + * <p>
  37 + * 提供了以下两种面板样式:
  38 + * <ul>
  39 + * <li>列表样式, 使用 {@link BottomSheet.BottomListSheetBuilder} 生成。</li>
  40 + * </ul>
  41 + * </p>
  42 + */
  43 +public class BottomSheet extends Dialog {
  44 + private static final String TAG = "QMUIBottomSheet";
  45 + // 动画时长
  46 + private final static int mAnimationDuration = 200;
  47 + // 持有 ContentView,为了做动画
  48 + private View mContentView;
  49 + private boolean mIsAnimating = false;
  50 +
  51 + private OnBottomSheetShowListener mOnBottomSheetShowListener;
  52 +
  53 + public BottomSheet(Context context) {
  54 + super(context, com.qmuiteam.qmui.R.style.QMUI_BottomSheet);
  55 + }
  56 +
  57 + public void setOnBottomSheetShowListener(OnBottomSheetShowListener onBottomSheetShowListener) {
  58 + mOnBottomSheetShowListener = onBottomSheetShowListener;
  59 + }
  60 +
  61 + @Override
  62 + protected void onCreate(Bundle savedInstanceState) {
  63 + super.onCreate(savedInstanceState);
  64 +
  65 + //noinspection ConstantConditions
  66 + getWindow().getDecorView().setPadding(0, 0, 0, 0);
  67 +
  68 + // 在底部,宽度撑满
  69 + WindowManager.LayoutParams params = getWindow().getAttributes();
  70 + params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
  71 + params.gravity = Gravity.BOTTOM | Gravity.CENTER;
  72 +
  73 + int screenWidth = QMUIDisplayHelper.getScreenWidth(getContext());
  74 + int screenHeight = QMUIDisplayHelper.getScreenHeight(getContext());
  75 + params.width = screenWidth < screenHeight ? screenWidth : screenHeight;
  76 + getWindow().setAttributes(params);
  77 + setCanceledOnTouchOutside(true);
  78 + }
  79 +
  80 + @Override
  81 + public void setContentView(int layoutResID) {
  82 + mContentView = LayoutInflater.from(getContext()).inflate(layoutResID, null);
  83 + super.setContentView(mContentView);
  84 + }
  85 +
  86 + @Override
  87 + public void setContentView(@NonNull View view, ViewGroup.LayoutParams params) {
  88 + mContentView = view;
  89 + super.setContentView(view, params);
  90 + }
  91 +
  92 + public View getContentView() {
  93 + return mContentView;
  94 + }
  95 +
  96 + @Override
  97 + public void setContentView(@NonNull View view) {
  98 + mContentView = view;
  99 + super.setContentView(view);
  100 + }
  101 +
  102 + /**
  103 + * BottomSheet升起动画
  104 + */
  105 + private void animateUp() {
  106 + if (mContentView == null) {
  107 + return;
  108 + }
  109 + TranslateAnimation translate = new TranslateAnimation(
  110 + Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f,
  111 + Animation.RELATIVE_TO_SELF, 1f, Animation.RELATIVE_TO_SELF, 0f
  112 + );
  113 + AlphaAnimation alpha = new AlphaAnimation(0, 1);
  114 + AnimationSet set = new AnimationSet(true);
  115 + set.addAnimation(translate);
  116 + set.addAnimation(alpha);
  117 + set.setInterpolator(new DecelerateInterpolator());
  118 + set.setDuration(mAnimationDuration);
  119 + set.setFillAfter(true);
  120 + mContentView.startAnimation(set);
  121 + }
  122 +
  123 + /**
  124 + * BottomSheet降下动画
  125 + */
  126 + private void animateDown() {
  127 + if (mContentView == null) {
  128 + return;
  129 + }
  130 + TranslateAnimation translate = new TranslateAnimation(
  131 + Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f,
  132 + Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 1f
  133 + );
  134 + AlphaAnimation alpha = new AlphaAnimation(1, 0);
  135 + AnimationSet set = new AnimationSet(true);
  136 + set.addAnimation(translate);
  137 + set.addAnimation(alpha);
  138 + set.setInterpolator(new DecelerateInterpolator());
  139 + set.setDuration(mAnimationDuration);
  140 + set.setFillAfter(true);
  141 + set.setAnimationListener(new Animation.AnimationListener() {
  142 + @Override
  143 + public void onAnimationStart(Animation animation) {
  144 + mIsAnimating = true;
  145 + }
  146 +
  147 + @Override
  148 + public void onAnimationEnd(Animation animation) {
  149 + mIsAnimating = false;
  150 + /**
  151 + * Bugfix: Attempting to destroy the window while drawing!
  152 + */
  153 + mContentView.post(new Runnable() {
  154 + @Override
  155 + public void run() {
  156 + // java.lang.IllegalArgumentException: View=com.android.internal.policy.PhoneWindow$DecorView{22dbf5b V.E...... R......D 0,0-1080,1083} not attached to window manager
  157 + // 在dismiss的时候可能已经detach了,简单try-catch一下
  158 + try {
  159 + BottomSheet.super.dismiss();
  160 + } catch (Exception e) {
  161 + QMUILog.w(TAG, "dismiss error\n" + Log.getStackTraceString(e));
  162 + }
  163 + }
  164 + });
  165 + }
  166 +
  167 + @Override
  168 + public void onAnimationRepeat(Animation animation) {
  169 +
  170 + }
  171 + });
  172 + mContentView.startAnimation(set);
  173 + }
  174 +
  175 + @Override
  176 + public void show() {
  177 + super.show();
  178 + animateUp();
  179 + if (mOnBottomSheetShowListener != null) {
  180 + mOnBottomSheetShowListener.onShow();
  181 + }
  182 + }
  183 +
  184 + @Override
  185 + public void dismiss() {
  186 + if (mIsAnimating) {
  187 + return;
  188 + }
  189 + animateDown();
  190 + }
  191 +
  192 + /**
  193 + * 销毁提示窗
  194 + *
  195 + * @param animation 是否启动动画
  196 + */
  197 + public void dismiss(boolean animation) {
  198 + if (animation) {
  199 + dismiss();
  200 + } else {
  201 + super.dismiss();
  202 + }
  203 + }
  204 +
  205 + public interface OnBottomSheetShowListener {
  206 + void onShow();
  207 + }
  208 +
  209 + /**
  210 + * 生成列表类型的 {@link BottomSheet} 对话框。
  211 + */
  212 + public static class BottomListSheetBuilder {
  213 +
  214 + private Context mContext;
  215 +
  216 + private BottomSheet mDialog;
  217 + private List<BottomSheetListItemData> mItems;
  218 + private BaseAdapter mAdapter;
  219 + private List<View> mHeaderViews;
  220 + private ListView mContainerView;
  221 + private int mCheckedIndex;
  222 + private String mTitle;
  223 + private TextView mTitleTv;
  224 + private OnSheetItemClickListener mOnSheetItemClickListener;
  225 + private OnDismissListener mOnBottomDialogDismissListener;
  226 +
  227 +
  228 + public BottomListSheetBuilder(Context context) {
  229 + mContext = context;
  230 + mItems = new ArrayList<>();
  231 + mHeaderViews = new ArrayList<>();
  232 + }
  233 +
  234 + public BottomListSheetBuilder setCheckedIndex(int checkedIndex) {
  235 + mCheckedIndex = checkedIndex;
  236 + return this;
  237 + }
  238 +
  239 + /**
  240 + * @param textAndTag Item 的文字内容,同时会把内容设置为 tag。
  241 + */
  242 + public BottomListSheetBuilder addItem(String textAndTag) {
  243 + mItems.add(new BottomSheetListItemData(textAndTag, textAndTag, null, false));
  244 + return this;
  245 + }
  246 +
  247 + /**
  248 + * @param textAndTag Item 的文字内容,同时会把内容设置为 tag。
  249 + * @param split 是否显示分割线
  250 + */
  251 + public BottomListSheetBuilder addItem(String textAndTag, boolean split) {
  252 + mItems.add(new BottomSheetListItemData(textAndTag, textAndTag, null, split));
  253 + return this;
  254 + }
  255 +
  256 + /**
  257 + * @param subTitle 副标题文字内容
  258 + * @param textAndTag Item 的文字内容,同时会把内容设置为 tag。
  259 + * @param split 是否显示分割线
  260 + * @return
  261 + */
  262 + public BottomListSheetBuilder addItem(String textAndTag, String subTitle, boolean split) {
  263 + mItems.add(new BottomSheetListItemData(textAndTag, textAndTag, subTitle, split));
  264 + return this;
  265 + }
  266 +
  267 + /**
  268 + * @param text Item 的文字内容。
  269 + * @param tag item 的 tag。
  270 + */
  271 + public BottomListSheetBuilder addItem(String text, String tag) {
  272 + mItems.add(new BottomSheetListItemData(text, tag));
  273 + return this;
  274 + }
  275 +
  276 +
  277 + public BottomListSheetBuilder setOnSheetItemClickListener(OnSheetItemClickListener onSheetItemClickListener) {
  278 + mOnSheetItemClickListener = onSheetItemClickListener;
  279 + return this;
  280 + }
  281 +
  282 + public BottomListSheetBuilder setOnBottomDialogDismissListener(OnDismissListener listener) {
  283 + mOnBottomDialogDismissListener = listener;
  284 + return this;
  285 + }
  286 +
  287 + public BottomListSheetBuilder addHeaderView(View view) {
  288 + if (view != null) {
  289 + mHeaderViews.add(view);
  290 + }
  291 + return this;
  292 + }
  293 +
  294 + public BottomListSheetBuilder setTitle(String title) {
  295 + mTitle = title;
  296 + return this;
  297 + }
  298 +
  299 + public BottomListSheetBuilder setTitle(int resId) {
  300 + mTitle = mContext.getResources().getString(resId);
  301 + return this;
  302 + }
  303 +
  304 + public BottomSheet build() {
  305 + mDialog = new BottomSheet(mContext);
  306 + View contentView = buildViews();
  307 + mDialog.setContentView(contentView,
  308 + new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
  309 + if (mOnBottomDialogDismissListener != null) {
  310 + mDialog.setOnDismissListener(mOnBottomDialogDismissListener);
  311 + }
  312 + return mDialog;
  313 + }
  314 +
  315 + private View buildViews() {
  316 + View wrapperView = View.inflate(mContext, getContentViewLayoutId(), null);
  317 + mTitleTv = (TextView) wrapperView.findViewById(com.qmuiteam.qmui.R.id.title);
  318 + mContainerView = (ListView) wrapperView.findViewById(com.qmuiteam.qmui.R.id.listview);
  319 + if (mTitle != null && mTitle.length() != 0) {
  320 + mTitleTv.setVisibility(View.VISIBLE);
  321 + mTitleTv.setText(mTitle);
  322 + } else {
  323 + mTitleTv.setVisibility(View.GONE);
  324 + }
  325 + if (mHeaderViews.size() > 0) {
  326 + for (View headerView : mHeaderViews) {
  327 + mContainerView.addHeaderView(headerView);
  328 + }
  329 + }
  330 + if (needToScroll()) {
  331 + mContainerView.getLayoutParams().height = getListMaxHeight();
  332 + mDialog.setOnBottomSheetShowListener(new OnBottomSheetShowListener() {
  333 + @Override
  334 + public void onShow() {
  335 + mContainerView.setSelection(mCheckedIndex);
  336 + }
  337 + });
  338 + }
  339 +
  340 + mAdapter = new ListAdapter();
  341 + mContainerView.setAdapter(mAdapter);
  342 + return wrapperView;
  343 + }
  344 +
  345 + private boolean needToScroll() {
  346 + int itemHeight = QMUIResHelper.getAttrDimen(mContext, com.qmuiteam.qmui.R.attr.qmui_bottom_sheet_list_item_height);
  347 + int totalHeight = mItems.size() * itemHeight;
  348 + if (mHeaderViews.size() > 0) {
  349 + for (View view : mHeaderViews) {
  350 + if (view.getMeasuredHeight() == 0) {
  351 + view.measure(0, 0);
  352 + }
  353 + totalHeight += view.getMeasuredHeight();
  354 + }
  355 + }
  356 + if (mTitleTv != null && !QMUILangHelper.isNullOrEmpty(mTitle)) {
  357 + totalHeight += QMUIResHelper.getAttrDimen(mContext, com.qmuiteam.qmui.R.attr.qmui_bottom_sheet_title_height);
  358 + }
  359 + return totalHeight > getListMaxHeight();
  360 + }
  361 +
  362 + /**
  363 + * 注意:这里只考虑List的高度,如果有title或者headerView,不计入考虑中
  364 + */
  365 + protected int getListMaxHeight() {
  366 + return (int) (QMUIDisplayHelper.getScreenHeight(mContext) * 0.5);
  367 + }
  368 +
  369 + public void notifyDataSetChanged() {
  370 + if (mAdapter != null) {
  371 + mAdapter.notifyDataSetChanged();
  372 + }
  373 + if (needToScroll()) {
  374 + mContainerView.getLayoutParams().height = getListMaxHeight();
  375 + mContainerView.setSelection(mCheckedIndex);
  376 + }
  377 + }
  378 +
  379 + protected int getContentViewLayoutId() {
  380 + return R.layout.qmui_bottom_sheet_list;
  381 + }
  382 +
  383 + public interface OnSheetItemClickListener {
  384 + void onClick(BottomSheet dialog, View itemView, int position, String tag);
  385 + }
  386 +
  387 + private static class BottomSheetListItemData {
  388 +
  389 + String text;
  390 + String tag = "";
  391 + boolean isDisabled = false;
  392 + boolean split = false;
  393 + String subTitle;
  394 +
  395 + public BottomSheetListItemData(String text, String tag, String subTitle, boolean split) {
  396 + this.text = text;
  397 + this.tag = tag;
  398 + this.split = split;
  399 + this.subTitle = subTitle;
  400 + }
  401 +
  402 + public BottomSheetListItemData(String text, String tag) {
  403 + this.text = text;
  404 + this.tag = tag;
  405 + }
  406 +
  407 +
  408 + }
  409 +
  410 + private static class ViewHolder {
  411 + TextView textView;
  412 + TextView subTextView;
  413 + View bottonBar;
  414 + View itemView;
  415 + }
  416 +
  417 + private class ListAdapter extends BaseAdapter {
  418 +
  419 + @Override
  420 + public int getCount() {
  421 + return mItems.size();
  422 + }
  423 +
  424 + @Override
  425 + public BottomSheetListItemData getItem(int position) {
  426 + return mItems.get(position);
  427 + }
  428 +
  429 + @Override
  430 + public long getItemId(int position) {
  431 + return 0;
  432 + }
  433 +
  434 + @Override
  435 + public View getView(final int position, View convertView, ViewGroup parent) {
  436 + final BottomSheetListItemData data = getItem(position);
  437 + final ViewHolder holder;
  438 + if (convertView == null) {
  439 + LayoutInflater inflater = LayoutInflater.from(mContext);
  440 + convertView = inflater.inflate(R.layout.qmui_bottom_sheet_list_item, parent, false);
  441 + holder = new ViewHolder();
  442 + holder.textView = (TextView) convertView.findViewById(com.qmuiteam.qmui.R.id.bottom_dialog_list_item_title);
  443 + holder.bottonBar = convertView.findViewById(R.id.botton_bar);
  444 + holder.subTextView = convertView.findViewById(R.id.bottom_dialog_list_item_subtitle);
  445 + holder.itemView = convertView.findViewById(R.id.itemView);
  446 + convertView.setTag(holder);
  447 + } else {
  448 + holder = (ViewHolder) convertView.getTag();
  449 + }
  450 + // holder.textView.setTextColor(mContext.getResources().getColor(R.color.qmui_config_color_red));
  451 + if (data.text.equals("取消")){
  452 + holder.textView.setTextColor(mContext.getResources().getColor(R.color.gay));
  453 + }else {
  454 + holder.textView.setTextColor(mContext.getResources().getColor(R.color.green));
  455 + }
  456 + holder.textView.setText(data.text);
  457 +
  458 + if (data.isDisabled) {
  459 + holder.textView.setEnabled(false);
  460 + convertView.setEnabled(false);
  461 + } else {
  462 + holder.textView.setEnabled(true);
  463 + convertView.setEnabled(true);
  464 + }
  465 +
  466 + if (data.split) {
  467 + holder.bottonBar.setVisibility(View.VISIBLE);
  468 + } else {
  469 + holder.bottonBar.setVisibility(View.GONE);
  470 + }
  471 + if (TextUtils.isEmpty(data.subTitle)) {
  472 + holder.subTextView.setText("");
  473 + holder.subTextView.setVisibility(View.GONE);
  474 + holder.itemView.getLayoutParams().height = DensityUtils.dp2px(56);
  475 + } else {
  476 + holder.itemView.getLayoutParams().height = DensityUtils.dp2px(61);
  477 + holder.subTextView.setText(data.subTitle);
  478 + holder.subTextView.setVisibility(View.VISIBLE);
  479 + }
  480 +
  481 + convertView.setOnClickListener(new View.OnClickListener() {
  482 + @Override
  483 + public void onClick(View v) {
  484 + if (mOnSheetItemClickListener != null) {
  485 + mOnSheetItemClickListener.onClick(mDialog, v, position, data.tag);
  486 + }
  487 + }
  488 + });
  489 + return convertView;
  490 + }
  491 + }
  492 +
  493 + }
  494 +
  495 +}
... ...
core/base/src/main/java/com/cnlive/core/libs/base/ui/widget/switchbutton/ColorUtils.java 0 → 100644
  1 +package com.cnlive.core.libs.base.ui.widget.switchbutton;
  2 +
  3 +import android.content.res.ColorStateList;
  4 +
  5 +/**
  6 + * Generate thumb and background color state list use tintColor
  7 + * Created by kyle on 15/11/4.
  8 + */
  9 +public class ColorUtils {
  10 + private static final int ENABLE_ATTR = android.R.attr.state_enabled;
  11 + private static final int CHECKED_ATTR = android.R.attr.state_checked;
  12 + private static final int PRESSED_ATTR = android.R.attr.state_pressed;
  13 +
  14 + static ColorStateList generateThumbColorWithTintColor(final int tintColor) {
  15 + int[][] states = new int[][]{
  16 + {-ENABLE_ATTR, CHECKED_ATTR},
  17 + {-ENABLE_ATTR},
  18 + {PRESSED_ATTR, -CHECKED_ATTR},
  19 + {PRESSED_ATTR, CHECKED_ATTR},
  20 + {CHECKED_ATTR},
  21 + {-CHECKED_ATTR}
  22 + };
  23 +
  24 + int[] colors = new int[]{
  25 + tintColor - 0xAA000000,
  26 + 0xFFBABABA,
  27 + tintColor - 0x99000000,
  28 + tintColor - 0x99000000,
  29 + tintColor | 0xFF000000,
  30 + 0xFFEEEEEE
  31 + };
  32 + return new ColorStateList(states, colors);
  33 + }
  34 +
  35 + static ColorStateList generateBackColorWithTintColor(final int tintColor) {
  36 + int[][] states = new int[][]{
  37 + {-ENABLE_ATTR, CHECKED_ATTR},
  38 + {-ENABLE_ATTR},
  39 + {CHECKED_ATTR, PRESSED_ATTR},
  40 + {-CHECKED_ATTR, PRESSED_ATTR},
  41 + {CHECKED_ATTR},
  42 + {-CHECKED_ATTR}
  43 + };
  44 +
  45 + int[] colors = new int[]{
  46 + tintColor - 0xE1000000,
  47 + 0x10000000,
  48 + tintColor - 0xD0000000,
  49 + 0x20000000,
  50 + tintColor - 0xD0000000,
  51 + 0x20000000
  52 + };
  53 + return new ColorStateList(states, colors);
  54 + }
  55 +}
... ...
core/base/src/main/java/com/cnlive/core/libs/base/ui/widget/switchbutton/SwitchButton.java 0 → 100644
  1 +package com.cnlive.core.libs.base.ui.widget.switchbutton;
  2 +
  3 +import android.animation.ObjectAnimator;
  4 +import android.annotation.SuppressLint;
  5 +import android.content.Context;
  6 +import android.content.res.ColorStateList;
  7 +import android.content.res.Resources;
  8 +import android.content.res.TypedArray;
  9 +import android.graphics.Canvas;
  10 +import android.graphics.Color;
  11 +import android.graphics.Paint;
  12 +import android.graphics.PointF;
  13 +import android.graphics.RectF;
  14 +import android.graphics.drawable.Drawable;
  15 +import android.graphics.drawable.StateListDrawable;
  16 +import android.os.Parcel;
  17 +import android.os.Parcelable;
  18 +import android.text.Layout;
  19 +import android.text.StaticLayout;
  20 +import android.text.TextPaint;
  21 +import android.text.TextUtils;
  22 +import android.util.AttributeSet;
  23 +import android.util.TypedValue;
  24 +import android.view.MotionEvent;
  25 +import android.view.SoundEffectConstants;
  26 +import android.view.ViewConfiguration;
  27 +import android.view.ViewParent;
  28 +import android.view.animation.AccelerateDecelerateInterpolator;
  29 +import android.widget.CompoundButton;
  30 +
  31 +import androidx.core.content.ContextCompat;
  32 +
  33 +import com.cnlive.strike.base.R;
  34 +
  35 +
  36 +/**
  37 + * SwitchButton
  38 + *
  39 + * @author kyleduo
  40 + * @since 2014-09-24
  41 + */
  42 +
  43 +@SuppressWarnings("unused")
  44 +public class SwitchButton extends CompoundButton {
  45 + public static final float DEFAULT_THUMB_RANGE_RATIO = 1.8f;
  46 + public static final int DEFAULT_THUMB_SIZE_DP = 20;
  47 + public static final int DEFAULT_THUMB_MARGIN_DP = 2;
  48 + public static final int DEFAULT_ANIMATION_DURATION = 250;
  49 + public static final int DEFAULT_TINT_COLOR = 0x327FC2;
  50 +
  51 + private static int[] CHECKED_PRESSED_STATE = new int[]{android.R.attr.state_checked, android.R.attr.state_enabled, android.R.attr.state_pressed};
  52 + private static int[] UNCHECKED_PRESSED_STATE = new int[]{-android.R.attr.state_checked, android.R.attr.state_enabled, android.R.attr.state_pressed};
  53 +
  54 + private Drawable mThumbDrawable, mBackDrawable;
  55 + private ColorStateList mBackColor, mThumbColor;
  56 + private float mThumbRadius, mBackRadius;
  57 + private RectF mThumbMargin;
  58 + private float mThumbRangeRatio;
  59 + private long mAnimationDuration;
  60 + // fade back drawable or color when dragging or animating
  61 + private boolean mFadeBack;
  62 + private int mTintColor;
  63 + private int mThumbWidth;
  64 + private int mThumbHeight;
  65 + private int mBackWidth;
  66 + private int mBackHeight;
  67 +
  68 + private int mCurrThumbColor, mCurrBackColor, mNextBackColor, mOnTextColor, mOffTextColor;
  69 + private Drawable mCurrentBackDrawable, mNextBackDrawable;
  70 + private RectF mThumbRectF, mBackRectF, mSafeRectF, mTextOnRectF, mTextOffRectF;
  71 + private Paint mPaint;
  72 + // whether using Drawable for thumb or back
  73 + private boolean mIsThumbUseDrawable, mIsBackUseDrawable;
  74 + private boolean mDrawDebugRect = false;
  75 + private ObjectAnimator mProgressAnimator;
  76 + // animation control
  77 + private float mProgress;
  78 + // temp position of thumb when dragging or animating
  79 + private RectF mPresentThumbRectF;
  80 + private float mStartX, mStartY, mLastX;
  81 + private int mTouchSlop;
  82 + private int mClickTimeout;
  83 + private Paint mRectPaint;
  84 + private CharSequence mTextOn;
  85 + private CharSequence mTextOff;
  86 + private TextPaint mTextPaint;
  87 + private Layout mOnLayout;
  88 + private Layout mOffLayout;
  89 + private float mTextWidth;
  90 + private float mTextHeight;
  91 + private int mTextThumbInset;
  92 + private int mTextExtra;
  93 + private int mTextAdjust;
  94 + // FIX #78,#85 : When restoring saved states, setChecked() called by super. So disable
  95 + // animation and event listening when restoring.
  96 + private boolean mRestoring = false;
  97 + private boolean mReady = false;
  98 + private boolean mCatch = false;
  99 +
  100 + private OnCheckedChangeListener mChildOnCheckedChangeListener;
  101 +
  102 + public SwitchButton(Context context, AttributeSet attrs, int defStyle) {
  103 + super(context, attrs, defStyle);
  104 + init(attrs);
  105 + }
  106 +
  107 + public SwitchButton(Context context, AttributeSet attrs) {
  108 + super(context, attrs);
  109 + init(attrs);
  110 + }
  111 +
  112 + public SwitchButton(Context context) {
  113 + super(context);
  114 + init(null);
  115 + }
  116 +
  117 + private void init(AttributeSet attrs) {
  118 + mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
  119 + mClickTimeout = ViewConfiguration.getPressedStateDuration() + ViewConfiguration.getTapTimeout();
  120 +
  121 + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  122 + mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
  123 + mRectPaint.setStyle(Paint.Style.STROKE);
  124 + mRectPaint.setStrokeWidth(getResources().getDisplayMetrics().density);
  125 +
  126 + mTextPaint = getPaint();
  127 +
  128 + mThumbRectF = new RectF();
  129 + mBackRectF = new RectF();
  130 + mSafeRectF = new RectF();
  131 + mThumbMargin = new RectF();
  132 + mTextOnRectF = new RectF();
  133 + mTextOffRectF = new RectF();
  134 +
  135 + mProgressAnimator = ObjectAnimator.ofFloat(this, "progress", 0, 0).setDuration(DEFAULT_ANIMATION_DURATION);
  136 + mProgressAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
  137 +
  138 + mPresentThumbRectF = new RectF();
  139 +
  140 + Resources res = getResources();
  141 + float density = res.getDisplayMetrics().density;
  142 +
  143 + Drawable thumbDrawable = null;
  144 + ColorStateList thumbColor = null;
  145 + float margin = density * DEFAULT_THUMB_MARGIN_DP;
  146 + float marginLeft = 0;
  147 + float marginRight = 0;
  148 + float marginTop = 0;
  149 + float marginBottom = 0;
  150 + float thumbWidth = 0;
  151 + float thumbHeight = 0;
  152 + float thumbRadius = -1;
  153 + float backRadius = -1;
  154 + Drawable backDrawable = null;
  155 + ColorStateList backColor = null;
  156 + float thumbRangeRatio = DEFAULT_THUMB_RANGE_RATIO;
  157 + int animationDuration = DEFAULT_ANIMATION_DURATION;
  158 + boolean fadeBack = true;
  159 + int tintColor = 0;
  160 + String textOn = null;
  161 + String textOff = null;
  162 + int textThumbInset = 0;
  163 + int textExtra = 0;
  164 + int textAdjust = 0;
  165 +
  166 + TypedArray ta = attrs == null ? null : getContext().obtainStyledAttributes(attrs, R.styleable.SwitchButton);
  167 + if (ta != null) {
  168 + thumbDrawable = ta.getDrawable(R.styleable.SwitchButton_kswThumbDrawable);
  169 + thumbColor = ta.getColorStateList(R.styleable.SwitchButton_kswThumbColor);
  170 + margin = ta.getDimension(R.styleable.SwitchButton_kswThumbMargin, margin);
  171 + marginLeft = ta.getDimension(R.styleable.SwitchButton_kswThumbMarginLeft, margin);
  172 + marginRight = ta.getDimension(R.styleable.SwitchButton_kswThumbMarginRight, margin);
  173 + marginTop = ta.getDimension(R.styleable.SwitchButton_kswThumbMarginTop, margin);
  174 + marginBottom = ta.getDimension(R.styleable.SwitchButton_kswThumbMarginBottom, margin);
  175 + thumbWidth = ta.getDimension(R.styleable.SwitchButton_kswThumbWidth, thumbWidth);
  176 + thumbHeight = ta.getDimension(R.styleable.SwitchButton_kswThumbHeight, thumbHeight);
  177 + thumbRadius = ta.getDimension(R.styleable.SwitchButton_kswThumbRadius, thumbRadius);
  178 + backRadius = ta.getDimension(R.styleable.SwitchButton_kswBackRadius, backRadius);
  179 + backDrawable = ta.getDrawable(R.styleable.SwitchButton_kswBackDrawable);
  180 + backColor = ta.getColorStateList(R.styleable.SwitchButton_kswBackColor);
  181 + thumbRangeRatio = ta.getFloat(R.styleable.SwitchButton_kswThumbRangeRatio, thumbRangeRatio);
  182 + animationDuration = ta.getInteger(R.styleable.SwitchButton_kswAnimationDuration, animationDuration);
  183 + fadeBack = ta.getBoolean(R.styleable.SwitchButton_kswFadeBack, true);
  184 + tintColor = ta.getColor(R.styleable.SwitchButton_kswTintColor, tintColor);
  185 + textOn = ta.getString(R.styleable.SwitchButton_kswTextOn);
  186 + textOff = ta.getString(R.styleable.SwitchButton_kswTextOff);
  187 + textThumbInset = ta.getDimensionPixelSize(R.styleable.SwitchButton_kswTextThumbInset, 0);
  188 + textExtra = ta.getDimensionPixelSize(R.styleable.SwitchButton_kswTextExtra, 0);
  189 + textAdjust = ta.getDimensionPixelSize(R.styleable.SwitchButton_kswTextAdjust, 0);
  190 + ta.recycle();
  191 + }
  192 +
  193 + // click
  194 + ta = attrs == null ? null : getContext().obtainStyledAttributes(attrs, new int[]{android.R.attr.focusable, android.R.attr.clickable});
  195 + if (ta != null) {
  196 + boolean focusable = ta.getBoolean(0, true);
  197 + //noinspection ResourceType
  198 + @SuppressLint("ResourceType")
  199 + boolean clickable = ta.getBoolean(1, focusable);
  200 + setFocusable(focusable);
  201 + setClickable(clickable);
  202 + ta.recycle();
  203 + } else {
  204 + setFocusable(true);
  205 + setClickable(true);
  206 + }
  207 +
  208 + // text
  209 + mTextOn = textOn;
  210 + mTextOff = textOff;
  211 + mTextThumbInset = textThumbInset;
  212 + mTextExtra = textExtra;
  213 + mTextAdjust = textAdjust;
  214 +
  215 + // thumb drawable and color
  216 + mThumbDrawable = thumbDrawable;
  217 + mThumbColor = thumbColor;
  218 + mIsThumbUseDrawable = mThumbDrawable != null;
  219 + mTintColor = tintColor;
  220 + if (mTintColor == 0) {
  221 + TypedValue typedValue = new TypedValue();
  222 + boolean found = getContext().getTheme().resolveAttribute(R.attr.colorAccent, typedValue, true);
  223 + if (found) {
  224 + mTintColor = typedValue.data;
  225 + } else {
  226 + mTintColor = DEFAULT_TINT_COLOR;
  227 + }
  228 + }
  229 + if (!mIsThumbUseDrawable && mThumbColor == null) {
  230 + mThumbColor = ColorUtils.generateThumbColorWithTintColor(mTintColor);
  231 + mCurrThumbColor = mThumbColor.getDefaultColor();
  232 + }
  233 +
  234 + // thumbSize
  235 + mThumbWidth = ceil(thumbWidth);
  236 + mThumbHeight = ceil(thumbHeight);
  237 +
  238 + // back drawable and color
  239 + mBackDrawable = backDrawable;
  240 + mBackColor = backColor;
  241 + mIsBackUseDrawable = mBackDrawable != null;
  242 + if (!mIsBackUseDrawable && mBackColor == null) {
  243 + mBackColor = ColorUtils.generateBackColorWithTintColor(mTintColor);
  244 + mCurrBackColor = mBackColor.getDefaultColor();
  245 + mNextBackColor = mBackColor.getColorForState(CHECKED_PRESSED_STATE, mCurrBackColor);
  246 + }
  247 +
  248 + // margin
  249 + mThumbMargin.set(marginLeft, marginTop, marginRight, marginBottom);
  250 +
  251 + // size & measure params must larger than 1
  252 + mThumbRangeRatio = mThumbMargin.width() >= 0 ? Math.max(thumbRangeRatio, 1) : thumbRangeRatio;
  253 +
  254 + mThumbRadius = thumbRadius;
  255 + mBackRadius = backRadius;
  256 + mAnimationDuration = animationDuration;
  257 + mFadeBack = fadeBack;
  258 +
  259 + mProgressAnimator.setDuration(mAnimationDuration);
  260 +
  261 + // sync checked status
  262 + if (isChecked()) {
  263 + setProgress(1);
  264 + }
  265 + }
  266 +
  267 +
  268 + private Layout makeLayout(CharSequence text) {
  269 + return new StaticLayout(text, mTextPaint, (int) Math.ceil(Layout.getDesiredWidth(text, mTextPaint)), Layout.Alignment.ALIGN_CENTER, 1.f, 0, false);
  270 + }
  271 +
  272 + @Override
  273 + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  274 + /*
  275 + * ensure textLayout
  276 + */
  277 + if (mOnLayout == null && !TextUtils.isEmpty(mTextOn)) {
  278 + mOnLayout = makeLayout(mTextOn);
  279 + }
  280 + if (mOffLayout == null && !TextUtils.isEmpty(mTextOff)) {
  281 + mOffLayout = makeLayout(mTextOff);
  282 + }
  283 +
  284 + float onWidth = mOnLayout != null ? mOnLayout.getWidth() : 0;
  285 + float offWidth = mOffLayout != null ? mOffLayout.getWidth() : 0;
  286 + if (onWidth != 0 || offWidth != 0) {
  287 + mTextWidth = Math.max(onWidth, offWidth);
  288 + } else {
  289 + mTextWidth = 0;
  290 + }
  291 +
  292 + float onHeight = mOnLayout != null ? mOnLayout.getHeight() : 0;
  293 + float offHeight = mOffLayout != null ? mOffLayout.getHeight() : 0;
  294 + if (onHeight != 0 || offHeight != 0) {
  295 + mTextHeight = Math.max(onHeight, offHeight);
  296 + } else {
  297 + mTextHeight = 0;
  298 + }
  299 +
  300 + setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
  301 + }
  302 +
  303 + /**
  304 + * SwitchButton use this formula to determine the final size of thumb, background and itself.
  305 + *
  306 + * textWidth = max(onWidth, offWidth)
  307 + * thumbRange = thumbWidth * rangeRatio
  308 + * textExtraSpace = textWidth + textExtra - (moveRange - thumbWidth + max(thumbMargin.left, thumbMargin.right) + textThumbInset)
  309 + * backWidth = thumbRange + thumbMargin.left + thumbMargin.right + max(textExtraSpace, 0)
  310 + * contentSize = thumbRange + max(thumbMargin.left, 0) + max(thumbMargin.right, 0) + max(textExtraSpace, 0)
  311 + *
  312 + * @param widthMeasureSpec widthMeasureSpec
  313 + * @return measuredWidth
  314 + */
  315 + private int measureWidth(int widthMeasureSpec) {
  316 + int widthSize = MeasureSpec.getSize(widthMeasureSpec);
  317 + int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  318 + int measuredWidth = widthSize;
  319 +
  320 + if (mThumbWidth == 0 && mIsThumbUseDrawable) {
  321 + mThumbWidth = mThumbDrawable.getIntrinsicWidth();
  322 + }
  323 +
  324 + int moveRange;
  325 + int textWidth = ceil(mTextWidth);
  326 + // how much the background should extend to fit text.
  327 + int textExtraSpace;
  328 + int contentSize;
  329 +
  330 + if (mThumbRangeRatio == 0) {
  331 + mThumbRangeRatio = DEFAULT_THUMB_RANGE_RATIO;
  332 + }
  333 +
  334 + if (widthMode == MeasureSpec.EXACTLY) {
  335 + contentSize = widthSize - getPaddingLeft() - getPaddingRight();
  336 +
  337 + if (mThumbWidth != 0) {
  338 + moveRange = ceil(mThumbWidth * mThumbRangeRatio);
  339 + textExtraSpace = textWidth + mTextExtra - (moveRange - mThumbWidth + ceil(Math.max(mThumbMargin.left, mThumbMargin.right)));
  340 + mBackWidth = ceil(moveRange + mThumbMargin.left + mThumbMargin.right + Math.max(textExtraSpace, 0));
  341 + if (mBackWidth < 0) {
  342 + mThumbWidth = 0;
  343 + }
  344 + if (moveRange + Math.max(mThumbMargin.left, 0) + Math.max(mThumbMargin.right, 0) + Math.max(textExtraSpace, 0) > contentSize) {
  345 + mThumbWidth = 0;
  346 + }
  347 + }
  348 +
  349 + if (mThumbWidth == 0) {
  350 + contentSize = widthSize - getPaddingLeft() - getPaddingRight();
  351 + moveRange = ceil(contentSize - Math.max(mThumbMargin.left, 0) - Math.max(mThumbMargin.right, 0));
  352 + if (moveRange < 0) {
  353 + mThumbWidth = 0;
  354 + mBackWidth = 0;
  355 + return measuredWidth;
  356 + }
  357 + mThumbWidth = ceil(moveRange / mThumbRangeRatio);
  358 + mBackWidth = ceil(moveRange + mThumbMargin.left + mThumbMargin.right);
  359 + if (mBackWidth < 0) {
  360 + mThumbWidth = 0;
  361 + mBackWidth = 0;
  362 + return measuredWidth;
  363 + }
  364 + textExtraSpace = textWidth + mTextExtra - (moveRange - mThumbWidth + ceil(Math.max(mThumbMargin.left, mThumbMargin.right)));
  365 + if (textExtraSpace > 0) {
  366 + // since backWidth is determined by view width, so we can only reduce thumbSize.
  367 + mThumbWidth = mThumbWidth - textExtraSpace;
  368 + }
  369 + if (mThumbWidth < 0) {
  370 + mThumbWidth = 0;
  371 + mBackWidth = 0;
  372 + return measuredWidth;
  373 + }
  374 + }
  375 + } else {
  376 + /*
  377 + If parent view want SwitchButton to determine it's size itself, we calculate the minimal
  378 + size of it's content. Further more, we ignore the limitation of widthSize since we want
  379 + to display SwitchButton in its actual size rather than compress the shape.
  380 + */
  381 + if (mThumbWidth == 0) {
  382 + /*
  383 + If thumbWidth is not set, use the default one.
  384 + */
  385 + mThumbWidth = ceil(getResources().getDisplayMetrics().density * DEFAULT_THUMB_SIZE_DP);
  386 + }
  387 + if (mThumbRangeRatio == 0) {
  388 + mThumbRangeRatio = DEFAULT_THUMB_RANGE_RATIO;
  389 + }
  390 +
  391 + moveRange = ceil(mThumbWidth * mThumbRangeRatio);
  392 + textExtraSpace = ceil(textWidth + mTextExtra - (moveRange - mThumbWidth + Math.max(mThumbMargin.left, mThumbMargin.right) + mTextThumbInset));
  393 + mBackWidth = ceil(moveRange + mThumbMargin.left + mThumbMargin.right + Math.max(0, textExtraSpace));
  394 + if (mBackWidth < 0) {
  395 + mThumbWidth = 0;
  396 + mBackWidth = 0;
  397 + return measuredWidth;
  398 + }
  399 + contentSize = ceil(moveRange + Math.max(0, mThumbMargin.left) + Math.max(0, mThumbMargin.right) + Math.max(0, textExtraSpace));
  400 +
  401 + measuredWidth = Math.max(contentSize, contentSize + getPaddingLeft() + getPaddingRight());
  402 + }
  403 + return measuredWidth;
  404 + }
  405 +
  406 + private int measureHeight(int heightMeasureSpec) {
  407 + int heightSize = MeasureSpec.getSize(heightMeasureSpec);
  408 + int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  409 + int measuredHeight = heightSize;
  410 +
  411 + if (mThumbHeight == 0 && mIsThumbUseDrawable) {
  412 + mThumbHeight = mThumbDrawable.getIntrinsicHeight();
  413 + }
  414 + int contentSize;
  415 + int textExtraSpace;
  416 + if (heightMode == MeasureSpec.EXACTLY) {
  417 + if (mThumbHeight != 0) {
  418 + /*
  419 + If thumbHeight has been set, we calculate backHeight and check if there is enough room.
  420 + */
  421 + mBackHeight = ceil(mThumbHeight + mThumbMargin.top + mThumbMargin.bottom);
  422 + mBackHeight = ceil(Math.max(mBackHeight, mTextHeight));
  423 + if (mBackHeight + getPaddingTop() + getPaddingBottom() - Math.min(0, mThumbMargin.top) - Math.min(0, mThumbMargin.bottom) > heightSize) {
  424 + // No enough room, we set thumbHeight to zero to calculate these value again.
  425 + mThumbHeight = 0;
  426 + }
  427 + }
  428 +
  429 + if (mThumbHeight == 0) {
  430 + mBackHeight = ceil(heightSize - getPaddingTop() - getPaddingBottom() + Math.min(0, mThumbMargin.top) + Math.min(0, mThumbMargin.bottom));
  431 + if (mBackHeight < 0) {
  432 + mBackHeight = 0;
  433 + mThumbHeight = 0;
  434 + return measuredHeight;
  435 + }
  436 + mThumbHeight = ceil(mBackHeight - mThumbMargin.top - mThumbMargin.bottom);
  437 + }
  438 + if (mThumbHeight < 0) {
  439 + mBackHeight = 0;
  440 + mThumbHeight = 0;
  441 + return measuredHeight;
  442 + }
  443 + } else {
  444 + if (mThumbHeight == 0) {
  445 + mThumbHeight = ceil(getResources().getDisplayMetrics().density * DEFAULT_THUMB_SIZE_DP);
  446 + }
  447 + mBackHeight = ceil(mThumbHeight + mThumbMargin.top + mThumbMargin.bottom);
  448 + if (mBackHeight < 0) {
  449 + mBackHeight = 0;
  450 + mThumbHeight = 0;
  451 + return measuredHeight;
  452 + }
  453 + textExtraSpace = ceil(mTextHeight - mBackHeight);
  454 + if (textExtraSpace > 0) {
  455 + mBackHeight += textExtraSpace;
  456 + mThumbHeight += textExtraSpace;
  457 + }
  458 + contentSize = Math.max(mThumbHeight, mBackHeight);
  459 +
  460 + measuredHeight = Math.max(contentSize, contentSize + getPaddingTop() + getPaddingBottom());
  461 + measuredHeight = Math.max(measuredHeight, getSuggestedMinimumHeight());
  462 + }
  463 +
  464 + return measuredHeight;
  465 + }
  466 +
  467 + @Override
  468 + protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  469 + super.onSizeChanged(w, h, oldw, oldh);
  470 + if (w != oldw || h != oldh) {
  471 + setup();
  472 + }
  473 + }
  474 +
  475 + private int ceil(double dimen) {
  476 + return (int) Math.ceil(dimen);
  477 + }
  478 +
  479 + /**
  480 + * set up the rect of back and thumb
  481 + */
  482 + private void setup() {
  483 + if (mThumbWidth == 0 || mThumbHeight == 0 || mBackWidth == 0 || mBackHeight == 0) {
  484 + return;
  485 + }
  486 +
  487 + if (mThumbRadius == -1) {
  488 + mThumbRadius = Math.min(mThumbWidth, mThumbHeight) / 2;
  489 + }
  490 + if (mBackRadius == -1) {
  491 + mBackRadius = Math.min(mBackWidth, mBackHeight) / 2;
  492 + }
  493 +
  494 + int contentWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
  495 + int contentHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
  496 +
  497 + // max range of drawing content, when thumbMargin is negative, drawing range is larger than backWidth
  498 + int drawingWidth = ceil(mBackWidth - Math.min(0, mThumbMargin.left) - Math.min(0, mThumbMargin.right));
  499 + int drawingHeight = ceil(mBackHeight - Math.min(0, mThumbMargin.top) - Math.min(0, mThumbMargin.bottom));
  500 +
  501 + float thumbTop;
  502 + if (contentHeight <= drawingHeight) {
  503 + thumbTop = getPaddingTop() + Math.max(0, mThumbMargin.top);
  504 + } else {
  505 + // center vertical in content area
  506 + thumbTop = getPaddingTop() + Math.max(0, mThumbMargin.top) + (contentHeight - drawingHeight + 1) / 2;
  507 + }
  508 +
  509 + float thumbLeft;
  510 + if (contentWidth <= mBackWidth) {
  511 + thumbLeft = getPaddingLeft() + Math.max(0, mThumbMargin.left);
  512 + } else {
  513 + thumbLeft = getPaddingLeft() + Math.max(0, mThumbMargin.left) + (contentWidth - drawingWidth + 1) / 2;
  514 + }
  515 +
  516 + mThumbRectF.set(thumbLeft, thumbTop, thumbLeft + mThumbWidth, thumbTop + mThumbHeight);
  517 +
  518 + float backLeft = mThumbRectF.left - mThumbMargin.left;
  519 + mBackRectF.set(backLeft,
  520 + mThumbRectF.top - mThumbMargin.top,
  521 + backLeft + mBackWidth,
  522 + mThumbRectF.top - mThumbMargin.top + mBackHeight);
  523 +
  524 + mSafeRectF.set(mThumbRectF.left, 0, mBackRectF.right - mThumbMargin.right - mThumbRectF.width(), 0);
  525 +
  526 + float minBackRadius = Math.min(mBackRectF.width(), mBackRectF.height()) / 2.f;
  527 + mBackRadius = Math.min(minBackRadius, mBackRadius);
  528 +
  529 + if (mBackDrawable != null) {
  530 + mBackDrawable.setBounds((int) mBackRectF.left, (int) mBackRectF.top, ceil(mBackRectF.right), ceil(mBackRectF.bottom));
  531 + }
  532 +
  533 + if (mOnLayout != null) {
  534 + float onLeft = mBackRectF.left + (mBackRectF.width() + mTextThumbInset - mThumbWidth - mThumbMargin.right - mOnLayout.getWidth()) / 2f - mTextAdjust;
  535 + float onTop = mBackRectF.top + (mBackRectF.height() - mOnLayout.getHeight()) / 2;
  536 + mTextOnRectF.set(onLeft, onTop, onLeft + mOnLayout.getWidth(), onTop + mOnLayout.getHeight());
  537 + }
  538 +
  539 + if (mOffLayout != null) {
  540 + float offLeft = mBackRectF.right - (mBackRectF.width() + mTextThumbInset - mThumbWidth - mThumbMargin.left - mOffLayout.getWidth()) / 2f - mOffLayout.getWidth() + mTextAdjust;
  541 + float offTop = mBackRectF.top + (mBackRectF.height() - mOffLayout.getHeight()) / 2;
  542 + mTextOffRectF.set(offLeft, offTop, offLeft + mOffLayout.getWidth(), offTop + mOffLayout.getHeight());
  543 + }
  544 +
  545 + mReady = true;
  546 + }
  547 +
  548 + @Override
  549 + protected void onDraw(Canvas canvas) {
  550 + super.onDraw(canvas);
  551 +
  552 + if (!mReady) {
  553 + setup();
  554 + }
  555 + if (!mReady) {
  556 + return;
  557 + }
  558 +
  559 + // fade back
  560 + if (mIsBackUseDrawable) {
  561 + if (mFadeBack && mCurrentBackDrawable != null && mNextBackDrawable != null) {
  562 + // fix #75, 70%A + 30%B != 30%B + 70%A, order matters when mix two layer of different alpha.
  563 + // So make sure the order of on/off layers never change during slide from one endpoint to another.
  564 + Drawable below = isChecked() ? mCurrentBackDrawable : mNextBackDrawable;
  565 + Drawable above = isChecked() ? mNextBackDrawable : mCurrentBackDrawable;
  566 +
  567 + int alpha = (int) (255 * getProgress());
  568 + below.setAlpha(alpha);
  569 + below.draw(canvas);
  570 + alpha = 255 - alpha;
  571 + above.setAlpha(alpha);
  572 + above.draw(canvas);
  573 + } else {
  574 + mBackDrawable.setAlpha(255);
  575 + mBackDrawable.draw(canvas);
  576 + }
  577 + } else {
  578 + if (mFadeBack) {
  579 + int alpha;
  580 + int colorAlpha;
  581 +
  582 + // fix #75
  583 + int belowColor = isChecked() ? mCurrBackColor : mNextBackColor;
  584 + int aboveColor = isChecked() ? mNextBackColor : mCurrBackColor;
  585 +
  586 + // curr back
  587 + alpha = (int) (255 * getProgress());
  588 + colorAlpha = Color.alpha(belowColor);
  589 + colorAlpha = colorAlpha * alpha / 255;
  590 + mPaint.setARGB(colorAlpha, Color.red(belowColor), Color.green(belowColor), Color.blue(belowColor));
  591 + canvas.drawRoundRect(mBackRectF, mBackRadius, mBackRadius, mPaint);
  592 +
  593 + // next back
  594 + alpha = 255 - alpha;
  595 + colorAlpha = Color.alpha(aboveColor);
  596 + colorAlpha = colorAlpha * alpha / 255;
  597 + mPaint.setARGB(colorAlpha, Color.red(aboveColor), Color.green(aboveColor), Color.blue(aboveColor));
  598 + canvas.drawRoundRect(mBackRectF, mBackRadius, mBackRadius, mPaint);
  599 +
  600 + mPaint.setAlpha(255);
  601 + } else {
  602 + mPaint.setColor(mCurrBackColor);
  603 + canvas.drawRoundRect(mBackRectF, mBackRadius, mBackRadius, mPaint);
  604 + }
  605 + }
  606 +
  607 + // text
  608 + Layout switchText = getProgress() > 0.5 ? mOnLayout : mOffLayout;
  609 + RectF textRectF = getProgress() > 0.5 ? mTextOnRectF : mTextOffRectF;
  610 + if (switchText != null && textRectF != null) {
  611 + int alpha = (int) (255 * (getProgress() >= 0.75 ? getProgress() * 4 - 3 : (getProgress() < 0.25 ? 1 - getProgress() * 4 : 0)));
  612 + int textColor = getProgress() > 0.5 ? mOnTextColor : mOffTextColor;
  613 + int colorAlpha = Color.alpha(textColor);
  614 + colorAlpha = colorAlpha * alpha / 255;
  615 + switchText.getPaint().setARGB(colorAlpha, Color.red(textColor), Color.green(textColor), Color.blue(textColor));
  616 + canvas.save();
  617 + canvas.translate(textRectF.left, textRectF.top);
  618 + switchText.draw(canvas);
  619 + canvas.restore();
  620 + }
  621 +
  622 + // thumb
  623 + mPresentThumbRectF.set(mThumbRectF);
  624 + mPresentThumbRectF.offset(mProgress * mSafeRectF.width(), 0);
  625 + if (mIsThumbUseDrawable) {
  626 + mThumbDrawable.setBounds((int) mPresentThumbRectF.left, (int) mPresentThumbRectF.top, ceil(mPresentThumbRectF.right), ceil(mPresentThumbRectF.bottom));
  627 + mThumbDrawable.draw(canvas);
  628 + } else {
  629 + mPaint.setColor(mCurrThumbColor);
  630 + canvas.drawRoundRect(mPresentThumbRectF, mThumbRadius, mThumbRadius, mPaint);
  631 + }
  632 +
  633 + if (mDrawDebugRect) {
  634 + mRectPaint.setColor(Color.parseColor("#AA0000"));
  635 + canvas.drawRect(mBackRectF, mRectPaint);
  636 + mRectPaint.setColor(Color.parseColor("#0000FF"));
  637 + canvas.drawRect(mPresentThumbRectF, mRectPaint);
  638 + mRectPaint.setColor(Color.parseColor("#000000"));
  639 + canvas.drawLine(mSafeRectF.left, mThumbRectF.top, mSafeRectF.right, mThumbRectF.top, mRectPaint);
  640 + mRectPaint.setColor(Color.parseColor("#00CC00"));
  641 + canvas.drawRect(getProgress() > 0.5 ? mTextOnRectF : mTextOffRectF, mRectPaint);
  642 + }
  643 + }
  644 +
  645 + @Override
  646 + protected void drawableStateChanged() {
  647 + super.drawableStateChanged();
  648 +
  649 + if (!mIsThumbUseDrawable && mThumbColor != null) {
  650 + mCurrThumbColor = mThumbColor.getColorForState(getDrawableState(), mCurrThumbColor);
  651 + } else {
  652 + setDrawableState(mThumbDrawable);
  653 + }
  654 +
  655 + int[] nextState = isChecked() ? UNCHECKED_PRESSED_STATE : CHECKED_PRESSED_STATE;
  656 + ColorStateList textColors = getTextColors();
  657 + if (textColors != null) {
  658 + int defaultTextColor = textColors.getDefaultColor();
  659 + mOnTextColor = textColors.getColorForState(CHECKED_PRESSED_STATE, defaultTextColor);
  660 + mOffTextColor = textColors.getColorForState(UNCHECKED_PRESSED_STATE, defaultTextColor);
  661 + }
  662 + if (!mIsBackUseDrawable && mBackColor != null) {
  663 + mCurrBackColor = mBackColor.getColorForState(getDrawableState(), mCurrBackColor);
  664 + mNextBackColor = mBackColor.getColorForState(nextState, mCurrBackColor);
  665 + } else {
  666 + if (mBackDrawable instanceof StateListDrawable && mFadeBack) {
  667 + mBackDrawable.setState(nextState);
  668 + mNextBackDrawable = mBackDrawable.getCurrent().mutate();
  669 + } else {
  670 + mNextBackDrawable = null;
  671 + }
  672 + setDrawableState(mBackDrawable);
  673 + if (mBackDrawable != null) {
  674 + mCurrentBackDrawable = mBackDrawable.getCurrent().mutate();
  675 + }
  676 + }
  677 + }
  678 +
  679 + @Override
  680 + public boolean onTouchEvent(MotionEvent event) {
  681 +
  682 + if (!isEnabled() || !isClickable() || !isFocusable() || !mReady) {
  683 + return false;
  684 + }
  685 +
  686 + int action = event.getAction();
  687 +
  688 + float deltaX = event.getX() - mStartX;
  689 + float deltaY = event.getY() - mStartY;
  690 +
  691 + switch (action) {
  692 + case MotionEvent.ACTION_DOWN:
  693 + mStartX = event.getX();
  694 + mStartY = event.getY();
  695 + mLastX = mStartX;
  696 + setPressed(true);
  697 + break;
  698 +
  699 + case MotionEvent.ACTION_MOVE:
  700 + float x = event.getX();
  701 + setProgress(getProgress() + (x - mLastX) / mSafeRectF.width());
  702 + if (!mCatch && (Math.abs(deltaX) > mTouchSlop / 2 || Math.abs(deltaY) > mTouchSlop / 2)) {
  703 + if (deltaY == 0 || Math.abs(deltaX) > Math.abs(deltaY)) {
  704 + catchView();
  705 + } else if (Math.abs(deltaY) > Math.abs(deltaX)) {
  706 + return false;
  707 + }
  708 + }
  709 + mLastX = x;
  710 + break;
  711 +
  712 + case MotionEvent.ACTION_CANCEL:
  713 + case MotionEvent.ACTION_UP:
  714 + mCatch = false;
  715 + setPressed(false);
  716 + float time = event.getEventTime() - event.getDownTime();
  717 + if (Math.abs(deltaX) < mTouchSlop && Math.abs(deltaY) < mTouchSlop && time < mClickTimeout) {
  718 + performClick();
  719 + } else {
  720 + boolean nextStatus = getStatusBasedOnPos();
  721 + if (nextStatus != isChecked()) {
  722 + playSoundEffect(SoundEffectConstants.CLICK);
  723 + setChecked(nextStatus);
  724 + } else {
  725 + animateToState(nextStatus);
  726 + }
  727 + }
  728 + break;
  729 +
  730 + default:
  731 + break;
  732 + }
  733 + return true;
  734 + }
  735 +
  736 +
  737 + /**
  738 + * return the status based on position of thumb
  739 + *
  740 + * @return whether checked or not
  741 + */
  742 + private boolean getStatusBasedOnPos() {
  743 + return getProgress() > 0.5f;
  744 + }
  745 +
  746 + private float getProgress() {
  747 + return mProgress;
  748 + }
  749 +
  750 + private void setProgress(final float progress) {
  751 + float tp = progress;
  752 + if (tp > 1) {
  753 + tp = 1;
  754 + } else if (tp < 0) {
  755 + tp = 0;
  756 + }
  757 + this.mProgress = tp;
  758 + invalidate();
  759 + }
  760 +
  761 + @Override
  762 + public boolean performClick() {
  763 + return super.performClick();
  764 + }
  765 +
  766 + /**
  767 + * processing animation
  768 + *
  769 + * @param checked checked or unChecked
  770 + */
  771 + protected void animateToState(boolean checked) {
  772 + if (mProgressAnimator == null) {
  773 + return;
  774 + }
  775 + if (mProgressAnimator.isRunning()) {
  776 + mProgressAnimator.cancel();
  777 + }
  778 + mProgressAnimator.setDuration(mAnimationDuration);
  779 + if (checked) {
  780 + mProgressAnimator.setFloatValues(mProgress, 1f);
  781 + } else {
  782 + mProgressAnimator.setFloatValues(mProgress, 0);
  783 + }
  784 + mProgressAnimator.start();
  785 + }
  786 +
  787 + private void catchView() {
  788 + ViewParent parent = getParent();
  789 + if (parent != null) {
  790 + parent.requestDisallowInterceptTouchEvent(true);
  791 + }
  792 + mCatch = true;
  793 + }
  794 +
  795 + @Override
  796 + public void setChecked(final boolean checked) {
  797 + // animate before super.setChecked() become user may call setChecked again in OnCheckedChangedListener
  798 + if (isChecked() != checked) {
  799 + animateToState(checked);
  800 + }
  801 + if (mRestoring) {
  802 + setCheckedImmediatelyNoEvent(checked);
  803 + } else {
  804 + super.setChecked(checked);
  805 + }
  806 + }
  807 +
  808 + public void setCheckedNoEvent(final boolean checked) {
  809 + if (mChildOnCheckedChangeListener == null) {
  810 + setChecked(checked);
  811 + } else {
  812 + super.setOnCheckedChangeListener(null);
  813 + setChecked(checked);
  814 + super.setOnCheckedChangeListener(mChildOnCheckedChangeListener);
  815 + }
  816 + }
  817 +
  818 + public void setCheckedImmediatelyNoEvent(boolean checked) {
  819 + if (mChildOnCheckedChangeListener == null) {
  820 + setCheckedImmediately(checked);
  821 + } else {
  822 + super.setOnCheckedChangeListener(null);
  823 + setCheckedImmediately(checked);
  824 + super.setOnCheckedChangeListener(mChildOnCheckedChangeListener);
  825 + }
  826 + }
  827 +
  828 + public void toggleNoEvent() {
  829 + if (mChildOnCheckedChangeListener == null) {
  830 + toggle();
  831 + } else {
  832 + super.setOnCheckedChangeListener(null);
  833 + toggle();
  834 + super.setOnCheckedChangeListener(mChildOnCheckedChangeListener);
  835 + }
  836 + }
  837 +
  838 + public void toggleImmediatelyNoEvent() {
  839 + if (mChildOnCheckedChangeListener == null) {
  840 + toggleImmediately();
  841 + } else {
  842 + super.setOnCheckedChangeListener(null);
  843 + toggleImmediately();
  844 + super.setOnCheckedChangeListener(mChildOnCheckedChangeListener);
  845 + }
  846 + }
  847 +
  848 + @Override
  849 + public void setOnCheckedChangeListener(OnCheckedChangeListener onCheckedChangeListener) {
  850 + super.setOnCheckedChangeListener(onCheckedChangeListener);
  851 + mChildOnCheckedChangeListener = onCheckedChangeListener;
  852 + }
  853 +
  854 + public void setCheckedImmediately(boolean checked) {
  855 + super.setChecked(checked);
  856 + if (mProgressAnimator != null && mProgressAnimator.isRunning()) {
  857 + mProgressAnimator.cancel();
  858 + }
  859 + setProgress(checked ? 1 : 0);
  860 + invalidate();
  861 + }
  862 +
  863 + public void toggleImmediately() {
  864 + setCheckedImmediately(!isChecked());
  865 + }
  866 +
  867 + private void setDrawableState(Drawable drawable) {
  868 + if (drawable != null) {
  869 + int[] myDrawableState = getDrawableState();
  870 + drawable.setState(myDrawableState);
  871 + invalidate();
  872 + }
  873 + }
  874 +
  875 + public boolean isDrawDebugRect() {
  876 + return mDrawDebugRect;
  877 + }
  878 +
  879 + public void setDrawDebugRect(boolean drawDebugRect) {
  880 + mDrawDebugRect = drawDebugRect;
  881 + invalidate();
  882 + }
  883 +
  884 + public long getAnimationDuration() {
  885 + return mAnimationDuration;
  886 + }
  887 +
  888 + public void setAnimationDuration(long animationDuration) {
  889 + mAnimationDuration = animationDuration;
  890 + }
  891 +
  892 + public Drawable getThumbDrawable() {
  893 + return mThumbDrawable;
  894 + }
  895 +
  896 + public void setThumbDrawable(Drawable thumbDrawable) {
  897 + mThumbDrawable = thumbDrawable;
  898 + mIsThumbUseDrawable = mThumbDrawable != null;
  899 + refreshDrawableState();
  900 + mReady = false;
  901 + requestLayout();
  902 + invalidate();
  903 + }
  904 +
  905 + public void setThumbDrawableRes(int thumbDrawableRes) {
  906 + setThumbDrawable(ContextCompat.getDrawable(getContext(), thumbDrawableRes));
  907 + }
  908 +
  909 + public Drawable getBackDrawable() {
  910 + return mBackDrawable;
  911 + }
  912 +
  913 + public void setBackDrawable(Drawable backDrawable) {
  914 + mBackDrawable = backDrawable;
  915 + mIsBackUseDrawable = mBackDrawable != null;
  916 + refreshDrawableState();
  917 + mReady = false;
  918 + requestLayout();
  919 + invalidate();
  920 + }
  921 +
  922 + public void setBackDrawableRes(int backDrawableRes) {
  923 + setBackDrawable(ContextCompat.getDrawable(getContext(), backDrawableRes));
  924 + }
  925 +
  926 + public ColorStateList getBackColor() {
  927 + return mBackColor;
  928 + }
  929 +
  930 + public void setBackColor(ColorStateList backColor) {
  931 + mBackColor = backColor;
  932 + if (mBackColor != null) {
  933 + setBackDrawable(null);
  934 + }
  935 + invalidate();
  936 + }
  937 +
  938 + public void setBackColorRes(int backColorRes) {
  939 + setBackColor(ContextCompat.getColorStateList(getContext(), backColorRes));
  940 + }
  941 +
  942 + public ColorStateList getThumbColor() {
  943 + return mThumbColor;
  944 + }
  945 +
  946 + public void setThumbColor(ColorStateList thumbColor) {
  947 + mThumbColor = thumbColor;
  948 + if (mThumbColor != null) {
  949 + setThumbDrawable(null);
  950 + }
  951 + invalidate();
  952 + }
  953 +
  954 + public void setThumbColorRes(int thumbColorRes) {
  955 + setThumbColor(ContextCompat.getColorStateList(getContext(), thumbColorRes));
  956 + }
  957 +
  958 + public float getThumbRangeRatio() {
  959 + return mThumbRangeRatio;
  960 + }
  961 +
  962 + public void setThumbRangeRatio(float thumbRangeRatio) {
  963 + mThumbRangeRatio = thumbRangeRatio;
  964 + // We need to mark "ready" to false since requestLayout may not cause size changed.
  965 + mReady = false;
  966 + requestLayout();
  967 + }
  968 +
  969 + public RectF getThumbMargin() {
  970 + return mThumbMargin;
  971 + }
  972 +
  973 + public void setThumbMargin(RectF thumbMargin) {
  974 + if (thumbMargin == null) {
  975 + setThumbMargin(0, 0, 0, 0);
  976 + } else {
  977 + setThumbMargin(thumbMargin.left, thumbMargin.top, thumbMargin.right, thumbMargin.bottom);
  978 + }
  979 + }
  980 +
  981 + public void setThumbMargin(float left, float top, float right, float bottom) {
  982 + mThumbMargin.set(left, top, right, bottom);
  983 + mReady = false;
  984 + requestLayout();
  985 + }
  986 +
  987 + public void setThumbSize(int width, int height) {
  988 + mThumbWidth = width;
  989 + mThumbHeight = height;
  990 + mReady = false;
  991 + requestLayout();
  992 + }
  993 +
  994 + public float getThumbWidth() {
  995 + return mThumbWidth;
  996 + }
  997 +
  998 + public float getThumbHeight() {
  999 + return mThumbHeight;
  1000 + }
  1001 +
  1002 + public float getThumbRadius() {
  1003 + return mThumbRadius;
  1004 + }
  1005 +
  1006 + public void setThumbRadius(float thumbRadius) {
  1007 + mThumbRadius = thumbRadius;
  1008 + if (!mIsThumbUseDrawable) {
  1009 + invalidate();
  1010 + }
  1011 + }
  1012 +
  1013 + public PointF getBackSizeF() {
  1014 + return new PointF(mBackRectF.width(), mBackRectF.height());
  1015 + }
  1016 +
  1017 + public float getBackRadius() {
  1018 + return mBackRadius;
  1019 + }
  1020 +
  1021 + public void setBackRadius(float backRadius) {
  1022 + mBackRadius = backRadius;
  1023 + if (!mIsBackUseDrawable) {
  1024 + invalidate();
  1025 + }
  1026 + }
  1027 +
  1028 + public boolean isFadeBack() {
  1029 + return mFadeBack;
  1030 + }
  1031 +
  1032 + public void setFadeBack(boolean fadeBack) {
  1033 + mFadeBack = fadeBack;
  1034 + }
  1035 +
  1036 + public int getTintColor() {
  1037 + return mTintColor;
  1038 + }
  1039 +
  1040 + public void setTintColor(@SuppressWarnings("SameParameterValue") int tintColor) {
  1041 + mTintColor = tintColor;
  1042 + mThumbColor = ColorUtils.generateThumbColorWithTintColor(mTintColor);
  1043 + mBackColor = ColorUtils.generateBackColorWithTintColor(mTintColor);
  1044 + mIsBackUseDrawable = false;
  1045 + mIsThumbUseDrawable = false;
  1046 + // call this method to refresh color states
  1047 + refreshDrawableState();
  1048 + invalidate();
  1049 + }
  1050 +
  1051 + public void setText(CharSequence onText, CharSequence offText) {
  1052 + mTextOn = onText;
  1053 + mTextOff = offText;
  1054 +
  1055 + mOnLayout = null;
  1056 + mOffLayout = null;
  1057 +
  1058 + mReady = false;
  1059 + requestLayout();
  1060 + invalidate();
  1061 + }
  1062 +
  1063 + public CharSequence getTextOn() {
  1064 + return mTextOn;
  1065 + }
  1066 +
  1067 + public CharSequence getTextOff() {
  1068 + return mTextOff;
  1069 + }
  1070 +
  1071 + public void setTextThumbInset(int textThumbInset) {
  1072 + mTextThumbInset = textThumbInset;
  1073 + mReady = false;
  1074 + requestLayout();
  1075 + invalidate();
  1076 + }
  1077 +
  1078 + public void setTextExtra(int textExtra) {
  1079 + mTextExtra = textExtra;
  1080 + mReady = false;
  1081 + requestLayout();
  1082 + invalidate();
  1083 + }
  1084 +
  1085 + public void setTextAdjust(int textAdjust) {
  1086 + mTextAdjust = textAdjust;
  1087 + mReady = false;
  1088 + requestLayout();
  1089 + invalidate();
  1090 + }
  1091 +
  1092 + @Override
  1093 + public Parcelable onSaveInstanceState() {
  1094 + Parcelable superState = super.onSaveInstanceState();
  1095 + SavedState ss = new SavedState(superState);
  1096 + ss.onText = mTextOn;
  1097 + ss.offText = mTextOff;
  1098 + return ss;
  1099 + }
  1100 +
  1101 + @Override
  1102 + public void onRestoreInstanceState(Parcelable state) {
  1103 + SavedState ss = (SavedState) state;
  1104 + setText(ss.onText, ss.offText);
  1105 + mRestoring = true;
  1106 + super.onRestoreInstanceState(ss.getSuperState());
  1107 + mRestoring = false;
  1108 + }
  1109 +
  1110 + static class SavedState extends BaseSavedState {
  1111 + CharSequence onText;
  1112 + CharSequence offText;
  1113 +
  1114 + SavedState(Parcelable superState) {
  1115 + super(superState);
  1116 + }
  1117 +
  1118 + private SavedState(Parcel in) {
  1119 + super(in);
  1120 + onText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
  1121 + offText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
  1122 + }
  1123 +
  1124 + @Override
  1125 + public void writeToParcel(Parcel out, int flags) {
  1126 + super.writeToParcel(out, flags);
  1127 + TextUtils.writeToParcel(onText, out, flags);
  1128 + TextUtils.writeToParcel(offText, out, flags);
  1129 + }
  1130 +
  1131 + public static final Creator<SavedState> CREATOR
  1132 + = new Creator<SavedState>() {
  1133 + public SavedState createFromParcel(Parcel in) {
  1134 + return new SavedState(in);
  1135 + }
  1136 +
  1137 + public SavedState[] newArray(int size) {
  1138 + return new SavedState[size];
  1139 + }
  1140 + };
  1141 + }
  1142 +}
0 1143 \ No newline at end of file
... ...
core/base/src/main/java/com/cnlive/core/libs/base/util/CheckUtil.java
1 1 package com.cnlive.core.libs.base.util;
2 2  
3 3 import android.app.Activity;
  4 +import android.content.Context;
4 5 import android.content.Intent;
5 6 import android.content.pm.PackageManager;
  7 +import android.location.LocationManager;
6 8 import android.net.Uri;
7 9 import android.os.PowerManager;
8 10 import android.provider.Settings;
9 11 import android.widget.Toast;
10 12  
  13 +
  14 +import com.cnlive.strike.base.R;
  15 +
11 16 import static android.content.Context.POWER_SERVICE;
12 17  
13 18 public class CheckUtil {
  19 + /**
  20 + * 判断GPS是否开启,GPS或者AGPS开启一个就认为是开启的
  21 + *
  22 + * @param context
  23 + * @return true 表示开启
  24 + */
  25 + public static final boolean isOPenGps(final Context context) {
  26 + try {
  27 + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
  28 + LocationManager locationManager
  29 + = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
  30 + // 通过GPS卫星定位,定位级别可以精确到街(通过24颗卫星定位,在室外和空旷的地方定位准确、速度快)
  31 + boolean gps = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
  32 + // 通过WLAN或移动网络(3G/2G)确定的位置(也称作AGPS,辅助GPS定位。主要用于在室内或遮盖物(建筑群或茂密的深林等)密集的地方定位)
  33 + boolean network = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
  34 + if (gps) {
  35 + return true;
  36 + } else {
  37 + return false;
  38 + }
  39 + } else {
  40 + return true;
  41 + }
  42 + } catch (Exception e) {
  43 + //异常就返回true
  44 + return true;
  45 + }
  46 + }
14 47  
  48 + public static void openGPS(Activity context) {
  49 + //开启GPS
  50 + try {
  51 + Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
  52 + context.startActivityForResult(intent, 10);
  53 + Toast.makeText(context, context.getString(R.string.open_gps_tip), Toast.LENGTH_LONG).show();
  54 + } catch (Exception e) {
  55 + Toast.makeText(context, "请手动打开GPS", Toast.LENGTH_LONG).show();
  56 + }
  57 + }
15 58 /**
16 59 * 锤子手机不能检测电池白名单,会崩溃
17 60 *
... ...
core/base/src/main/java/com/cnlive/core/libs/base/util/SimpleDES.java 0 → 100644
  1 +package com.cnlive.core.libs.base.util;
  2 +
  3 +import android.util.Base64;
  4 +
  5 +import java.security.Key;
  6 +
  7 +import javax.crypto.Cipher;
  8 +import javax.crypto.SecretKeyFactory;
  9 +import javax.crypto.spec.DESKeySpec;
  10 +
  11 +import static javax.crypto.Cipher.getInstance;
  12 +
  13 +/**
  14 + * 加密工具
  15 + */
  16 +public class SimpleDES {
  17 + //key 的长度得大于8
  18 + public static final String DES_KEY = "cnliveIm";
  19 + private static String encoding = "UTF-8";
  20 +
  21 + /**
  22 + * 加密字符串
  23 + */
  24 + public static String ebotongEncrypto(String str, String key) {
  25 + String result = str;
  26 + if (str != null && str.length() > 0) {
  27 + try {
  28 + byte[] encodeByte = symmetricEncrypto(str.getBytes(encoding), key);
  29 + result = Base64.encodeToString(encodeByte, Base64.DEFAULT);
  30 +
  31 + } catch (Exception e) {
  32 + // e.printStackTrace();
  33 + }
  34 + }
  35 + return result;
  36 + }
  37 +
  38 + /**
  39 + * 解密字符串
  40 + */
  41 + public static String ebotongDecrypto(String str, String key) {
  42 + String result = str;
  43 + if (str != null && str.length() > 0) {
  44 + try {
  45 + byte[] encodeByte = Base64.decode(str, Base64.DEFAULT);
  46 +
  47 + byte[] decoder = symmetricDecrypto(encodeByte, key);
  48 + result = new String(decoder, encoding);
  49 + } catch (Exception e) {
  50 + // e.printStackTrace();
  51 + }
  52 + }
  53 + return result;
  54 + }
  55 +
  56 + /**
  57 + * 加密byte[]
  58 + */
  59 + public static byte[] ebotongEncrypto(byte[] str, String key) {
  60 + byte[] result = null;
  61 + if (str != null && str.length > 0) {
  62 + try {
  63 + byte[] encodeByte = symmetricEncrypto(str, key);
  64 + result = Base64.encode(encodeByte, Base64.DEFAULT);
  65 +
  66 + } catch (Exception e) {
  67 + // e.printStackTrace();
  68 + }
  69 + }
  70 + return result;
  71 + }
  72 +
  73 + /**
  74 + * 解密byte[]
  75 + */
  76 + public static byte[] ebotongDecrypto(byte[] str, String key) {
  77 + byte[] result = null;
  78 + if (str != null && str.length > 0) {
  79 + try {
  80 +
  81 + byte[] encodeByte = Base64.decode(new String(str, encoding), Base64.DEFAULT);
  82 + //byte[] encodeByte = base64decoder.decodeBuffer(new String(str));
  83 + byte[] decoder = symmetricDecrypto(encodeByte, key);
  84 + result = new String(decoder).getBytes(encoding);
  85 + result = new String(decoder).getBytes();
  86 + } catch (Exception e) {
  87 + // e.printStackTrace();
  88 + }
  89 + }
  90 + return result;
  91 + }
  92 +
  93 + /**
  94 + * 对称加密字节数组并返回
  95 + *
  96 + * @param byteSource 需要加密的数据
  97 + * @return 经过加密的数据
  98 + * @throws Exception
  99 + */
  100 + public static byte[] symmetricEncrypto(byte[] byteSource, String sKey) throws Exception {
  101 + try {
  102 + int mode = Cipher.ENCRYPT_MODE;
  103 + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
  104 + byte[] keyData = sKey.getBytes();
  105 + DESKeySpec keySpec = new DESKeySpec(keyData);
  106 + Key key = keyFactory.generateSecret(keySpec);
  107 + Cipher cipher = getInstance("DES");
  108 + cipher.init(mode, key);
  109 +
  110 + return cipher.doFinal(byteSource);
  111 + } catch (Exception e) {
  112 + return null;
  113 + }
  114 + }
  115 +
  116 + /**
  117 + * 对称解密字节数组并返回
  118 + *
  119 + * @param byteSource 需要解密的数据
  120 + * @return 经过解密的数据
  121 + * @throws Exception
  122 + */
  123 + public static byte[] symmetricDecrypto(byte[] byteSource, String sKey) throws Exception {
  124 + try {
  125 + int mode = Cipher.DECRYPT_MODE;
  126 + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
  127 + byte[] keyData = sKey.getBytes();
  128 + DESKeySpec keySpec = new DESKeySpec(keyData);
  129 + Key key = keyFactory.generateSecret(keySpec);
  130 + Cipher cipher = getInstance("DES");
  131 + cipher.init(mode, key);
  132 + return cipher.doFinal(byteSource);
  133 + } catch (Exception e) {
  134 + return null;
  135 + }
  136 + }
  137 +}
... ...