Commit ce60638ee9aa86f125b92b235422cbf851b45f17

Authored by YangShuai
1 parent deff69ec

1 新增switchButton

2 优化基类
Showing 23 changed files with 2185 additions and 393 deletions
app/strike/src/main/java/com/cnlive/strike/MainActivity.java
@@ -9,7 +9,9 @@ import android.util.AttributeSet; @@ -9,7 +9,9 @@ import android.util.AttributeSet;
9 import android.util.Log; 9 import android.util.Log;
10 import android.view.View; 10 import android.view.View;
11 11
  12 +import com.cnlive.strike.demo.activity.DemoActivity;
12 import com.cnlive.strike.imgutil.ImgActivity; 13 import com.cnlive.strike.imgutil.ImgActivity;
  14 +import com.cnlive.strike.user.ui.activity.LoginActivity;
13 15
14 import androidx.annotation.NonNull; 16 import androidx.annotation.NonNull;
15 import androidx.annotation.Nullable; 17 import androidx.annotation.Nullable;
@@ -22,6 +24,7 @@ public class MainActivity extends AppCompatActivity { @@ -22,6 +24,7 @@ public class MainActivity extends AppCompatActivity {
22 protected void onCreate(@Nullable Bundle savedInstanceState) { 24 protected void onCreate(@Nullable Bundle savedInstanceState) {
23 super.onCreate(savedInstanceState); 25 super.onCreate(savedInstanceState);
24 setContentView(R.layout.activity_main); 26 setContentView(R.layout.activity_main);
  27 + findViewById(R.id.go_to).setOnClickListener(view -> startActivity(new Intent(this, LoginActivity.class)) );
25 findViewById(R.id.to_img).setOnClickListener(view -> startActivity(new Intent(this, ImgActivity.class)) ); 28 findViewById(R.id.to_img).setOnClickListener(view -> startActivity(new Intent(this, ImgActivity.class)) );
26 } 29 }
27 30
build.gradle
@@ -128,3 +128,9 @@ allprojects { @@ -128,3 +128,9 @@ allprojects {
128 task clean(type: Delete) { 128 task clean(type: Delete) {
129 delete rootProject.buildDir 129 delete rootProject.buildDir
130 } 130 }
  131 +
  132 +//配置全局变量
  133 +ext {
  134 + libEmoj='2.0.9'
  135 + libMediaPicker = '1.5.8'
  136 +}
cloud/user/build.gradle
@@ -46,7 +46,8 @@ dependencies { @@ -46,7 +46,8 @@ dependencies {
46 androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 46 androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
47 47
48 implementation project(path: ':core:network') 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
@@ -9,15 +9,19 @@ import com.cnlive.core.network.BaseResult; @@ -9,15 +9,19 @@ import com.cnlive.core.network.BaseResult;
9 import com.cnlive.core.network.HttpConn; 9 import com.cnlive.core.network.HttpConn;
10 import com.cnlive.strike.user.network.api.ApiBaseServiceOpen; 10 import com.cnlive.strike.user.network.api.ApiBaseServiceOpen;
11 import com.cnlive.strike.user.network.api.BaseRequest; 11 import com.cnlive.strike.user.network.api.BaseRequest;
  12 +import com.cnlive.strike.user.network.model.FaceData;
12 import com.cnlive.strike.user.network.model.TokenData; 13 import com.cnlive.strike.user.network.model.TokenData;
13 import com.cnlive.strike.user.network.model.UserData; 14 import com.cnlive.strike.user.network.model.UserData;
14 15
15 import java.io.File; 16 import java.io.File;
  17 +import java.util.ArrayList;
16 import java.util.HashMap; 18 import java.util.HashMap;
  19 +import java.util.List;
17 import java.util.Map; 20 import java.util.Map;
18 21
19 import io.reactivex.Observable; 22 import io.reactivex.Observable;
20 import okhttp3.MediaType; 23 import okhttp3.MediaType;
  24 +import okhttp3.MultipartBody;
21 import okhttp3.RequestBody; 25 import okhttp3.RequestBody;
22 26
23 27
@@ -239,35 +243,34 @@ public class UserUtilAction { @@ -239,35 +243,34 @@ public class UserUtilAction {
239 return BaseRequest.init().service(ApiBaseServiceOpen.class).accessToken(map); 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 // Subscriber<BaseInfo<FaceData>> subscriber = new Subscriber<BaseInfo<FaceData>>(context, ApiBaseSubscriber.subscriberBuild) { 274 // Subscriber<BaseInfo<FaceData>> subscriber = new Subscriber<BaseInfo<FaceData>>(context, ApiBaseSubscriber.subscriberBuild) {
272 // @Override 275 // @Override
273 // public void onCompleted(String s, String s1, BaseInfo<FaceData> faceDataBaseInfo) { 276 // public void onCompleted(String s, String s1, BaseInfo<FaceData> faceDataBaseInfo) {
@@ -287,10 +290,11 @@ public class UserUtilAction { @@ -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 private static RequestBody getRequestString(String value) { 299 private static RequestBody getRequestString(String value) {
296 RequestBody requestString = RequestBody.create(MediaType.parse("text/plain"), value); 300 RequestBody requestString = RequestBody.create(MediaType.parse("text/plain"), value);
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 +11,15 @@ import com.cnlive.strike.user.R;
11 import com.cnlive.strike.user.UserUtilAction; 11 import com.cnlive.strike.user.UserUtilAction;
12 import com.cnlive.strike.user.auth.UserService; 12 import com.cnlive.strike.user.auth.UserService;
13 import com.cnlive.strike.user.frame.view.FirstLoginView; 13 import com.cnlive.strike.user.frame.view.FirstLoginView;
  14 +import com.cnlive.strike.user.network.model.FaceData;
  15 +import com.cnlive.strike.user.network.model.TokenData;
14 import com.cnlive.strike.user.network.model.UserData; 16 import com.cnlive.strike.user.network.model.UserData;
  17 +import com.cnlive.strike.user.router.user.UserOfflineUtil;
15 18
16 import java.io.File; 19 import java.io.File;
17 20
18 import io.reactivex.ObservableSource; 21 import io.reactivex.ObservableSource;
  22 +import io.reactivex.disposables.Disposable;
19 import io.reactivex.functions.Function; 23 import io.reactivex.functions.Function;
20 24
21 25
@@ -24,6 +28,7 @@ import io.reactivex.functions.Function; @@ -24,6 +28,7 @@ import io.reactivex.functions.Function;
24 */ 28 */
25 29
26 public class FirstLoginPresenter extends BasePresenter<FirstLoginView> { 30 public class FirstLoginPresenter extends BasePresenter<FirstLoginView> {
  31 + private Disposable updateFaceEvent;
27 32
28 public void loadUserInfo(Context context) { 33 public void loadUserInfo(Context context) {
29 UserService userService = UserService.getInstance(context); 34 UserService userService = UserService.getInstance(context);
@@ -112,52 +117,60 @@ public class FirstLoginPresenter extends BasePresenter&lt;FirstLoginView&gt; { @@ -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,19 +39,18 @@ import io.reactivex.disposables.Disposable;
39 public class QuickLoginPresenter extends BasePresenter<QuickLoginView> { 39 public class QuickLoginPresenter extends BasePresenter<QuickLoginView> {
40 private TimerUtil timerUtil; //计时工具类 40 private TimerUtil timerUtil; //计时工具类
41 41
42 - // private Event<CNLiveUserInfo> event; 42 + private Disposable event;
43 private Disposable sendMsgBefQuickLogin; 43 private Disposable sendMsgBefQuickLogin;
44 // private Event otherEvent; 44 // private Event otherEvent;
45 45
46 public void deleteUserInfo(Context context, String userName) { 46 public void deleteUserInfo(Context context, String userName) {
47 UserService.getInstance(context).removeUser(userName, future -> { 47 UserService.getInstance(context).removeUser(userName, future -> {
48 - if (getView() == null) return;  
49 //获取已登录用户列表 48 //获取已登录用户列表
50 Account[] accounts = UserService.getInstance(context).getUserList(); 49 Account[] accounts = UserService.getInstance(context).getUserList();
51 //倒序输出最近登录用户 50 //倒序输出最近登录用户
52 51
53 Collections.reverse(Arrays.asList(accounts)); 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,10 +66,10 @@ public class QuickLoginPresenter extends BasePresenter&lt;QuickLoginView&gt; {
67 String name = account == null ? "" : account.name; 66 String name = account == null ? "" : account.name;
68 //页面填充数据 67 //页面填充数据
69 if (!TextUtils.isEmpty(name)) { 68 if (!TextUtils.isEmpty(name)) {
70 - getView().uploadInputData(name); 69 + ifViewAttached(view -> view.uploadInputData(name));
71 } 70 }
72 if (null != accounts) { 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,29 +83,28 @@ public class QuickLoginPresenter extends BasePresenter&lt;QuickLoginView&gt; {
84 timerUtil.setTimerLiener(new TimerUtil.TimeListener() { 83 timerUtil.setTimerLiener(new TimerUtil.TimeListener() {
85 @Override 84 @Override
86 public void onFinish() { 85 public void onFinish() {
87 - if (getView() != null) getView().onTimerFinish(); 86 + ifViewAttached(view -> view.onTimerFinish());
88 } 87 }
89 88
90 @Override 89 @Override
91 public void onInterval(long remainTime) { 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 public void sendCode(Context context, String phone, String countryCode) { 96 public void sendCode(Context context, String phone, String countryCode) {
98 - if (getView() == null) return;  
99 if (TimeEvent.debounce(2_000)) return; 97 if (TimeEvent.debounce(2_000)) return;
100 if (TextUtils.isEmpty(phone)) { 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 return; 100 return;
103 } 101 }
104 if ("86".equals(countryCode) && !RegexUtils.isMobileSimple(phone)) { 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 return; 104 return;
107 } 105 }
108 if (sendMsgBefQuickLogin != null && !sendMsgBefQuickLogin.isDisposed()) { 106 if (sendMsgBefQuickLogin != null && !sendMsgBefQuickLogin.isDisposed()) {
109 - getView().showToast("处理中请稍后..."); 107 + ifViewAttached(view -> view.showToast("处理中请稍后..."));
110 } else { 108 } else {
111 sendMsgBefQuickLogin = HttpConn.action(UserUtilAction.sendMsgBefQuickLoginAction(context, phone, countryCode), new NetCallBack<BaseResult>() { 109 sendMsgBefQuickLogin = HttpConn.action(UserUtilAction.sendMsgBefQuickLoginAction(context, phone, countryCode), new NetCallBack<BaseResult>() {
112 @Override 110 @Override
@@ -137,7 +135,7 @@ public class QuickLoginPresenter extends BasePresenter&lt;QuickLoginView&gt; { @@ -137,7 +135,7 @@ public class QuickLoginPresenter extends BasePresenter&lt;QuickLoginView&gt; {
137 } else { 135 } else {
138 context.isLogin = true; 136 context.isLogin = true;
139 // UserAction.mobileLogin(context.getActivity(), data.getPhone(), data.getCode(), countryCode, initLoginEvent(context, true)); 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 @Override 139 @Override
142 public void callback(int state, String msg, Object object) { 140 public void callback(int state, String msg, Object object) {
143 initLoginEvent(context, state, msg, true, null); 141 initLoginEvent(context, state, msg, true, null);
@@ -229,7 +227,7 @@ public class QuickLoginPresenter extends BasePresenter&lt;QuickLoginView&gt; { @@ -229,7 +227,7 @@ public class QuickLoginPresenter extends BasePresenter&lt;QuickLoginView&gt; {
229 // } 227 // }
230 228
231 229
232 -// 230 + //
233 // private Event<CNLiveUserInfo> initLoginEvent(QuickLoginFragment context, Boolean retry, OtherUserInfo otherUserInfo) { 231 // private Event<CNLiveUserInfo> initLoginEvent(QuickLoginFragment context, Boolean retry, OtherUserInfo otherUserInfo) {
234 // return event = new Event<CNLiveUserInfo>() 232 // return event = new Event<CNLiveUserInfo>()
235 // .setStateCallback(state -> { 233 // .setStateCallback(state -> {
@@ -304,5 +302,12 @@ public class QuickLoginPresenter extends BasePresenter&lt;QuickLoginView&gt; { @@ -304,5 +302,12 @@ public class QuickLoginPresenter extends BasePresenter&lt;QuickLoginView&gt; {
304 // if (context != null) context.isLogin = false; 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/router/user/UserAction.java
@@ -19,6 +19,7 @@ import com.cnlive.strike.user.network.model.UserData; @@ -19,6 +19,7 @@ import com.cnlive.strike.user.network.model.UserData;
19 19
20 import io.reactivex.Observable; 20 import io.reactivex.Observable;
21 import io.reactivex.ObservableSource; 21 import io.reactivex.ObservableSource;
  22 +import io.reactivex.disposables.Disposable;
22 import io.reactivex.functions.Function; 23 import io.reactivex.functions.Function;
23 24
24 25
@@ -49,13 +50,13 @@ public class UserAction { @@ -49,13 +50,13 @@ public class UserAction {
49 // .start(event); 50 // .start(event);
50 // } 51 // }
51 52
52 - public static void mobileLogin(Context context, String phone, String code, String countryCode, CallBack callBack) { 53 + public static Disposable mobileLogin(Context context, String phone, String code, String countryCode, CallBack callBack) {
53 // Logic.create() 54 // Logic.create()
54 // .action(UserUtilAction.quickLoginAction(context, phone, code, countryCode)) 55 // .action(UserUtilAction.quickLoginAction(context, phone, code, countryCode))
55 // .action(loginAppAction(context, phone, code)) 56 // .action(loginAppAction(context, phone, code))
56 //// .action(loginIMAction()) 57 //// .action(loginIMAction())
57 // .start(event); 58 // .start(event);
58 - HttpConn.action( 59 + return HttpConn.action(
59 UserUtilAction.quickLoginAction(context, phone, code, countryCode) 60 UserUtilAction.quickLoginAction(context, phone, code, countryCode)
60 , new NetCallBack<BaseResult<UserData>>() { 61 , new NetCallBack<BaseResult<UserData>>() {
61 @Override 62 @Override
@@ -86,7 +87,7 @@ public class UserAction { @@ -86,7 +87,7 @@ public class UserAction {
86 if (null != callBack) { 87 if (null != callBack) {
87 callBack.callback(-5, "获取账户信息失败 请重试.", null); 88 callBack.callback(-5, "获取账户信息失败 请重试.", null);
88 } 89 }
89 - } else if (TextUtils.isEmpty(data.getData().getMobile())) { 90 + } else if (TextUtils.isEmpty(data.getData().getMobile())) {
90 callBack.callback(-5, "绑定手机号已失效..", null); 91 callBack.callback(-5, "绑定手机号已失效..", null);
91 } else { 92 } else {
92 //更新登录用户信息 93 //更新登录用户信息
cloud/user/src/main/java/com/cnlive/strike/user/router/user/UserOfflineUtil.java
@@ -5,9 +5,14 @@ import android.content.Context; @@ -5,9 +5,14 @@ import android.content.Context;
5 5
6 import androidx.appcompat.app.AppCompatActivity; 6 import androidx.appcompat.app.AppCompatActivity;
7 7
  8 +import com.cnlive.core.libs.base.ui.widget.BottomSheet;
8 import com.cnlive.core.libs.base.util.AlertUtil; 9 import com.cnlive.core.libs.base.util.AlertUtil;
  10 +import com.cnlive.core.libs.base.util.AppManager;
9 import com.cnlive.strike.user.auth.UserService; 11 import com.cnlive.strike.user.auth.UserService;
  12 +import com.cnlive.strike.user.ui.activity.LoginActivity;
10 import com.kongzue.dialog.interfaces.OnMenuItemClickListener; 13 import com.kongzue.dialog.interfaces.OnMenuItemClickListener;
  14 +import com.kongzue.dialog.util.DialogSettings;
  15 +import com.kongzue.dialog.util.TextInfo;
11 import com.kongzue.dialog.v3.BottomMenu; 16 import com.kongzue.dialog.v3.BottomMenu;
12 17
13 import org.greenrobot.eventbus.EventBus; 18 import org.greenrobot.eventbus.EventBus;
@@ -37,40 +42,44 @@ public class UserOfflineUtil { @@ -37,40 +42,44 @@ public class UserOfflineUtil {
37 } 42 }
38 43
39 public static void userInvalid(Context context) { 44 public static void userInvalid(Context context) {
40 - AlertUtil.showDeftToast(context, "用户 已失效."); 45 + AlertUtil.showDeftToast(context, "用户已失效.");
41 appLogout(context); 46 appLogout(context);
42 } 47 }
43 48
44 //todo BottomSheet 49 //todo BottomSheet
45 public static void logout(Context context) { 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 public static void appLogout(Context context) { 74 public static void appLogout(Context context) {
67 String uid = UserService.getUid(context); 75 String uid = UserService.getUid(context);
68 UserService.getInstance(context).logoutAppAccount(); 76 UserService.getInstance(context).logoutAppAccount();
69 //退出登录 77 //退出登录
70 - 78 + AppManager.getInstance().killAllActivity();
  79 + LoginActivity.start(context);
71 // LoginManager.logout(uid, null, context); 80 // LoginManager.logout(uid, null, context);
72 // if (ActivityLifecycle.isActive()) { 81 // if (ActivityLifecycle.isActive()) {
73 -// LoginActivity.start(context); 82 +
74 // } else { 83 // } else {
75 // Log.e("FinishAllActivity", "FinishAllActivity-----logout"); 84 // Log.e("FinishAllActivity", "FinishAllActivity-----logout");
76 // FinishAllActivity.finish(context); 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,8 +19,11 @@ import com.cnlive.strike.user.ui.fragment.QuickLoginFragment;
19 * @author Lynn 19 * @author Lynn
20 * @date 2017/12/22 20 * @date 2017/12/22
21 */ 21 */
22 -@Route(path = "/cnmain/LoginActivity") 22 +//@Route(path = "/cnmain/LoginActivity")
  23 +@Route(path = LoginActivity.PATH)
23 public class LoginActivity extends BaseActivity { 24 public class LoginActivity extends BaseActivity {
  25 + public static final String PATH = "/cloud/user/ui/activity/login";
  26 +
24 public static String FROM_TOKEN_ERROR = "from_token_error"; 27 public static String FROM_TOKEN_ERROR = "from_token_error";
25 public static String TAG_MSG = "tagMsg"; 28 public static String TAG_MSG = "tagMsg";
26 public static String TAG_SHARE = "tagValue"; 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,6 +5,7 @@ import android.app.Activity;
5 import android.app.Dialog; 5 import android.app.Dialog;
6 import android.app.ProgressDialog; 6 import android.app.ProgressDialog;
7 import android.content.Intent; 7 import android.content.Intent;
  8 +import android.os.Environment;
8 import android.text.Editable; 9 import android.text.Editable;
9 import android.text.TextUtils; 10 import android.text.TextUtils;
10 import android.text.TextWatcher; 11 import android.text.TextWatcher;
@@ -14,9 +15,13 @@ import androidx.annotation.NonNull; @@ -14,9 +15,13 @@ import androidx.annotation.NonNull;
14 import androidx.appcompat.app.AppCompatActivity; 15 import androidx.appcompat.app.AppCompatActivity;
15 16
16 import com.cnlive.core.libs.base.frame.fragment.BaseFragment; 17 import com.cnlive.core.libs.base.frame.fragment.BaseFragment;
  18 +import com.cnlive.core.libs.base.interfaces.OnPermissionResponseListener;
17 import com.cnlive.core.libs.base.util.AlertUtil; 19 import com.cnlive.core.libs.base.util.AlertUtil;
18 import com.cnlive.core.libs.base.util.GlideUtil; 20 import com.cnlive.core.libs.base.util.GlideUtil;
19 import com.cnlive.core.libs.base.util.StatusBarConfig; 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 import com.cnlive.strike.user.R; 25 import com.cnlive.strike.user.R;
21 import com.cnlive.strike.user.auth.UserService; 26 import com.cnlive.strike.user.auth.UserService;
22 import com.cnlive.strike.user.databinding.FragmentFirstLoginBinding; 27 import com.cnlive.strike.user.databinding.FragmentFirstLoginBinding;
@@ -28,6 +33,10 @@ import com.cnlive.strike.user.router.user.UserOfflineUtil; @@ -28,6 +33,10 @@ import com.cnlive.strike.user.router.user.UserOfflineUtil;
28 import com.cnlive.strike.user.ui.activity.FirstLoginActivity; 33 import com.cnlive.strike.user.ui.activity.FirstLoginActivity;
29 import com.cnlive.strike.user.ui.activity.LoginActivity; 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 * Created by xiansong on 2018/1/19. 42 * Created by xiansong on 2018/1/19.
@@ -128,31 +137,37 @@ public class FirstLoginFragment extends BaseFragment&lt;FirstLoginView, FirstLoginP @@ -128,31 +137,37 @@ public class FirstLoginFragment extends BaseFragment&lt;FirstLoginView, FirstLoginP
128 137
129 138
130 public void selectPhoto(boolean fromResult) { 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,31 +178,17 @@ public class FirstLoginFragment extends BaseFragment&lt;FirstLoginView, FirstLoginP
163 if (tokenErrorDialog != null) tokenErrorDialog.dismiss(); 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 @Override 182 @Override
182 public void onActivityResult(int requestCode, int resultCode, Intent data) { 183 public void onActivityResult(int requestCode, int resultCode, Intent data) {
183 super.onActivityResult(requestCode, resultCode, data); 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,7 +114,7 @@ public class QuickLoginFragment extends BaseFragment&lt;QuickLoginView, QuickLoginP
114 mProgressDialog.setMessage(getResources().getString(R.string.login_dialog)); 114 mProgressDialog.setMessage(getResources().getString(R.string.login_dialog));
115 mProgressDialog.setCanceledOnTouchOutside(false); 115 mProgressDialog.setCanceledOnTouchOutside(false);
116 mProgressDialog.setOnCancelListener(dialog -> { 116 mProgressDialog.setOnCancelListener(dialog -> {
117 -// getPresenter().cancelLoad(); 117 + getPresenter().cancelLoad();
118 }); 118 });
119 getMvpView().setAgreementText(); 119 getMvpView().setAgreementText();
120 binding.setClickListener(v -> onClick(v.getId())); 120 binding.setClickListener(v -> onClick(v.getId()));
core/base/src/main/java/com/cnlive/core/libs/base/frame/activity/BaseActivity.java
@@ -23,12 +23,14 @@ import androidx.annotation.ColorRes; @@ -23,12 +23,14 @@ import androidx.annotation.ColorRes;
23 import androidx.annotation.IntRange; 23 import androidx.annotation.IntRange;
24 import androidx.annotation.NonNull; 24 import androidx.annotation.NonNull;
25 import androidx.annotation.Nullable; 25 import androidx.annotation.Nullable;
  26 +import androidx.annotation.StringRes;
26 import androidx.appcompat.app.AlertDialog; 27 import androidx.appcompat.app.AlertDialog;
27 import androidx.core.app.ActivityCompat; 28 import androidx.core.app.ActivityCompat;
28 import androidx.core.content.ContextCompat; 29 import androidx.core.content.ContextCompat;
29 import androidx.databinding.DataBindingUtil; 30 import androidx.databinding.DataBindingUtil;
30 import androidx.databinding.ViewDataBinding; 31 import androidx.databinding.ViewDataBinding;
31 32
  33 +import com.alibaba.android.arouter.launcher.ARouter;
32 import com.cnlive.core.libs.base.frame.presenter.BasePresenter; 34 import com.cnlive.core.libs.base.frame.presenter.BasePresenter;
33 import com.cnlive.core.libs.base.frame.view.BaseView; 35 import com.cnlive.core.libs.base.frame.view.BaseView;
34 import com.cnlive.core.libs.base.interfaces.OnPermissionResponseListener; 36 import com.cnlive.core.libs.base.interfaces.OnPermissionResponseListener;
@@ -89,6 +91,8 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V @@ -89,6 +91,8 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
89 context = this; 91 context = this;
90 me = this; 92 me = this;
91 this.savedInstanceState = savedInstanceState; 93 this.savedInstanceState = savedInstanceState;
  94 + //路由参数初始化
  95 + ARouter.getInstance().inject(this);
92 //activity管理 96 //activity管理
93 AppManager.getInstance().pushActivity(me); 97 AppManager.getInstance().pushActivity(me);
94 //创建订阅映射 98 //创建订阅映射
@@ -446,6 +450,29 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V @@ -446,6 +450,29 @@ public abstract class BaseActivity&lt;V extends BaseView, P extends BasePresenter&lt;V
446 } 450 }
447 451
448 /** 452 /**
  453 + * 自定义权限申请码和提示信息
  454 + * 可传入string字符串
  455 + *
  456 + * @param requestCode
  457 + * @param permissions
  458 + * @param onPermissionResponseListener
  459 + */
  460 + public void requestPermission(int requestCode, @StringRes int defineTip, String[]
  461 + permissions, OnPermissionResponseListener onPermissionResponseListener) {
  462 + this.onPermissionResponseListener = onPermissionResponseListener;
  463 + this.USER_SET_REQUEST_CODE_PERMISSION = requestCode;
  464 + this.userSetDefinePermissionTip = getResources().getString(defineTip);
  465 + if (checkPermissions(permissions)) {
  466 + if (onPermissionResponseListener != null) {
  467 + onPermissionResponseListener.onSuccess(permissions);
  468 + }
  469 + } else {
  470 + List<String> needPermissions = getDeniedPermissions(permissions);
  471 + ActivityCompat.requestPermissions(this, needPermissions.toArray(new String[needPermissions.size()]), USER_SET_REQUEST_CODE_PERMISSION);
  472 + }
  473 + }
  474 +
  475 + /**
449 * 获取权限集中需要申请权限的列表 476 * 获取权限集中需要申请权限的列表
450 * 477 *
451 * @param permissions 478 * @param permissions
core/base/src/main/java/com/cnlive/core/libs/base/frame/fragment/BaseFragment.java
@@ -10,10 +10,12 @@ import androidx.annotation.ColorRes; @@ -10,10 +10,12 @@ import androidx.annotation.ColorRes;
10 import androidx.annotation.IntRange; 10 import androidx.annotation.IntRange;
11 import androidx.annotation.NonNull; 11 import androidx.annotation.NonNull;
12 import androidx.annotation.Nullable; 12 import androidx.annotation.Nullable;
  13 +import androidx.annotation.StringRes;
13 import androidx.core.content.ContextCompat; 14 import androidx.core.content.ContextCompat;
14 import androidx.databinding.DataBindingUtil; 15 import androidx.databinding.DataBindingUtil;
15 import androidx.databinding.ViewDataBinding; 16 import androidx.databinding.ViewDataBinding;
16 17
  18 +import com.alibaba.android.arouter.launcher.ARouter;
17 import com.cnlive.core.libs.base.frame.activity.BaseActivity; 19 import com.cnlive.core.libs.base.frame.activity.BaseActivity;
18 import com.cnlive.core.libs.base.frame.presenter.BasePresenter; 20 import com.cnlive.core.libs.base.frame.presenter.BasePresenter;
19 import com.cnlive.core.libs.base.interfaces.OnPermissionResponseListener; 21 import com.cnlive.core.libs.base.interfaces.OnPermissionResponseListener;
@@ -45,6 +47,7 @@ public abstract class BaseFragment&lt;V extends BaseView, P extends BasePresenter&lt;V @@ -45,6 +47,7 @@ public abstract class BaseFragment&lt;V extends BaseView, P extends BasePresenter&lt;V
45 super.onCreate(savedInstanceState); 47 super.onCreate(savedInstanceState);
46 if (getActivity() == null) return; 48 if (getActivity() == null) return;
47 me = (BaseActivity) getActivity(); 49 me = (BaseActivity) getActivity();
  50 + ARouter.getInstance().inject(this);
48 initFragmentStyle(); 51 initFragmentStyle();
49 initParams(); 52 initParams();
50 } 53 }
@@ -220,6 +223,11 @@ public abstract class BaseFragment&lt;V extends BaseView, P extends BasePresenter&lt;V @@ -220,6 +223,11 @@ public abstract class BaseFragment&lt;V extends BaseView, P extends BasePresenter&lt;V
220 me.requestPermission(requestCode, defineTip, permissions, onPermissionResponseListener); 223 me.requestPermission(requestCode, defineTip, permissions, onPermissionResponseListener);
221 } 224 }
222 225
  226 + public void requestPermission(int requestCode, @StringRes int defineTip, String[]
  227 + permissions, OnPermissionResponseListener onPermissionResponseListener) {
  228 + me.requestPermission(requestCode, defineTip, permissions, onPermissionResponseListener);
  229 + }
  230 +
223 //多权限检查 231 //多权限检查
224 public boolean checkPermissions(String[] permissions) { 232 public boolean checkPermissions(String[] permissions) {
225 return me.checkPermissions(permissions); 233 return me.checkPermissions(permissions);
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 \ No newline at end of file 1143 \ No newline at end of file
core/base/src/main/java/com/kongzue/dialog/v3/BottomMenu.java
@@ -48,18 +48,18 @@ import static com.kongzue.dialog.util.DialogSettings.menuTitleInfo; @@ -48,18 +48,18 @@ import static com.kongzue.dialog.util.DialogSettings.menuTitleInfo;
48 * CreateTime: 2019/4/12 18:33 48 * CreateTime: 2019/4/12 18:33
49 */ 49 */
50 public class BottomMenu extends BaseDialog { 50 public class BottomMenu extends BaseDialog {
51 - 51 +
52 private BaseAdapter customAdapter; //允许用户自定义 Menu 的 Adapter 52 private BaseAdapter customAdapter; //允许用户自定义 Menu 的 Adapter
53 - 53 +
54 private List<String> menuTextList; 54 private List<String> menuTextList;
55 private String title; 55 private String title;
56 private String cancelButtonText = DialogSettings.defaultCancelButtonText; 56 private String cancelButtonText = DialogSettings.defaultCancelButtonText;
57 private boolean showCancelButton = true; 57 private boolean showCancelButton = true;
58 private OnMenuItemClickListener onMenuItemClickListener; 58 private OnMenuItemClickListener onMenuItemClickListener;
59 - 59 +
60 private TextInfo menuTitleTextInfo; 60 private TextInfo menuTitleTextInfo;
61 private TextInfo cancelButtonTextInfo; 61 private TextInfo cancelButtonTextInfo;
62 - 62 +
63 private LinearLayout boxBody; 63 private LinearLayout boxBody;
64 private RelativeLayout boxList; 64 private RelativeLayout boxList;
65 private TextView txtTitle; 65 private TextView txtTitle;
@@ -69,16 +69,16 @@ public class BottomMenu extends BaseDialog { @@ -69,16 +69,16 @@ public class BottomMenu extends BaseDialog {
69 private ViewGroup boxCancel; 69 private ViewGroup boxCancel;
70 private TextView btnCancel; 70 private TextView btnCancel;
71 private TextInfo menuTextInfo; 71 private TextInfo menuTextInfo;
72 - 72 +
73 private BottomMenu() { 73 private BottomMenu() {
74 } 74 }
75 - 75 +
76 public static BottomMenu build(@NonNull AppCompatActivity context) { 76 public static BottomMenu build(@NonNull AppCompatActivity context) {
77 synchronized (BottomMenu.class) { 77 synchronized (BottomMenu.class) {
78 BottomMenu bottomMenu = new BottomMenu(); 78 BottomMenu bottomMenu = new BottomMenu();
79 bottomMenu.log("装载底部菜单: " + bottomMenu.toString()); 79 bottomMenu.log("装载底部菜单: " + bottomMenu.toString());
80 bottomMenu.context = new WeakReference<AppCompatActivity>(context); 80 bottomMenu.context = new WeakReference<AppCompatActivity>(context);
81 - 81 +
82 switch (bottomMenu.style) { 82 switch (bottomMenu.style) {
83 case STYLE_IOS: 83 case STYLE_IOS:
84 bottomMenu.build(bottomMenu, R.layout.bottom_menu_ios); 84 bottomMenu.build(bottomMenu, R.layout.bottom_menu_ios);
@@ -93,7 +93,7 @@ public class BottomMenu extends BaseDialog { @@ -93,7 +93,7 @@ public class BottomMenu extends BaseDialog {
93 return bottomMenu; 93 return bottomMenu;
94 } 94 }
95 } 95 }
96 - 96 +
97 public static BottomMenu show(@NonNull AppCompatActivity context, List<String> menuTextList, OnMenuItemClickListener onMenuItemClickListener) { 97 public static BottomMenu show(@NonNull AppCompatActivity context, List<String> menuTextList, OnMenuItemClickListener onMenuItemClickListener) {
98 BottomMenu bottomMenu = build(context); 98 BottomMenu bottomMenu = build(context);
99 bottomMenu.menuTextList = menuTextList; 99 bottomMenu.menuTextList = menuTextList;
@@ -101,7 +101,7 @@ public class BottomMenu extends BaseDialog { @@ -101,7 +101,7 @@ public class BottomMenu extends BaseDialog {
101 bottomMenu.showDialog(); 101 bottomMenu.showDialog();
102 return bottomMenu; 102 return bottomMenu;
103 } 103 }
104 - 104 +
105 public static BottomMenu show(@NonNull AppCompatActivity context, BaseAdapter customAdapter, OnMenuItemClickListener onMenuItemClickListener) { 105 public static BottomMenu show(@NonNull AppCompatActivity context, BaseAdapter customAdapter, OnMenuItemClickListener onMenuItemClickListener) {
106 BottomMenu bottomMenu = build(context); 106 BottomMenu bottomMenu = build(context);
107 bottomMenu.customAdapter = customAdapter; 107 bottomMenu.customAdapter = customAdapter;
@@ -109,7 +109,7 @@ public class BottomMenu extends BaseDialog { @@ -109,7 +109,7 @@ public class BottomMenu extends BaseDialog {
109 bottomMenu.showDialog(); 109 bottomMenu.showDialog();
110 return bottomMenu; 110 return bottomMenu;
111 } 111 }
112 - 112 +
113 public static BottomMenu show(@NonNull AppCompatActivity context, String title, List<String> menuTextList, OnMenuItemClickListener onMenuItemClickListener) { 113 public static BottomMenu show(@NonNull AppCompatActivity context, String title, List<String> menuTextList, OnMenuItemClickListener onMenuItemClickListener) {
114 BottomMenu bottomMenu = build(context); 114 BottomMenu bottomMenu = build(context);
115 bottomMenu.menuTextList = menuTextList; 115 bottomMenu.menuTextList = menuTextList;
@@ -118,7 +118,7 @@ public class BottomMenu extends BaseDialog { @@ -118,7 +118,7 @@ public class BottomMenu extends BaseDialog {
118 bottomMenu.showDialog(); 118 bottomMenu.showDialog();
119 return bottomMenu; 119 return bottomMenu;
120 } 120 }
121 - 121 +
122 public static BottomMenu show(@NonNull AppCompatActivity context, String title, BaseAdapter customAdapter, OnMenuItemClickListener onMenuItemClickListener) { 122 public static BottomMenu show(@NonNull AppCompatActivity context, String title, BaseAdapter customAdapter, OnMenuItemClickListener onMenuItemClickListener) {
123 BottomMenu bottomMenu = build(context); 123 BottomMenu bottomMenu = build(context);
124 bottomMenu.customAdapter = customAdapter; 124 bottomMenu.customAdapter = customAdapter;
@@ -127,7 +127,7 @@ public class BottomMenu extends BaseDialog { @@ -127,7 +127,7 @@ public class BottomMenu extends BaseDialog {
127 bottomMenu.showDialog(); 127 bottomMenu.showDialog();
128 return bottomMenu; 128 return bottomMenu;
129 } 129 }
130 - 130 +
131 public static BottomMenu show(@NonNull AppCompatActivity context, String[] menuTexts, OnMenuItemClickListener onMenuItemClickListener) { 131 public static BottomMenu show(@NonNull AppCompatActivity context, String[] menuTexts, OnMenuItemClickListener onMenuItemClickListener) {
132 BottomMenu bottomMenu = build(context); 132 BottomMenu bottomMenu = build(context);
133 List<String> list = new ArrayList<>(); 133 List<String> list = new ArrayList<>();
@@ -139,7 +139,7 @@ public class BottomMenu extends BaseDialog { @@ -139,7 +139,7 @@ public class BottomMenu extends BaseDialog {
139 bottomMenu.showDialog(); 139 bottomMenu.showDialog();
140 return bottomMenu; 140 return bottomMenu;
141 } 141 }
142 - 142 +
143 public static BottomMenu show(@NonNull AppCompatActivity context, String title, String[] menuTexts, OnMenuItemClickListener onMenuItemClickListener) { 143 public static BottomMenu show(@NonNull AppCompatActivity context, String title, String[] menuTexts, OnMenuItemClickListener onMenuItemClickListener) {
144 BottomMenu bottomMenu = build(context); 144 BottomMenu bottomMenu = build(context);
145 List<String> list = new ArrayList<>(); 145 List<String> list = new ArrayList<>();
@@ -152,9 +152,9 @@ public class BottomMenu extends BaseDialog { @@ -152,9 +152,9 @@ public class BottomMenu extends BaseDialog {
152 bottomMenu.showDialog(); 152 bottomMenu.showDialog();
153 return bottomMenu; 153 return bottomMenu;
154 } 154 }
155 - 155 +
156 private View rootView; 156 private View rootView;
157 - 157 +
158 @Override 158 @Override
159 public void bindView(View rootView) { 159 public void bindView(View rootView) {
160 log("启动底部菜单 -> " + toString()); 160 log("启动底部菜单 -> " + toString());
@@ -168,10 +168,10 @@ public class BottomMenu extends BaseDialog { @@ -168,10 +168,10 @@ public class BottomMenu extends BaseDialog {
168 listMenu = rootView.findViewById(R.id.list_menu); 168 listMenu = rootView.findViewById(R.id.list_menu);
169 boxCancel = rootView.findViewById(R.id.box_cancel); 169 boxCancel = rootView.findViewById(R.id.box_cancel);
170 btnCancel = rootView.findViewById(R.id.btn_cancel); 170 btnCancel = rootView.findViewById(R.id.btn_cancel);
171 - 171 +
172 switch (style) { 172 switch (style) {
173 case STYLE_MATERIAL: 173 case STYLE_MATERIAL:
174 - boxCancel.setVisibility(View.GONE); 174 +// boxCancel.setVisibility(View.GONE);
175 boxBody.setY(getRootHeight()); 175 boxBody.setY(getRootHeight());
176 boxBody.setVisibility(View.VISIBLE); 176 boxBody.setVisibility(View.VISIBLE);
177 boxBody.post(new Runnable() { 177 boxBody.post(new Runnable() {
@@ -187,7 +187,7 @@ public class BottomMenu extends BaseDialog { @@ -187,7 +187,7 @@ public class BottomMenu extends BaseDialog {
187 }); 187 });
188 listMenu.setOnTouchListener(listViewTouchListener); 188 listMenu.setOnTouchListener(listViewTouchListener);
189 boxBody.setOnTouchListener(listViewTouchListener); 189 boxBody.setOnTouchListener(listViewTouchListener);
190 - 190 +
191 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 191 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
192 Window window = dialog.get().getDialog().getWindow(); 192 Window window = dialog.get().getDialog().getWindow();
193 window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 193 window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
@@ -197,6 +197,9 @@ public class BottomMenu extends BaseDialog { @@ -197,6 +197,9 @@ public class BottomMenu extends BaseDialog {
197 } 197 }
198 break; 198 break;
199 case STYLE_KONGZUE: 199 case STYLE_KONGZUE:
  200 + if (null != menuTextInfo) {
  201 + btnCancel.setTextSize(menuTextInfo.getFontSize());
  202 + }
200 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 203 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
201 Window window = dialog.get().getDialog().getWindow(); 204 Window window = dialog.get().getDialog().getWindow();
202 window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 205 window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
@@ -204,7 +207,7 @@ public class BottomMenu extends BaseDialog { @@ -204,7 +207,7 @@ public class BottomMenu extends BaseDialog {
204 window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 207 window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
205 window.setNavigationBarColor(Color.WHITE); 208 window.setNavigationBarColor(Color.WHITE);
206 boxBody.setPadding(0, 0, 0, getNavigationBarHeight()); 209 boxBody.setPadding(0, 0, 0, getNavigationBarHeight());
207 - 210 +
208 //设置底部导航栏按钮暗色,无效,悬赏解决———— 211 //设置底部导航栏按钮暗色,无效,悬赏解决————
209 View decorView = window.getDecorView(); 212 View decorView = window.getDecorView();
210 int vis = decorView.getSystemUiVisibility(); 213 int vis = decorView.getSystemUiVisibility();
@@ -216,6 +219,9 @@ public class BottomMenu extends BaseDialog { @@ -216,6 +219,9 @@ public class BottomMenu extends BaseDialog {
216 break; 219 break;
217 case STYLE_IOS: 220 case STYLE_IOS:
218 final int bkgResId, blurFrontColor; 221 final int bkgResId, blurFrontColor;
  222 + if (null != menuTextInfo) {
  223 + btnCancel.setTextSize(menuTextInfo.getFontSize());
  224 + }
219 if (theme == DialogSettings.THEME.LIGHT) { 225 if (theme == DialogSettings.THEME.LIGHT) {
220 bkgResId = R.drawable.rect_menu_bkg_ios; 226 bkgResId = R.drawable.rect_menu_bkg_ios;
221 blurFrontColor = Color.argb(blurAlpha, 244, 245, 246); 227 blurFrontColor = Color.argb(blurAlpha, 244, 245, 246);
@@ -258,31 +264,31 @@ public class BottomMenu extends BaseDialog { @@ -258,31 +264,31 @@ public class BottomMenu extends BaseDialog {
258 } 264 }
259 break; 265 break;
260 } 266 }
261 - 267 +
262 refreshView(); 268 refreshView();
263 if (onShowListener != null) onShowListener.onShow(this); 269 if (onShowListener != null) onShowListener.onShow(this);
264 } 270 }
265 - 271 +
266 private BlurView blurList; 272 private BlurView blurList;
267 private BlurView blurCancel; 273 private BlurView blurCancel;
268 - 274 +
269 @Override 275 @Override
270 public void refreshView() { 276 public void refreshView() {
271 if (cancelButtonTextInfo == null) cancelButtonTextInfo = menuTextInfo; 277 if (cancelButtonTextInfo == null) cancelButtonTextInfo = menuTextInfo;
272 if (menuTitleTextInfo == null) menuTitleTextInfo = menuTitleInfo; 278 if (menuTitleTextInfo == null) menuTitleTextInfo = menuTitleInfo;
273 if (menuTextInfo == null) menuTextInfo = DialogSettings.menuTextInfo; 279 if (menuTextInfo == null) menuTextInfo = DialogSettings.menuTextInfo;
274 if (cancelButtonText == null) cancelButtonText = "取消"; 280 if (cancelButtonText == null) cancelButtonText = "取消";
275 - 281 +
276 if (rootView != null) { 282 if (rootView != null) {
277 btnCancel.setText(cancelButtonText); 283 btnCancel.setText(cancelButtonText);
278 - 284 +
279 ((ViewGroup) boxBody.getParent()).setOnClickListener(new View.OnClickListener() { 285 ((ViewGroup) boxBody.getParent()).setOnClickListener(new View.OnClickListener() {
280 @Override 286 @Override
281 public void onClick(View v) { 287 public void onClick(View v) {
282 doDismiss(); 288 doDismiss();
283 } 289 }
284 }); 290 });
285 - 291 +
286 switch (style) { 292 switch (style) {
287 case STYLE_MATERIAL: 293 case STYLE_MATERIAL:
288 if (customAdapter != null) { 294 if (customAdapter != null) {
@@ -317,7 +323,7 @@ public class BottomMenu extends BaseDialog { @@ -317,7 +323,7 @@ public class BottomMenu extends BaseDialog {
317 menuArrayAdapter = new IOSMenuArrayAdapter(context.get(), R.layout.item_bottom_menu_ios, menuTextList); 323 menuArrayAdapter = new IOSMenuArrayAdapter(context.get(), R.layout.item_bottom_menu_ios, menuTextList);
318 } 324 }
319 listMenu.setAdapter(menuArrayAdapter); 325 listMenu.setAdapter(menuArrayAdapter);
320 - 326 +
321 break; 327 break;
322 } 328 }
323 if (customView != null) { 329 if (customView != null) {
@@ -329,13 +335,13 @@ public class BottomMenu extends BaseDialog { @@ -329,13 +335,13 @@ public class BottomMenu extends BaseDialog {
329 } else { 335 } else {
330 boxCustom.setVisibility(View.GONE); 336 boxCustom.setVisibility(View.GONE);
331 } 337 }
332 - 338 +
333 if (!isNull(title)) { 339 if (!isNull(title)) {
334 txtTitle.setText(title); 340 txtTitle.setText(title);
335 txtTitle.setVisibility(View.VISIBLE); 341 txtTitle.setVisibility(View.VISIBLE);
336 if (titleSplitLine != null) titleSplitLine.setVisibility(View.VISIBLE); 342 if (titleSplitLine != null) titleSplitLine.setVisibility(View.VISIBLE);
337 } 343 }
338 - 344 +
339 listMenu.setOnItemClickListener(new AdapterView.OnItemClickListener() { 345 listMenu.setOnItemClickListener(new AdapterView.OnItemClickListener() {
340 @Override 346 @Override
341 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 347 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
@@ -349,7 +355,7 @@ public class BottomMenu extends BaseDialog { @@ -349,7 +355,7 @@ public class BottomMenu extends BaseDialog {
349 doDismiss(); 355 doDismiss();
350 } 356 }
351 }); 357 });
352 - 358 +
353 btnCancel.setOnClickListener(new View.OnClickListener() { 359 btnCancel.setOnClickListener(new View.OnClickListener() {
354 @Override 360 @Override
355 public void onClick(View v) { 361 public void onClick(View v) {
@@ -357,24 +363,24 @@ public class BottomMenu extends BaseDialog { @@ -357,24 +363,24 @@ public class BottomMenu extends BaseDialog {
357 } 363 }
358 }); 364 });
359 } 365 }
360 - 366 +
361 useTextInfo(txtTitle, menuTitleTextInfo); 367 useTextInfo(txtTitle, menuTitleTextInfo);
362 useTextInfo(btnCancel, cancelButtonTextInfo); 368 useTextInfo(btnCancel, cancelButtonTextInfo);
363 } 369 }
364 - 370 +
365 @Override 371 @Override
366 public void show() { 372 public void show() {
367 showDialog(); 373 showDialog();
368 } 374 }
369 - 375 +
370 private BaseAdapter menuArrayAdapter; 376 private BaseAdapter menuArrayAdapter;
371 - 377 +
372 public class IOSMenuArrayAdapter extends NormalMenuArrayAdapter { 378 public class IOSMenuArrayAdapter extends NormalMenuArrayAdapter {
373 - 379 +
374 public IOSMenuArrayAdapter(Context context, int resourceId, List<String> objects) { 380 public IOSMenuArrayAdapter(Context context, int resourceId, List<String> objects) {
375 super(context, resourceId, objects); 381 super(context, resourceId, objects);
376 } 382 }
377 - 383 +
378 @Override 384 @Override
379 public View getView(int position, View convertView, ViewGroup parent) { 385 public View getView(int position, View convertView, ViewGroup parent) {
380 ViewHolder viewHolder = null; 386 ViewHolder viewHolder = null;
@@ -390,9 +396,9 @@ public class BottomMenu extends BaseDialog { @@ -390,9 +396,9 @@ public class BottomMenu extends BaseDialog {
390 String text = objects.get(position); 396 String text = objects.get(position);
391 if (null != text) { 397 if (null != text) {
392 viewHolder.textView.setText(text); 398 viewHolder.textView.setText(text);
393 - 399 +
394 useTextInfo(viewHolder.textView, menuTextInfo); 400 useTextInfo(viewHolder.textView, menuTextInfo);
395 - 401 +
396 if (objects.size() == 1) { 402 if (objects.size() == 1) {
397 if (theme == DialogSettings.THEME.LIGHT) { 403 if (theme == DialogSettings.THEME.LIGHT) {
398 if (title != null && !title.trim().isEmpty()) { 404 if (title != null && !title.trim().isEmpty()) {
@@ -451,42 +457,42 @@ public class BottomMenu extends BaseDialog { @@ -451,42 +457,42 @@ public class BottomMenu extends BaseDialog {
451 } 457 }
452 } 458 }
453 } 459 }
454 - 460 +
455 return convertView; 461 return convertView;
456 } 462 }
457 } 463 }
458 - 464 +
459 public class NormalMenuArrayAdapter extends ArrayAdapter { 465 public class NormalMenuArrayAdapter extends ArrayAdapter {
460 public int resoureId; 466 public int resoureId;
461 public List<String> objects; 467 public List<String> objects;
462 public Context context; 468 public Context context;
463 - 469 +
464 public NormalMenuArrayAdapter(Context context, int resourceId, List<String> objects) { 470 public NormalMenuArrayAdapter(Context context, int resourceId, List<String> objects) {
465 super(context, resourceId, objects); 471 super(context, resourceId, objects);
466 this.objects = objects; 472 this.objects = objects;
467 this.resoureId = resourceId; 473 this.resoureId = resourceId;
468 this.context = context; 474 this.context = context;
469 } 475 }
470 - 476 +
471 public class ViewHolder { 477 public class ViewHolder {
472 TextView textView; 478 TextView textView;
473 } 479 }
474 - 480 +
475 @Override 481 @Override
476 public int getCount() { 482 public int getCount() {
477 return objects.size(); 483 return objects.size();
478 } 484 }
479 - 485 +
480 @Override 486 @Override
481 public String getItem(int position) { 487 public String getItem(int position) {
482 return objects.get(position); 488 return objects.get(position);
483 } 489 }
484 - 490 +
485 @Override 491 @Override
486 public long getItemId(int position) { 492 public long getItemId(int position) {
487 return position; 493 return position;
488 } 494 }
489 - 495 +
490 @Override 496 @Override
491 public View getView(int position, View convertView, ViewGroup parent) { 497 public View getView(int position, View convertView, ViewGroup parent) {
492 ViewHolder viewHolder = null; 498 ViewHolder viewHolder = null;
@@ -502,25 +508,25 @@ public class BottomMenu extends BaseDialog { @@ -502,25 +508,25 @@ public class BottomMenu extends BaseDialog {
502 String text = objects.get(position); 508 String text = objects.get(position);
503 if (null != text) { 509 if (null != text) {
504 viewHolder.textView.setText(text); 510 viewHolder.textView.setText(text);
505 - 511 +
506 useTextInfo(viewHolder.textView, menuTextInfo); 512 useTextInfo(viewHolder.textView, menuTextInfo);
507 } 513 }
508 - 514 +
509 return convertView; 515 return convertView;
510 } 516 }
511 } 517 }
512 - 518 +
513 //其他设置 519 //其他设置
514 public List<String> getMenuTextList() { 520 public List<String> getMenuTextList() {
515 return menuTextList; 521 return menuTextList;
516 } 522 }
517 - 523 +
518 public BottomMenu setMenuTextList(List<String> menuTextList) { 524 public BottomMenu setMenuTextList(List<String> menuTextList) {
519 this.menuTextList = menuTextList; 525 this.menuTextList = menuTextList;
520 refreshView(); 526 refreshView();
521 return this; 527 return this;
522 } 528 }
523 - 529 +
524 public BottomMenu setMenuTextList(String[] menuTexts) { 530 public BottomMenu setMenuTextList(String[] menuTexts) {
525 List<String> list = new ArrayList<>(); 531 List<String> list = new ArrayList<>();
526 for (String s : menuTexts) { 532 for (String s : menuTexts) {
@@ -530,150 +536,150 @@ public class BottomMenu extends BaseDialog { @@ -530,150 +536,150 @@ public class BottomMenu extends BaseDialog {
530 refreshView(); 536 refreshView();
531 return this; 537 return this;
532 } 538 }
533 - 539 +
534 public String getTitle() { 540 public String getTitle() {
535 return title; 541 return title;
536 } 542 }
537 - 543 +
538 public BottomMenu setTitle(String title) { 544 public BottomMenu setTitle(String title) {
539 this.title = title; 545 this.title = title;
540 refreshView(); 546 refreshView();
541 return this; 547 return this;
542 } 548 }
543 - 549 +
544 public BottomMenu setTitle(int titleResId) { 550 public BottomMenu setTitle(int titleResId) {
545 this.title = context.get().getString(titleResId); 551 this.title = context.get().getString(titleResId);
546 refreshView(); 552 refreshView();
547 return this; 553 return this;
548 } 554 }
549 - 555 +
550 public String getCancelButtonText() { 556 public String getCancelButtonText() {
551 return cancelButtonText; 557 return cancelButtonText;
552 } 558 }
553 - 559 +
554 public BottomMenu setCancelButtonText(String cancelButtonText) { 560 public BottomMenu setCancelButtonText(String cancelButtonText) {
555 this.cancelButtonText = cancelButtonText; 561 this.cancelButtonText = cancelButtonText;
556 refreshView(); 562 refreshView();
557 return this; 563 return this;
558 } 564 }
559 - 565 +
560 public BottomMenu setCancelButtonText(int cancelButtonTextResId) { 566 public BottomMenu setCancelButtonText(int cancelButtonTextResId) {
561 this.cancelButtonText = context.get().getString(cancelButtonTextResId); 567 this.cancelButtonText = context.get().getString(cancelButtonTextResId);
562 refreshView(); 568 refreshView();
563 return this; 569 return this;
564 } 570 }
565 - 571 +
566 public boolean isShowCancelButton() { 572 public boolean isShowCancelButton() {
567 return showCancelButton; 573 return showCancelButton;
568 } 574 }
569 - 575 +
570 public BottomMenu setShowCancelButton(boolean showCancelButton) { 576 public BottomMenu setShowCancelButton(boolean showCancelButton) {
571 this.showCancelButton = showCancelButton; 577 this.showCancelButton = showCancelButton;
572 refreshView(); 578 refreshView();
573 return this; 579 return this;
574 } 580 }
575 - 581 +
576 public OnMenuItemClickListener getOnMenuItemClickListener() { 582 public OnMenuItemClickListener getOnMenuItemClickListener() {
577 return onMenuItemClickListener; 583 return onMenuItemClickListener;
578 } 584 }
579 - 585 +
580 public BottomMenu setOnMenuItemClickListener(OnMenuItemClickListener onMenuItemClickListener) { 586 public BottomMenu setOnMenuItemClickListener(OnMenuItemClickListener onMenuItemClickListener) {
581 this.onMenuItemClickListener = onMenuItemClickListener; 587 this.onMenuItemClickListener = onMenuItemClickListener;
582 refreshView(); 588 refreshView();
583 return this; 589 return this;
584 } 590 }
585 - 591 +
586 public TextInfo getMenuTitleTextInfo() { 592 public TextInfo getMenuTitleTextInfo() {
587 return menuTitleTextInfo; 593 return menuTitleTextInfo;
588 } 594 }
589 - 595 +
590 public BottomMenu setMenuTitleTextInfo(TextInfo menuTitleTextInfo) { 596 public BottomMenu setMenuTitleTextInfo(TextInfo menuTitleTextInfo) {
591 this.menuTitleTextInfo = menuTitleTextInfo; 597 this.menuTitleTextInfo = menuTitleTextInfo;
592 refreshView(); 598 refreshView();
593 return this; 599 return this;
594 } 600 }
595 - 601 +
596 public TextInfo getMenuTextInfo() { 602 public TextInfo getMenuTextInfo() {
597 return menuTextInfo; 603 return menuTextInfo;
598 } 604 }
599 - 605 +
600 public BottomMenu setMenuTextInfo(TextInfo menuTextInfo) { 606 public BottomMenu setMenuTextInfo(TextInfo menuTextInfo) {
601 this.menuTextInfo = menuTextInfo; 607 this.menuTextInfo = menuTextInfo;
602 refreshView(); 608 refreshView();
603 return this; 609 return this;
604 } 610 }
605 - 611 +
606 public TextInfo getCancelButtonTextInfo() { 612 public TextInfo getCancelButtonTextInfo() {
607 return cancelButtonTextInfo; 613 return cancelButtonTextInfo;
608 } 614 }
609 - 615 +
610 public BottomMenu setCancelButtonTextInfo(TextInfo cancelButtonTextInfo) { 616 public BottomMenu setCancelButtonTextInfo(TextInfo cancelButtonTextInfo) {
611 this.cancelButtonTextInfo = cancelButtonTextInfo; 617 this.cancelButtonTextInfo = cancelButtonTextInfo;
612 refreshView(); 618 refreshView();
613 return this; 619 return this;
614 } 620 }
615 - 621 +
616 public OnDismissListener getOnDismissListener() { 622 public OnDismissListener getOnDismissListener() {
617 return onDismissListener == null ? new OnDismissListener() { 623 return onDismissListener == null ? new OnDismissListener() {
618 @Override 624 @Override
619 public void onDismiss() { 625 public void onDismiss() {
620 - 626 +
621 } 627 }
622 } : onDismissListener; 628 } : onDismissListener;
623 } 629 }
624 - 630 +
625 public BottomMenu setOnDismissListener(OnDismissListener onDismissListener) { 631 public BottomMenu setOnDismissListener(OnDismissListener onDismissListener) {
626 this.onDismissListener = onDismissListener; 632 this.onDismissListener = onDismissListener;
627 return this; 633 return this;
628 } 634 }
629 - 635 +
630 public OnShowListener getOnShowListener() { 636 public OnShowListener getOnShowListener() {
631 return onShowListener == null ? new OnShowListener() { 637 return onShowListener == null ? new OnShowListener() {
632 @Override 638 @Override
633 public void onShow(BaseDialog dialog) { 639 public void onShow(BaseDialog dialog) {
634 - 640 +
635 } 641 }
636 } : onShowListener; 642 } : onShowListener;
637 } 643 }
638 - 644 +
639 public BottomMenu setOnShowListener(OnShowListener onShowListener) { 645 public BottomMenu setOnShowListener(OnShowListener onShowListener) {
640 this.onShowListener = onShowListener; 646 this.onShowListener = onShowListener;
641 return this; 647 return this;
642 } 648 }
643 - 649 +
644 public View getCustomView() { 650 public View getCustomView() {
645 return customView; 651 return customView;
646 } 652 }
647 - 653 +
648 public BottomMenu setCustomView(View customView) { 654 public BottomMenu setCustomView(View customView) {
649 this.customView = customView; 655 this.customView = customView;
650 refreshView(); 656 refreshView();
651 return this; 657 return this;
652 } 658 }
653 - 659 +
654 private OnBindView onBindView; 660 private OnBindView onBindView;
655 - 661 +
656 public BottomMenu setCustomView(int customViewLayoutId, OnBindView onBindView) { 662 public BottomMenu setCustomView(int customViewLayoutId, OnBindView onBindView) {
657 customView = LayoutInflater.from(context.get()).inflate(customViewLayoutId, null); 663 customView = LayoutInflater.from(context.get()).inflate(customViewLayoutId, null);
658 this.onBindView = onBindView; 664 this.onBindView = onBindView;
659 refreshView(); 665 refreshView();
660 return this; 666 return this;
661 } 667 }
662 - 668 +
663 public interface OnBindView { 669 public interface OnBindView {
664 void onBind(BottomMenu bottomMenu, View v); 670 void onBind(BottomMenu bottomMenu, View v);
665 } 671 }
666 - 672 +
667 public DialogSettings.STYLE getStyle() { 673 public DialogSettings.STYLE getStyle() {
668 return style; 674 return style;
669 } 675 }
670 - 676 +
671 public BottomMenu setStyle(DialogSettings.STYLE style) { 677 public BottomMenu setStyle(DialogSettings.STYLE style) {
672 if (isAlreadyShown) { 678 if (isAlreadyShown) {
673 error("必须使用 build(...) 方法创建时,才可以使用 setStyle(...) 来修改对话框主题或风格。"); 679 error("必须使用 build(...) 方法创建时,才可以使用 setStyle(...) 来修改对话框主题或风格。");
674 return this; 680 return this;
675 } 681 }
676 - 682 +
677 this.style = style; 683 this.style = style;
678 switch (this.style) { 684 switch (this.style) {
679 case STYLE_IOS: 685 case STYLE_IOS:
@@ -686,40 +692,40 @@ public class BottomMenu extends BaseDialog { @@ -686,40 +692,40 @@ public class BottomMenu extends BaseDialog {
686 build(this, R.layout.bottom_menu_material); 692 build(this, R.layout.bottom_menu_material);
687 break; 693 break;
688 } 694 }
689 - 695 +
690 return this; 696 return this;
691 } 697 }
692 - 698 +
693 public DialogSettings.THEME getTheme() { 699 public DialogSettings.THEME getTheme() {
694 return theme; 700 return theme;
695 } 701 }
696 - 702 +
697 public BottomMenu setTheme(DialogSettings.THEME theme) { 703 public BottomMenu setTheme(DialogSettings.THEME theme) {
698 - 704 +
699 if (isAlreadyShown) { 705 if (isAlreadyShown) {
700 error("必须使用 build(...) 方法创建时,才可以使用 setTheme(...) 来修改对话框主题或风格。"); 706 error("必须使用 build(...) 方法创建时,才可以使用 setTheme(...) 来修改对话框主题或风格。");
701 return this; 707 return this;
702 } 708 }
703 - 709 +
704 this.theme = theme; 710 this.theme = theme;
705 refreshView(); 711 refreshView();
706 return this; 712 return this;
707 } 713 }
708 - 714 +
709 public BaseAdapter getCustomAdapter() { 715 public BaseAdapter getCustomAdapter() {
710 return customAdapter; 716 return customAdapter;
711 } 717 }
712 - 718 +
713 public BottomMenu setCustomAdapter(BaseAdapter customAdapter) { 719 public BottomMenu setCustomAdapter(BaseAdapter customAdapter) {
714 this.customAdapter = customAdapter; 720 this.customAdapter = customAdapter;
715 return this; 721 return this;
716 } 722 }
717 - 723 +
718 private float boxBodyOldY; 724 private float boxBodyOldY;
719 private int step; 725 private int step;
720 private boolean isTouchDown; 726 private boolean isTouchDown;
721 private float touchDownY; 727 private float touchDownY;
722 - 728 +
723 private View.OnTouchListener listViewTouchListener = new View.OnTouchListener() { 729 private View.OnTouchListener listViewTouchListener = new View.OnTouchListener() {
724 @Override 730 @Override
725 public boolean onTouch(View v, MotionEvent event) { 731 public boolean onTouch(View v, MotionEvent event) {
@@ -749,7 +755,7 @@ public class BottomMenu extends BaseDialog { @@ -749,7 +755,7 @@ public class BottomMenu extends BaseDialog {
749 case MotionEvent.ACTION_CANCEL: 755 case MotionEvent.ACTION_CANCEL:
750 if (isTouchDown) { 756 if (isTouchDown) {
751 float deltaY = boxBody.getY() - boxBodyOldY; 757 float deltaY = boxBody.getY() - boxBodyOldY;
752 - 758 +
753 if (deltaY >= -dip2px(50) && deltaY <= dip2px(50)) { 759 if (deltaY >= -dip2px(50) && deltaY <= dip2px(50)) {
754 //几乎没动,回到原来位置 760 //几乎没动,回到原来位置
755 boxBody.animate().setDuration(300).translationY(boxBodyOldY); 761 boxBody.animate().setDuration(300).translationY(boxBodyOldY);
@@ -802,7 +808,7 @@ public class BottomMenu extends BaseDialog { @@ -802,7 +808,7 @@ public class BottomMenu extends BaseDialog {
802 } 808 }
803 } 809 }
804 }; 810 };
805 - 811 +
806 private boolean isListViewOnTop() { 812 private boolean isListViewOnTop() {
807 View c = listMenu.getChildAt(0); 813 View c = listMenu.getChildAt(0);
808 if (c == null) { 814 if (c == null) {
@@ -815,7 +821,7 @@ public class BottomMenu extends BaseDialog { @@ -815,7 +821,7 @@ public class BottomMenu extends BaseDialog {
815 int top = c.getTop(); 821 int top = c.getTop();
816 return top == 0; 822 return top == 0;
817 } 823 }
818 - 824 +
819 public BottomMenu setCustomDialogStyleId(int customDialogStyleId) { 825 public BottomMenu setCustomDialogStyleId(int customDialogStyleId) {
820 if (isAlreadyShown) { 826 if (isAlreadyShown) {
821 error("必须使用 build(...) 方法创建时,才可以使用 setTheme(...) 来修改对话框主题或风格。"); 827 error("必须使用 build(...) 方法创建时,才可以使用 setTheme(...) 来修改对话框主题或风格。");
@@ -824,24 +830,24 @@ public class BottomMenu extends BaseDialog { @@ -824,24 +830,24 @@ public class BottomMenu extends BaseDialog {
824 this.customDialogStyleId = customDialogStyleId; 830 this.customDialogStyleId = customDialogStyleId;
825 return this; 831 return this;
826 } 832 }
827 - 833 +
828 public String toString() { 834 public String toString() {
829 return getClass().getSimpleName() + "@" + Integer.toHexString(hashCode()); 835 return getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
830 } 836 }
831 - 837 +
832 public OnBackClickListener getOnBackClickListener() { 838 public OnBackClickListener getOnBackClickListener() {
833 return onBackClickListener; 839 return onBackClickListener;
834 } 840 }
835 - 841 +
836 public BottomMenu setOnBackClickListener(OnBackClickListener onBackClickListener) { 842 public BottomMenu setOnBackClickListener(OnBackClickListener onBackClickListener) {
837 this.onBackClickListener = onBackClickListener; 843 this.onBackClickListener = onBackClickListener;
838 return this; 844 return this;
839 } 845 }
840 - 846 +
841 public boolean getCancelable() { 847 public boolean getCancelable() {
842 return cancelable == BOOLEAN.TRUE; 848 return cancelable == BOOLEAN.TRUE;
843 } 849 }
844 - 850 +
845 public BottomMenu setCancelable(boolean enable) { 851 public BottomMenu setCancelable(boolean enable) {
846 this.cancelable = enable ? BOOLEAN.TRUE : BOOLEAN.FALSE; 852 this.cancelable = enable ? BOOLEAN.TRUE : BOOLEAN.FALSE;
847 if (dialog != null) dialog.get().setCancelable(cancelable == BOOLEAN.TRUE); 853 if (dialog != null) dialog.get().setCancelable(cancelable == BOOLEAN.TRUE);
core/base/src/main/res/layout/bottom_menu_ios.xml
@@ -94,8 +94,8 @@ @@ -94,8 +94,8 @@
94 android:paddingRight="15dp" 94 android:paddingRight="15dp"
95 android:singleLine="true" 95 android:singleLine="true"
96 android:text="CANCEL" 96 android:text="CANCEL"
97 - android:textColor="@color/dialogButtonIOSNormal"  
98 - android:textSize="19dp" 97 + android:textColor="@color/btnCancel"
  98 + android:textSize="16dp"
99 android:textStyle="bold" /> 99 android:textStyle="bold" />
100 100
101 </RelativeLayout> 101 </RelativeLayout>
core/base/src/main/res/values/attrs.xml
1 <?xml version="1.0" encoding="utf-8"?> 1 <?xml version="1.0" encoding="utf-8"?>
2 -<resources> 2 +<resources xmlns:tools="http://schemas.android.com/tools">
3 <attr name="iconSize" format="dimension" /> 3 <attr name="iconSize" format="dimension" />
4 <attr name="iconMargin" format="dimension" /> 4 <attr name="iconMargin" format="dimension" />
5 <attr name="iconSrc" format="reference" /> 5 <attr name="iconSrc" format="reference" />
@@ -80,4 +80,30 @@ @@ -80,4 +80,30 @@
80 80
81 <attr name="SwipeBackLayoutStyle" format="reference" /> 81 <attr name="SwipeBackLayoutStyle" format="reference" />
82 <!-- --> 82 <!-- -->
  83 + <!-- swithbutton-->
  84 + <declare-styleable name="SwitchButton" tools:ignore="ResourceName">
  85 + <attr name="kswThumbDrawable" format="reference" />
  86 + <attr name="kswThumbColor" format="color|reference" />
  87 + <attr name="kswThumbMargin" format="dimension|reference" />
  88 + <attr name="kswThumbMarginTop" format="dimension|reference" />
  89 + <attr name="kswThumbMarginBottom" format="dimension|reference" />
  90 + <attr name="kswThumbMarginLeft" format="dimension|reference" />
  91 + <attr name="kswThumbMarginRight" format="dimension|reference" />
  92 + <attr name="kswThumbWidth" format="dimension|reference" />
  93 + <attr name="kswThumbHeight" format="dimension|reference" />
  94 + <attr name="kswThumbRadius" format="dimension|reference" />
  95 + <attr name="kswBackRadius" format="dimension|reference" />
  96 + <attr name="kswBackDrawable" format="reference" />
  97 + <attr name="kswBackColor" format="color|reference" />
  98 + <attr name="kswFadeBack" format="boolean" />
  99 + <attr name="kswThumbRangeRatio" format="float" />
  100 + <attr name="kswAnimationDuration" format="integer" />
  101 + <attr name="kswTintColor" format="color|reference" />
  102 + <attr name="kswTextOn" format="string" />
  103 + <attr name="kswTextOff" format="string" />
  104 + <attr name="kswTextThumbInset" format="dimension" />
  105 + <attr name="kswTextExtra" format="dimension" />
  106 + <attr name="kswTextAdjust" format="dimension" />
  107 + </declare-styleable>
  108 + <!---->
83 </resources> 109 </resources>
84 \ No newline at end of file 110 \ No newline at end of file
core/base/src/main/res/values/colors.xml
@@ -51,6 +51,8 @@ @@ -51,6 +51,8 @@
51 <color name="blackAlpha30">#4D000000</color> 51 <color name="blackAlpha30">#4D000000</color>
52 <color name="blackAlpha10">#1A000000</color> 52 <color name="blackAlpha10">#1A000000</color>
53 <color name="notificationNormal">#353535</color> 53 <color name="notificationNormal">#353535</color>
  54 + <color name="btnCancel">#FF6A6A</color>
  55 +
54 <color name="notificationError">#e74e63</color> 56 <color name="notificationError">#e74e63</color>
55 <color name="notificationWarning">#ef8e43</color> 57 <color name="notificationWarning">#ef8e43</color>
56 <color name="notificationFinish">#53ae5d</color> 58 <color name="notificationFinish">#53ae5d</color>
core/imageload/build.gradle
1 apply plugin: 'com.android.library' 1 apply plugin: 'com.android.library'
2 2
3 android { 3 android {
4 - compileSdkVersion 29  
5 - buildToolsVersion "29.0.2"  
6 -  
7 -  
8 - defaultConfig {  
9 - minSdkVersion 16  
10 - targetSdkVersion 29  
11 - versionCode 1  
12 - versionName "1.0"  
13 -  
14 - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"  
15 - consumerProguardFiles 'consumer-rules.pro'  
16 - }  
17 -  
18 - buildTypes {  
19 - release {  
20 - minifyEnabled false  
21 - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'  
22 - }  
23 - } 4 +// compileSdkVersion 29
  5 +// buildToolsVersion "29.0.2"
  6 +//
  7 +//
  8 +// defaultConfig {
  9 +// minSdkVersion 16
  10 +// targetSdkVersion 29
  11 +// versionCode 1
  12 +// versionName "1.0"
  13 +//
  14 +// testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
  15 +// consumerProguardFiles 'consumer-rules.pro'
  16 +// }
  17 +//
  18 +// buildTypes {
  19 +// release {
  20 +// minifyEnabled false
  21 +// proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
  22 +// }
  23 +// }
24 24
25 } 25 }
26 26
core/network/src/main/java/com/cnlive/core/network/HttpConn.java
1 package com.cnlive.core.network; 1 package com.cnlive.core.network;
2 2
3 3
  4 +import android.content.Context;
4 import android.util.Log; 5 import android.util.Log;
5 6
  7 +import com.cnlive.core.libs.base.application.BaseApplication;
6 import com.cnlive.core.libs.base.network.manager.SubscriptionManager; 8 import com.cnlive.core.libs.base.network.manager.SubscriptionManager;
  9 +import com.cnlive.core.network.util.NetworkUtil;
7 10
8 import java.util.ArrayList; 11 import java.util.ArrayList;
9 import java.util.HashMap; 12 import java.util.HashMap;
@@ -22,7 +25,9 @@ public class HttpConn { @@ -22,7 +25,9 @@ public class HttpConn {
22 public static final int ON_START = -6006; 25 public static final int ON_START = -6006;
23 public static final int ON_END = -6007; 26 public static final int ON_END = -6007;
24 public static final String EXCEPTION_CODE = "-1";//异常 27 public static final String EXCEPTION_CODE = "-1";//异常
25 -// public <T> Observable 28 + private static String API_ERROR_NETWORK = "-3";
  29 + private static String API_MESSAGE_NETWORK = "网络连接失败";
  30 +
26 31
27 /** 32 /**
28 * 统一处理单个请求 33 * 统一处理单个请求
@@ -35,48 +40,99 @@ public class HttpConn { @@ -35,48 +40,99 @@ public class HttpConn {
35 40
36 public static <T> Disposable action(Observable<T> observable, final NetCallBack<T> callBack) { 41 public static <T> Disposable action(Observable<T> observable, final NetCallBack<T> callBack) {
37 disposable = null; 42 disposable = null;
38 - observable  
39 - .subscribeOn(Schedulers.io())  
40 - .observeOn(AndroidSchedulers.mainThread())  
41 - .subscribe(new BaseObserver<T>() {  
42 - @Override  
43 - protected void onRequestStart(Disposable d) {  
44 - super.onRequestStart(d);  
45 - disposable = d;  
46 - if (null != callBack) {  
47 - callBack.onRequestState(ON_START); 43 + if (null != BaseApplication.getInstance()) {
  44 + if (!NetworkUtil.isConnectInternet(BaseApplication.getInstance())) {
  45 + if (null != callBack) {
  46 + callBack.onFailure(API_ERROR_NETWORK, API_MESSAGE_NETWORK);
  47 + }
  48 + } else {
  49 + observable
  50 + .subscribeOn(Schedulers.io())
  51 + .observeOn(AndroidSchedulers.mainThread())
  52 + .subscribe(new BaseObserver<T>() {
  53 + @Override
  54 + protected void onRequestStart(Disposable d) {
  55 + super.onRequestStart(d);
  56 + disposable = d;
  57 + if (null != callBack) {
  58 + callBack.onRequestState(ON_START);
  59 + }
  60 + }
  61 +
  62 + @Override
  63 + protected void onRequestEnd() {
  64 + super.onRequestEnd();
  65 + if (null != callBack) {
  66 + callBack.onRequestState(ON_END);
  67 + }
  68 + }
  69 +
  70 + @Override
  71 + protected void onSuccess(T result) throws Exception {
  72 + if (null != callBack) {
  73 + callBack.onSuccess(result);
  74 + }
  75 + }
  76 +
  77 + @Override
  78 + protected void onCodeError(String errCode, String errMsg) throws Exception {
  79 + if (null != callBack) {
  80 + callBack.onFailure(errCode, errMsg);
  81 + }
  82 + }
  83 +
  84 + @Override
  85 + protected void onFailure(String errCode, String errMsg) throws Exception {
  86 + if (null != callBack) {
  87 + callBack.onFailure(errCode, errMsg);
  88 + }
  89 + }
  90 + });
  91 + }
  92 + } else {
  93 + observable
  94 + .subscribeOn(Schedulers.io())
  95 + .observeOn(AndroidSchedulers.mainThread())
  96 + .subscribe(new BaseObserver<T>() {
  97 + @Override
  98 + protected void onRequestStart(Disposable d) {
  99 + super.onRequestStart(d);
  100 + disposable = d;
  101 + if (null != callBack) {
  102 + callBack.onRequestState(ON_START);
  103 + }
48 } 104 }
49 - }  
50 105
51 - @Override  
52 - protected void onRequestEnd() {  
53 - super.onRequestEnd();  
54 - if (null != callBack) {  
55 - callBack.onRequestState(ON_END); 106 + @Override
  107 + protected void onRequestEnd() {
  108 + super.onRequestEnd();
  109 + if (null != callBack) {
  110 + callBack.onRequestState(ON_END);
  111 + }
56 } 112 }
57 - }  
58 113
59 - @Override  
60 - protected void onSuccess(T result) throws Exception {  
61 - if (null != callBack) {  
62 - callBack.onSuccess(result); 114 + @Override
  115 + protected void onSuccess(T result) throws Exception {
  116 + if (null != callBack) {
  117 + callBack.onSuccess(result);
  118 + }
63 } 119 }
64 - }  
65 120
66 - @Override  
67 - protected void onCodeError(String errCode, String errMsg) throws Exception {  
68 - if (null != callBack) {  
69 - callBack.onFailure(errCode, errMsg); 121 + @Override
  122 + protected void onCodeError(String errCode, String errMsg) throws Exception {
  123 + if (null != callBack) {
  124 + callBack.onFailure(errCode, errMsg);
  125 + }
70 } 126 }
71 - }  
72 127
73 - @Override  
74 - protected void onFailure(String errCode, String errMsg) throws Exception {  
75 - if (null != callBack) {  
76 - callBack.onFailure(errCode, errMsg); 128 + @Override
  129 + protected void onFailure(String errCode, String errMsg) throws Exception {
  130 + if (null != callBack) {
  131 + callBack.onFailure(errCode, errMsg);
  132 + }
77 } 133 }
78 - }  
79 - }); 134 + });
  135 + }
80 // .doOnSubscribe(new Consumer<Disposable>() { 136 // .doOnSubscribe(new Consumer<Disposable>() {
81 // @Override 137 // @Override
82 // public void accept(Disposable disposable) throws Exception { 138 // public void accept(Disposable disposable) throws Exception {