From 0c89bf11bcddd39b5193bb19e28399648c59a2b8 Mon Sep 17 00:00:00 2001 From: nilupeng <qingingrunt2010@qq.com> Date: Sat, 29 Jan 2022 11:04:25 +0000 Subject: [PATCH] 登录界面及接口 --- app/src/main/java/com/runt/open/mvvm/base/activities/BaseActivity.java | 129 +++ app/src/main/java/com/runt/open/mvvm/MyApplication.java | 11 app/src/main/res/values/styles.xml | 44 + app/src/main/res/values/themes.xml | 5 app/src/main/java/com/runt/open/mvvm/retrofit/api/LoginApiCenter.java | 49 + app/src/main/java/com/runt/open/mvvm/data/BaseApiResult.java | 1 app/src/main/java/com/runt/open/mvvm/ui/web/WebViewActivity.java | 159 +++ app/src/main/java/com/runt/open/mvvm/util/PhoneUtil.java | 77 + app/src/main/java/com/runt/open/mvvm/listener/CrashHandler.java | 260 ++++++ app/src/main/java/com/runt/open/mvvm/ui/login/CodeTimer.java | 40 + app/src/main/java/com/runt/open/mvvm/ui/login/LoginViewModel.java | 132 +++ app/src/main/java/com/runt/open/mvvm/retrofit/Interceptor/HttpLoggingInterceptor.java | 2 app/src/main/java/com/runt/open/mvvm/util/PreferencesUtils.java | 352 ++++++++ app/src/main/res/values/strings.xml | 67 + app/src/main/java/com/runt/open/mvvm/MainActivity.java | 16 app/src/main/AndroidManifest.xml | 2 app/src/main/java/com/runt/open/mvvm/retrofit/observable/HttpObserver.java | 7 app/src/main/res/color/btn_txt_normal.xml | 9 /dev/null | 48 - app/src/main/java/com/runt/open/mvvm/config/Configuration.java | 16 app/src/main/res/layout/activity_login.xml | 138 +++ app/src/main/res/layout/activity_web.xml | 40 + app/src/main/java/com/runt/open/mvvm/data/Results.java | 16 app/src/main/java/com/runt/open/mvvm/util/MyAnimations.java | 477 +++++++++++ app/src/main/java/com/runt/open/mvvm/ui/login/RegisterLoginActivity.java | 287 +++++++ 25 files changed, 2,322 insertions(+), 62 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1b81d3c..4e8fded 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -51,6 +51,8 @@ <action android:name="com.zfwl.merchant.activities.MainActivity" /> </intent-filter> </activity> + <activity android:name=".ui.login.RegisterLoginActivity" /> + <activity android:name=".ui.web.WebViewActivity" /> </application> </manifest> \ No newline at end of file diff --git a/app/src/main/java/com/runt/open/mvvm/MainActivity.java b/app/src/main/java/com/runt/open/mvvm/MainActivity.java index 6871cf3..1297088 100644 --- a/app/src/main/java/com/runt/open/mvvm/MainActivity.java +++ b/app/src/main/java/com/runt/open/mvvm/MainActivity.java @@ -1,7 +1,12 @@ package com.runt.open.mvvm; import android.Manifest; +import android.content.Intent; +import androidx.activity.result.ActivityResult; +import androidx.activity.result.ActivityResultCallback; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.navigation.NavController; import androidx.navigation.Navigation; import androidx.navigation.ui.NavigationUI; @@ -11,6 +16,7 @@ import com.runt.open.mvvm.data.PhoneDevice; import com.runt.open.mvvm.databinding.ActivityMainBinding; import com.runt.open.mvvm.listener.ResPonse; +import com.runt.open.mvvm.ui.login.RegisterLoginActivity; import com.runt.open.mvvm.ui.main.MainViewModel; public class MainActivity extends BaseActivity<ActivityMainBinding, MainViewModel> { @@ -20,6 +26,16 @@ NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_main); NavigationUI.setupWithNavController(binding.navView, navController); checkPermission(); + ActivityResultLauncher<Intent> launcher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() { + @Override + public void onActivityResult(ActivityResult result) { + if(result.getResultCode() == RESULT_CODE_SUCESS){ + showToast("登录成功"); + } + } + }); + Intent intent = new Intent(mContext, RegisterLoginActivity.class); + launcher.launch(intent); } private void showPermissionDialog(){ diff --git a/app/src/main/java/com/runt/open/mvvm/MyApplication.java b/app/src/main/java/com/runt/open/mvvm/MyApplication.java index ab1a97f..30f98b9 100644 --- a/app/src/main/java/com/runt/open/mvvm/MyApplication.java +++ b/app/src/main/java/com/runt/open/mvvm/MyApplication.java @@ -11,6 +11,7 @@ import com.bytedance.sdk.openadsdk.TTAdConfig; import com.bytedance.sdk.openadsdk.TTAdConstant; import com.bytedance.sdk.openadsdk.TTAdSdk; +import com.runt.open.mvvm.listener.CrashHandler; import com.runt.open.mvvm.util.MyLog; import com.scwang.smart.refresh.footer.ClassicsFooter; import com.scwang.smart.refresh.header.ClassicsHeader; @@ -137,6 +138,16 @@ MyLog.e(TAG,"TTAdSdk fail"); } }); + CrashHandler crashHandler = CrashHandler.getInstance(); + crashHandler.init(getApplicationContext(), new CrashHandler.CrashListener() { + @Override + public void onCrash() { + for(Activity activity : activities){ + activity.finish(); + } + System.exit(0); + } + }); } /** diff --git a/app/src/main/java/com/runt/open/mvvm/base/activities/BaseActivity.java b/app/src/main/java/com/runt/open/mvvm/base/activities/BaseActivity.java index 5d775df..1629d1c 100644 --- a/app/src/main/java/com/runt/open/mvvm/base/activities/BaseActivity.java +++ b/app/src/main/java/com/runt/open/mvvm/base/activities/BaseActivity.java @@ -28,10 +28,12 @@ import com.runt.open.mvvm.base.model.BaseViewModel; import com.runt.open.mvvm.base.model.ViewModelFactory; import com.runt.open.mvvm.listener.ResPonse; +import com.runt.open.mvvm.util.PreferencesUtils; import java.io.File; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; +import java.util.Set; import dmax.dialog.SpotsDialog; @@ -48,6 +50,9 @@ public final String[] LOCATION_PERMISSIONS = new String []{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION}; public final String[] CAMERA_PERMISSIONS = new String[]{ FILE_PERMISSIONS[0],FILE_PERMISSIONS[1], Manifest.permission.CAMERA}; public final String[] CAMERA_RECORD_PERMISSIONS = new String[]{ FILE_PERMISSIONS[0],FILE_PERMISSIONS[1], Manifest.permission.CAMERA,Manifest.permission.RECORD_AUDIO}; + + public static final String PARAMS_TITLE = "title"; + public static final String PARAMS_URL = "url"; public static final int RESULT_LOGIN = 100,RESULT_LOGIN_RECREATE = 103,RESULT_BIND = 101,RESULT_SENDEDFILES = 105,RESULT_DISSCONNECT = 104, RESULT_UPDATEUSER = 115,RESULT_LOGOUT = 113, REQUEST_CODE_ACTIVITY = 333; @@ -366,4 +371,128 @@ return false; } + + public boolean getBooleanUserPrefrence(String key){ + return PreferencesUtils.getBoolean(this,key,false,PreferencesUtils.USER); + } + + public boolean getBooleanProjectPrefrence(String key){ + return PreferencesUtils.getBoolean(this,key,false,PreferencesUtils.PROJECT); + } + + public String getStringUserPrefrence(String key){ + return PreferencesUtils.getString(this,key,"",PreferencesUtils.USER); + } + + public String getStringProjectPrefrence(String key){ + return PreferencesUtils.getString(this,key,"",PreferencesUtils.PROJECT); + } + + public Integer getIntProjectPrefrence(String key){ + return PreferencesUtils.getInt(this,key,0,PreferencesUtils.PROJECT); + } + + public Long getLongProjectPrefrence(String key){ + return PreferencesUtils.getLong(this,key,0,PreferencesUtils.PROJECT); + } + + public float getFloatProjectPrefrence(String key){ + return PreferencesUtils.getFloat(this,key,0,PreferencesUtils.PROJECT); + } + + public Set getStringSetProjectPrefrence(String key){ + return PreferencesUtils.getStringSet(this,key,PreferencesUtils.PROJECT); + } + + public Integer getIntUserPrefrence(String key){ + return PreferencesUtils.getInt(this,key,0,PreferencesUtils.USER); + } + + public Long getLongUserPrefrence(String key){ + return PreferencesUtils.getLong(this,key,0,PreferencesUtils.USER); + } + + public float getFloatUserPrefrence(String key){ + return PreferencesUtils.getFloat(this,key,0,PreferencesUtils.USER); + } + + public Set getStringSetUserPrefrence(String key){ + return PreferencesUtils.getStringSet(this,key,PreferencesUtils.USER); + } + + + public void putBooleanUserPrefrence(String key ,Boolean value){ + PreferencesUtils.putBoolean(this,key,value,PreferencesUtils.USER); + } + + public void putBooleanProjectPrefrence(String key,Boolean value){ + PreferencesUtils.putBoolean(this,key,value,PreferencesUtils.PROJECT); + } + + public void putStringUserPrefrence(String key,String value){ + PreferencesUtils.putString(this,key,value,PreferencesUtils.USER); + } + + public void putStringProjectPrefrence(String key,String value){ + PreferencesUtils.putString(this,key,value,PreferencesUtils.PROJECT); + } + + public void putIntProjectPrefrence(String key,int value){ + PreferencesUtils.putInt(this,key,value,PreferencesUtils.PROJECT); + } + + public void putLongProjectPrefrence(String key,long value){ + PreferencesUtils.putLong(this,key,value,PreferencesUtils.PROJECT); + } + + public void putFloatProjectPrefrence(String key,float value){ + PreferencesUtils.putFloat(this,key,value,PreferencesUtils.PROJECT); + } + + public void putStringSetProjectPrefrence(String key, Set value){ + PreferencesUtils.putStringSet(this,key,value,PreferencesUtils.PROJECT); + } + + public void putIntUserPrefrence(String key,int value){ + PreferencesUtils.putInt(this,key,value,PreferencesUtils.USER); + } + + public void putLongUserPrefrence(String key,long value){ + PreferencesUtils.putLong(this,key,value,PreferencesUtils.USER); + } + + public void putFloatUserPrefrence(String key,float value){ + PreferencesUtils.putFloat(this,key,value,PreferencesUtils.USER); + } + + public void putStringSetUserPrefrence(String key, Set value){ + PreferencesUtils.putStringSet(this,key,value,PreferencesUtils.USER); + } + + + public void removeUserKey(String key){ + PreferencesUtils.removeKey(this,key,PreferencesUtils.USER); + } + + public void removeProjectKey(String key){ + PreferencesUtils.removeKey(this,key,PreferencesUtils.PROJECT); + } + + public void removeUserValue(String Value){ + PreferencesUtils.removeValue(this,Value,PreferencesUtils.USER); + } + + public void removeProjectValue(String Value){ + PreferencesUtils.removeValue(this,Value,PreferencesUtils.PROJECT); + } + + + public void clearProjectData(){ + PreferencesUtils.clearData(this,PreferencesUtils.PROJECT); + } + public void clearUserData(){ + PreferencesUtils.clearData(this,PreferencesUtils.USER); + } + + } diff --git a/app/src/main/java/com/runt/open/mvvm/config/Configuration.java b/app/src/main/java/com/runt/open/mvvm/config/Configuration.java new file mode 100644 index 0000000..e865ba8 --- /dev/null +++ b/app/src/main/java/com/runt/open/mvvm/config/Configuration.java @@ -0,0 +1,16 @@ +package com.runt.open.mvvm.config; + +/** + * My father is Object, ites purpose of + * + * @purpose Created by Runt (qingingrunt2010@qq.com) on 2022/1/29. + */ +public class Configuration { + + public final static String KEY_CODE= "code"; + public static final String KEY_TOKEN = "token"; + public static final String KEY_USERNAME = "username"; + public static final String KEY_PHONE = "phone"; + public static final String KEY_USERPASS = "userpass"; + public final static String IS_LOGIN= "is_login"; +} diff --git a/app/src/main/java/com/runt/open/mvvm/data/BaseApiResult.java b/app/src/main/java/com/runt/open/mvvm/data/BaseApiResult.java index 9b758bf..8ddd410 100644 --- a/app/src/main/java/com/runt/open/mvvm/data/BaseApiResult.java +++ b/app/src/main/java/com/runt/open/mvvm/data/BaseApiResult.java @@ -6,6 +6,7 @@ * Created by Administrator on 2021/10/28 0028. */ public class BaseApiResult<D extends Object> implements Serializable { + public String msg; public int code = 200; public D data; diff --git a/app/src/main/java/com/runt/open/mvvm/data/Results.java b/app/src/main/java/com/runt/open/mvvm/data/Results.java new file mode 100644 index 0000000..fc55568 --- /dev/null +++ b/app/src/main/java/com/runt/open/mvvm/data/Results.java @@ -0,0 +1,16 @@ +package com.runt.open.mvvm.data; + +import com.runt.open.mvvm.ui.login.UserBean; + +/** + * My father is Object, ites purpose of + * + * @purpose Created by Runt (qingingrunt2010@qq.com) on 2022/1/29. + */ +public class Results { + + public static class LoggedInUser extends BaseApiResult<UserBean> { } + + public static class StringApiResult extends BaseApiResult<String>{ } + +} diff --git a/app/src/main/java/com/runt/open/mvvm/listener/CrashHandler.java b/app/src/main/java/com/runt/open/mvvm/listener/CrashHandler.java new file mode 100644 index 0000000..a837be7 --- /dev/null +++ b/app/src/main/java/com/runt/open/mvvm/listener/CrashHandler.java @@ -0,0 +1,260 @@ +package com.runt.open.mvvm.listener; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Environment; +import android.os.Looper; +import android.util.Log; +import android.widget.Toast; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Field; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * My father is Object, ites purpose of 崩溃监听 + * + * @purpose Created by Runt (qingingrunt2010@qq.com) on 2021-4-13. + */ + +public class CrashHandler implements Thread.UncaughtExceptionHandler { + + public static final String TAG = "CrashHandler"; + + //系统默认的UncaughtException处理类 + private Thread.UncaughtExceptionHandler mDefaultHandler; + + CrashListener crashListener; + + //CrashHandler实例 + private static CrashHandler instance; + //程序的Context对象 + private Context mContext; + //用来存储设备信息和异常信息 + private Map<String, String> infos = new HashMap<String, String>(); + + //用于格式化日期,作为日志文件名的一部分 + private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + /** 保证只有一个CrashHandler实例 */ + private CrashHandler() {} + + /** 获取CrashHandler实例 ,单例模式 */ + public static CrashHandler getInstance() { + Log.i(TAG, "getInstance"); + if(instance == null) + instance = new CrashHandler(); + return instance; + } + + /** + * 初始化 + */ + public void init(Context context) { + Log.i(TAG, "init context:"+context); + mContext = context; + //获取系统默认的UncaughtException处理器 + mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); + //设置该CrashHandler为程序的默认处理器 + Thread.setDefaultUncaughtExceptionHandler(this); + } + + /** + * 初始化 + */ + public void init(Context context,CrashListener crashListener) { + Log.i(TAG, "init context:"+context); + mContext = context; + this.crashListener = crashListener; + //设置该CrashHandler为程序的默认处理器 + Thread.setDefaultUncaughtExceptionHandler(this); + } + + /** + * 当UncaughtException发生时会转入该函数来处理 + */ + @Override + public void uncaughtException(Thread thread, Throwable ex) { + Log.i(TAG, "uncaughtException Throwable:"+ex); + if (!handleException(ex) && mDefaultHandler != null) { + //如果用户没有处理则让系统默认的异常处理器来处理 + mDefaultHandler.uncaughtException(thread, ex); + } else if(crashListener != null){ + crashListener.onCrash(); + } else { + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + Log.e(TAG, "error : ", e); + } + //退出程序 + android.os.Process.killProcess(android.os.Process.myPid()); + System.exit(1); + } + } + + /** + * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. + * + * @param ex + * @return true:如果处理了该异常信息;否则返回false. + */ + private boolean handleException(Throwable ex) { + Log.i(TAG, "handleException Throwable:"+ex); + if (ex == null) { + return false; + } + //收集设备参数信息 + collectDeviceInfo(mContext); + + //使用Toast来显示异常信息 + new Thread() { + @Override + public void run() { + Looper.prepare(); + Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出.", Toast.LENGTH_SHORT).show(); + Looper.loop(); + } + }.start(); + //保存日志文件 + saveCatchInfo2File(ex); + return true; + } + + /** + * 收集设备参数信息 + * @param ctx + */ + public void collectDeviceInfo(Context ctx) { + Log.i(TAG, "collectDeviceInfo Context:"+ctx); + try { + PackageManager pm = ctx.getPackageManager(); + PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES); + if (pi != null) { + String versionName = pi.versionName == null ? "null" : pi.versionName; + String versionCode = pi.versionCode + ""; + infos.put("versionName", versionName); + infos.put("versionCode", versionCode); + } + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "an error occured when collect package info", e); + } + Field[] fields = Build.class.getDeclaredFields(); + for (Field field : fields) { + try { + field.setAccessible(true); + infos.put(field.getName(), field.get(null).toString()); + Log.d(TAG, field.getName() + " : " + field.get(null)); + } catch (Exception e) { + Log.e(TAG, "an error occured when collect crash info", e); + } + } + } + + /** + * 保存错误信息到文件中 + * + * @param ex + * @return 返回文件名称,便于将文件传送到服务器 + */ + private String saveCatchInfo2File(Throwable ex) { + ex.printStackTrace(); + Log.i(TAG, "saveCatchInfo2File Throwable:"+ex); + + StringBuffer sb = new StringBuffer(); + for (Map.Entry<String, String> entry : infos.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + sb.append(key + "=" + value + "\n"); + } + + Writer writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + ex.printStackTrace(printWriter); + Throwable cause = ex.getCause(); + while (cause != null) { + cause.printStackTrace(printWriter); + cause = cause.getCause(); + } + printWriter.close(); + String result = writer.toString(); + sb.append(result); + try { + long timestamp = System.currentTimeMillis(); + String time = formatter.format(new Date()); + String fileName = "crash-" + time + "-" + timestamp + ".log"; + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + String path = "/mnt/sdcard/crash/"; + File dir = new File(path); + if (!dir.exists()) { + dir.mkdirs(); + } + FileOutputStream fos = new FileOutputStream(path + fileName); + fos.write(sb.toString().getBytes()); + //发送给开发人员 + sendCrashLog2PM(path+fileName); + fos.close(); + } + return fileName; + } catch (Exception e) { + Log.e(TAG, "an error occured while writing file...", e); + } + return null; + } + + /** + * 将捕获的导致崩溃的错误信息发送给开发人员 + * + * 目前只将log日志保存在sdcard 和输出到LogCat中,并未发送给后台。 + */ + private void sendCrashLog2PM(String fileName){ + Log.i(TAG, "asendCrashLog2PM fileName:"+fileName); + if(!new File(fileName).exists()){ + Toast.makeText(mContext, "日志文件不存在!", Toast.LENGTH_SHORT).show(); + return; + } + FileInputStream fis = null; + BufferedReader reader = null; + String s = null; + try { + fis = new FileInputStream(fileName); + reader = new BufferedReader(new InputStreamReader(fis, "GBK")); + while(true){ + s = reader.readLine(); + if(s == null) break; + //由于目前尚未确定以何种方式发送,所以先打出log日志。 + //Log.i("info", s.toString()); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + }finally{ // 关闭流 + try { + reader.close(); + fis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public static interface CrashListener{ + void onCrash(); + } +} diff --git a/app/src/main/java/com/runt/open/mvvm/retrofit/Interceptor/HttpLoggingInterceptor.java b/app/src/main/java/com/runt/open/mvvm/retrofit/Interceptor/HttpLoggingInterceptor.java index 221f070..6d271e4 100644 --- a/app/src/main/java/com/runt/open/mvvm/retrofit/Interceptor/HttpLoggingInterceptor.java +++ b/app/src/main/java/com/runt/open/mvvm/retrofit/Interceptor/HttpLoggingInterceptor.java @@ -51,7 +51,7 @@ int position = logArrays.size() +2; Response response; try { - //request = encryptRequest(request);//加密 + request = encryptRequest(request);//加密 response = chain.proceed(request); logArrays.addAll(getResponseLog(response)); Log.d(TAG,"hashcode:"+hashCode); diff --git a/app/src/main/java/com/runt/open/mvvm/retrofit/api/LoginApiCenter.java b/app/src/main/java/com/runt/open/mvvm/retrofit/api/LoginApiCenter.java index 7e03dc2..c41d848 100644 --- a/app/src/main/java/com/runt/open/mvvm/retrofit/api/LoginApiCenter.java +++ b/app/src/main/java/com/runt/open/mvvm/retrofit/api/LoginApiCenter.java @@ -1,24 +1,65 @@ package com.runt.open.mvvm.retrofit.api; -import com.runt.open.mvvm.ui.login.LoggedInUser; +import com.runt.open.mvvm.config.Configuration; +import com.runt.open.mvvm.data.Results; import io.reactivex.Observable; import retrofit2.http.Field; import retrofit2.http.FormUrlEncoded; import retrofit2.http.POST; +import retrofit2.http.Url; /** * Created by Administrator on 2021/11/15 0015. */ public interface LoginApiCenter { + /** + * 密码登录 + * @param phone + * @param pass + * @return + */ @FormUrlEncoded @POST("login") - Observable<LoggedInUser> login(@Field("phone") String phone,@Field("pass") String pass); + Observable<Results.LoggedInUser> login(@Field(Configuration.KEY_PHONE) String phone, @Field("pass") String pass); + + /** + * 验证码登录 + * @param phone + * @param code + * @return + */ + @FormUrlEncoded + @POST("loginCode") + Observable<Results.LoggedInUser> loginByCode(@Field(Configuration.KEY_PHONE) String phone, @Field(Configuration.KEY_CODE) String code); @FormUrlEncoded - @POST("login") - Observable<LoggedInUser> loginByCode(@Field("phone") String phone,@Field("code") String code); + @POST + Observable<Results.StringApiResult> getVerifyCode(@Url String url, @Field(Configuration.KEY_PHONE) String phone, @Field(Configuration.KEY_CODE) String code, @Field("time") String time); + + /** + * 重置密码 + * @param phone + * @param sms + * @param newPass + * @return + */ + @FormUrlEncoded + @POST("verifySMSReSetLoginPwd") + Observable<Results.StringApiResult> resetLoginPwd(@Field(Configuration.KEY_PHONE) String phone,@Field("sms") String sms, @Field("pass") String newPass); + + + /** + * 注册 + * @param phone + * @param sms + * @param pass + * @return + */ + @FormUrlEncoded + @POST("registerCustomer") + Observable<Results.StringApiResult> register(@Field(Configuration.KEY_USERNAME) String phone,@Field("sms") String sms, @Field("pass") String pass); } diff --git a/app/src/main/java/com/runt/open/mvvm/retrofit/observable/HttpObserver.java b/app/src/main/java/com/runt/open/mvvm/retrofit/observable/HttpObserver.java index 7024299..3a4ac2c 100644 --- a/app/src/main/java/com/runt/open/mvvm/retrofit/observable/HttpObserver.java +++ b/app/src/main/java/com/runt/open/mvvm/retrofit/observable/HttpObserver.java @@ -1,5 +1,6 @@ package com.runt.open.mvvm.retrofit.observable; +import android.accounts.NetworkErrorException; import android.util.Log; import androidx.annotation.NonNull; @@ -41,14 +42,16 @@ Log.i("subscribe","onError"); try { - Log.e(TAG,this.getClass().getSimpleName()+" "+throwable.getMessage()); + Log.e(TAG,this.getClass().getSimpleName()+" mes:"+throwable.getMessage()); Class<M> entityClass = (Class<M>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; M t = entityClass.newInstance();//实例化一个泛型 t.code = 410; if( throwable instanceof SocketTimeoutException){ t.msg = "服务请求超时,请稍候再试";//设置错误信息 - }else{ + }else if( throwable instanceof NetworkErrorException){ t.msg = "网络连接不畅,请检查您的网络设置";//设置错误信息 + }else{ + t.msg = throwable.getMessage();//设置错误信息 } resultLive.setValue(t); } catch (ClassCastException e) { diff --git a/app/src/main/java/com/runt/open/mvvm/ui/login/CodeTimer.java b/app/src/main/java/com/runt/open/mvvm/ui/login/CodeTimer.java new file mode 100644 index 0000000..764b79a --- /dev/null +++ b/app/src/main/java/com/runt/open/mvvm/ui/login/CodeTimer.java @@ -0,0 +1,40 @@ +package com.runt.open.mvvm.ui.login; + +import android.os.CountDownTimer; +import android.widget.TextView; + +import com.runt.open.mvvm.R; + +/** + * My father is Object, ites purpose of + * + * @purpose Created by Runt (qingingrunt2010@qq.com) on 2020-2-23. + */ +public class CodeTimer extends CountDownTimer { + + TextView txtGetCode; + + public CodeTimer(long millisInFuture, long countDownInterval, TextView txtGetCode) { + super(millisInFuture, countDownInterval); + this.txtGetCode = txtGetCode; + } + + public void startUp(){ + txtGetCode.setEnabled(false); + txtGetCode.setTextColor(txtGetCode.getContext().getResources().getColor(R.color.txt_enable)); + start(); + } + + @Override + public void onTick(long l) { + txtGetCode.setText(String.format("(%s)", l/1000)); + } + + @Override + public void onFinish() { + txtGetCode.setEnabled(true); + txtGetCode.setTextColor(txtGetCode.getContext().getResources().getColor(R.color.link)); + txtGetCode.setText(txtGetCode.getContext().getResources().getString(R.string.get_verify_code)); + } + +} diff --git a/app/src/main/java/com/runt/open/mvvm/ui/login/LoggedInUser.java b/app/src/main/java/com/runt/open/mvvm/ui/login/LoggedInUser.java deleted file mode 100644 index 8a5ad19..0000000 --- a/app/src/main/java/com/runt/open/mvvm/ui/login/LoggedInUser.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.runt.open.mvvm.ui.login; - -import com.runt.open.mvvm.data.BaseApiResult; - -/** - * Created by Administrator on 2021/11/15 0015. - */ -public class LoggedInUser extends BaseApiResult<UserBean> { - -} diff --git a/app/src/main/java/com/runt/open/mvvm/ui/login/LoginViewModel.java b/app/src/main/java/com/runt/open/mvvm/ui/login/LoginViewModel.java index 866420b..eda4bd3 100644 --- a/app/src/main/java/com/runt/open/mvvm/ui/login/LoginViewModel.java +++ b/app/src/main/java/com/runt/open/mvvm/ui/login/LoginViewModel.java @@ -3,9 +3,14 @@ import androidx.lifecycle.MutableLiveData; import com.runt.open.mvvm.base.model.BaseViewModel; +import com.runt.open.mvvm.data.Results; import com.runt.open.mvvm.retrofit.api.LoginApiCenter; import com.runt.open.mvvm.retrofit.observable.HttpObserver; import com.runt.open.mvvm.retrofit.utils.RetrofitUtils; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; import io.reactivex.Observable; @@ -14,17 +19,132 @@ */ public class LoginViewModel extends BaseViewModel { - MutableLiveData<LoggedInUser> loginResult = new MutableLiveData<>(); + LoginApiCenter loginApi; - public MutableLiveData<LoggedInUser> getLoginResult() { + public LoginViewModel() { + loginApi = RetrofitUtils.getInstance().getRetrofit(LoginApiCenter.class); + } + + MutableLiveData<Results.LoggedInUser> loginResult = new MutableLiveData<>(); + MutableLiveData<Results.StringApiResult> verifyResult = new MutableLiveData<>(); + MutableLiveData<Results.StringApiResult> resetResult = new MutableLiveData<>(); + MutableLiveData<Results.StringApiResult> registerResult = new MutableLiveData<>(); + + public MutableLiveData<Results.LoggedInUser> getLoginResult() { return loginResult; } - public void login(String username, String password) { - // can be launched in a separate asynchronous job - final Observable<LoggedInUser> userObservable = RetrofitUtils.getInstance().getRetrofit(LoginApiCenter.class).login(username, password); - httpObserverOn(userObservable,new HttpObserver<LoggedInUser>(loginResult){}); + public MutableLiveData<Results.StringApiResult> getVerifyResult() { + return verifyResult; } + /** + * 密码登录 + * @param username + * @param password + */ + public void login(String username, String password) { + // can be launched in a separate asynchronous job + final Observable<Results.LoggedInUser> userObservable = loginApi.login(username, password); + httpObserverOnLoading(userObservable,new HttpObserver<Results.LoggedInUser>(loginResult){}); + } + /** + * 验证码登录 + * @param phone + * @param code + */ + public void loginByCode(String phone,String code){ + httpObserverOnLoading(loginApi.loginByCode(phone,code), + new HttpObserver<Results.LoggedInUser>(loginResult){}); + } + + /** + * 重置密码 + * @param phone + * @param sms + * @param pass + */ + public void resetPwd(String phone,String sms,String pass){ + httpObserverOnLoading(loginApi.resetLoginPwd(phone, sms, pass), new HttpObserver<Results.StringApiResult>(resetResult) {}); + } + + /** + * 注册 + * @param phone + * @param sms + * @param pass + */ + public void register(String phone,String sms,String pass){ + httpObserverOnLoading(loginApi.register(phone, sms, pass), new HttpObserver<Results.StringApiResult>(resetResult) {}); + } + + /** + * 注册密码 + * @param phone + */ + public void getRegisterSMS(String phone){ + getVerifyCode("getRegisterSMS",phone); + } + + /** + * 忘记密码 + * @param phone + */ + public void getForgetSMS(String phone){ + getVerifyCode("getForgetSMS",phone); + } + + /** + * 登录验证码 + * @param phone + */ + public void getLoginSMS(String phone){ + getVerifyCode("getLoginSMS",phone); + } + + /** + * 获取验证码 + * @param url 验证码地址 + * @param phone 手机号 + */ + public void getVerifyCode(String url,String phone){ + String time = new Date().getTime()+""; + httpObserverOnLoading(loginApi.getVerifyCode(url, phone, randomString(phone, time), time), new HttpObserver<Results.StringApiResult>(verifyResult){}); + } + + /** + * 随机字符串 + * @param phone + * @param time + * @return + */ + private String randomString(String phone,String time){ + int p = (int) Math.round(phone.length()/6.0); + int t = time.length()/6; + List<String> list = new ArrayList<String>(); + for(int i = 0 ; i < 6 ; i ++){ + String str = ""; + if(i*p>phone.length()){ + str = phone.substring((i-1)*p); + }else if((i+1)*p>phone.length()){ + str = phone.substring(i*p); + }else{ + str = phone.substring(i*p,(i+1)*p); + } + String num = ((Integer.parseInt(str)*Long.parseLong(time))+"") ; + list.add(num); + } + //return sb.toString(); + return plusSingle2(list); + } + + private String plusSingle2(List<String> list){ + StringBuilder sb = new StringBuilder(); + for(int i = 0 ; i < list.size() ; i ++){ + sb.append(list.get(i).substring(list.get(i).length()-2<0?0:list.get(i).length()-2)); + } + return sb.toString(); + + } } diff --git a/app/src/main/java/com/runt/open/mvvm/ui/login/RegisterLoginActivity.java b/app/src/main/java/com/runt/open/mvvm/ui/login/RegisterLoginActivity.java new file mode 100644 index 0000000..ab84fd8 --- /dev/null +++ b/app/src/main/java/com/runt/open/mvvm/ui/login/RegisterLoginActivity.java @@ -0,0 +1,287 @@ +package com.runt.open.mvvm.ui.login; + +import android.content.Intent; +import android.view.View; +import android.widget.EditText; + +import com.google.gson.Gson; +import com.runt.open.mvvm.R; +import com.runt.open.mvvm.base.activities.BaseActivity; +import com.runt.open.mvvm.config.Configuration; +import com.runt.open.mvvm.databinding.ActivityLoginBinding; +import com.runt.open.mvvm.listener.CustomClickListener; +import com.runt.open.mvvm.ui.web.WebViewActivity; +import com.runt.open.mvvm.util.AlgorithmUtils; +import com.runt.open.mvvm.util.MyLog; +import com.runt.open.mvvm.util.PhoneUtil; + +import java.util.Date; + +/** + * My father is Object, ites purpose of + * + * @purpose Created by Runt (qingingrunt2010@qq.com) on 2022/1/29. + */ +public class RegisterLoginActivity extends BaseActivity<ActivityLoginBinding,LoginViewModel> { + final String VERIFY_CODE = "verify_code"; + final String TAG = "RegisterLoginActivity"; + int type = 0;//0 登录,1忘记密码,2注册,-1短信登录 + + @Override + public void initViews() { + binding.txtGetVerify.setOnClickListener(onclick); + binding.txtForgot.setOnClickListener(onclick); + binding.txtLogin.setOnClickListener(onclick); + binding.txtRegister.setOnClickListener(onclick); + binding.txtPrivacy.setOnClickListener(onclick); + long getTime = getLongProjectPrefrence(VERIFY_CODE); + long cha = new Date().getTime() - getTime; + if(cha <1000*60){ + CodeTimer codeTimer = new CodeTimer(cha, 1000, binding.txtGetVerify); + codeTimer.startUp(); + } + changeView(); + binding.editPhone.setText(getStringProjectPrefrence(Configuration.KEY_USERNAME)); + viewModel.getVerifyResult().observe(this, stringApiResult -> { + if(stringApiResult.code == 200){ + + }else{ + showToast(stringApiResult.msg); + } + }); + viewModel.getLoginResult().observe(this,loggedInUser -> { + if(loggedInUser.code == 200){ + putBooleanProjectPrefrence(Configuration.IS_LOGIN,true); + putStringProjectPrefrence(Configuration.KEY_USERNAME,binding.editPhone.getText().toString()); + + UserBean user = new Gson().fromJson(new Gson().toJson(loggedInUser.data) ,UserBean.class); + UserBean.setUser(user); + putStringProjectPrefrence(Configuration.KEY_TOKEN, user.getToken()); + MyLog.i("registerlogin",user.toString()); + showToast(R.string.login_success); + setResult(RESULT_CODE_SUCESS); + finish(); + }else{ + showToast(loggedInUser.msg); + } + }); + } + + CustomClickListener onclick = new CustomClickListener() { + @Override + protected void onSingleClick(View view) { + switch (view.getId()){ + case R.id.button: + submit(); + break; + case R.id.txt_get_verify: + + String phone = binding.editPhone.getText().toString(); + if(!verifyPhone(phone)){//验证手机 + return; + } + if(type==2){//获取注册验证码 + viewModel.getRegisterSMS(phone); + }else if(type ==1){ + viewModel.getForgetSMS( phone); + }else if(type == -1){ + viewModel.getLoginSMS( phone); + } + break; + case R.id.txt_privacy: + startActivity(new Intent(mContext, WebViewActivity.class).putExtra(PARAMS_URL,"http://www.hefan.space/privacyPolicy.html").putExtra(PARAMS_TITLE,"隐私政策")); + break; + case R.id.txt_register: + type = 2; + changeView(); + break; + case R.id.txt_forgot: + type = 1; + changeView(); + break; + case R.id.txt_login: + if(type != 0 ){ + type = 0; + }else { + type = -1; + } + changeView(); + break; + } + } + }; + + + /** + * 修改页面布局 + */ + private void changeView(){ + binding.button.setEnabled(true); + binding.txtRegister.setVisibility(View.VISIBLE); + binding.checkbox.setVisibility(View.GONE); + binding.txtPrivacy.setVisibility(View.GONE); + switch (type){ + case -1://短信登录 + binding.editVerifyCode.setVisibility(View.VISIBLE); + binding.txtGetVerify.setVisibility(View.VISIBLE); + binding.editPass.setVisibility(View.GONE); + binding.editPassRepeat.setVisibility(View.GONE); + binding.txtForgot.setVisibility(View.VISIBLE); + binding.txtLogin.setText(getResources().getString(R.string.login)); + binding.button.setText(getResources().getString(R.string.login)); + binding.checkbox.setVisibility(View.VISIBLE); + binding.txtPrivacy.setVisibility(View.VISIBLE); + break; + case 0://登录 + binding.editVerifyCode.setVisibility(View.GONE); + binding.txtGetVerify.setVisibility(View.GONE); + binding.editPass.setVisibility(View.VISIBLE); + binding.editPassRepeat.setVisibility(View.GONE); + binding.txtForgot.setVisibility(View.VISIBLE); + binding.txtLogin.setText(getResources().getString(R.string.msg_login)); + binding.button.setText(getResources().getString(R.string.login)); + break; + case 1://忘记密码 + binding.txtForgot.setVisibility(View.INVISIBLE); + binding.editVerifyCode.setVisibility(View.VISIBLE); + binding.txtGetVerify.setVisibility(View.VISIBLE); + binding.editPass.setVisibility(View.VISIBLE); + binding.editPassRepeat.setVisibility(View.VISIBLE); + binding.txtLogin.setText(getResources().getString(R.string.login)); + binding.button.setText(getResources().getString(R.string.str_confirm)); + break; + case 2://注册 + binding.checkbox.setVisibility(View.VISIBLE); + binding.txtPrivacy.setVisibility(View.VISIBLE); + binding.txtRegister.setVisibility(View.INVISIBLE); + binding.editVerifyCode.setVisibility(View.VISIBLE); + binding.txtGetVerify.setVisibility(View.VISIBLE); + binding.editPass.setVisibility(View.VISIBLE); + binding.editPassRepeat.setVisibility(View.VISIBLE); + binding.txtLogin.setText(getResources().getString(R.string.login)); + binding.button.setText(getResources().getString(R.string.register)); + break; + } + clearText(binding.editPassRepeat,binding.editPass,binding.editPhone,binding.editVerifyCode); + } + + private void clearText(EditText... editTextes){ + for(EditText editText :editTextes) { + editText.setText(""); + } + } + + + + + /** + * 提交数据 + */ + public void submit(){ + String phone = binding.editPhone.getText().toString(); + String pass = binding.editPass .getText().toString(); + String veriCode = binding.editVerifyCode.getText().toString(); + String invite = binding.editPassRepeat.getText().toString(); + if(!verifyPhone(phone)){//验证手机 + return; + } + switch (type){ + case -1://短信登录 + if(veriCode.length() == 0){//验证码 + showToast(R.string.input_verify_code); + return; + } + if(!binding.checkbox.isChecked()){ + showToast("请阅读并勾选《隐私条款》"); + return; + } + viewModel.loginByCode(phone,veriCode); + break; + case 0: + if(!verifyPassWord(pass)){//验证密码 + return; + } + viewModel.login(phone,pass); + break; + case 1: + if(!verifyPassWord(pass)){//验证密码 + return; + } + if(veriCode.length() == 0){//验证码 + showToast(R.string.input_verify_code); + return; + } + + //新密码 + if(invite.length() == 0){ + showToast(R.string.input_pass); + return; + } else if(!invite.equals(pass)){ + showToast(R.string.str_new_verify_failed); + return; + } + viewModel.resetPwd(phone,veriCode,pass); + break; + case 2://注册 + if(!verifyPassWord(pass)){//验证密码 + return; + } + if(veriCode.length() == 0){//验证码 + showToast(R.string.input_verify_code); + return; + } + if(!binding.checkbox.isChecked()){ + showToast("请阅读并勾选《隐私条款》"); + return; + } + viewModel.register(phone,veriCode,pass); + break; + } + } + + /** + * 验证密码 + * @param pass + * @return + */ + public boolean verifyPassWord(String pass){ + + if(pass.length() == 0){ + showToast(R.string.input_pass); + return false; + } else if(!verifyPass(pass)){ + showToast(R.string.str_pass_format_failed); + return false; + } + return true; + } + + + /** + * 验证手机号 + * @param phone + * @return + */ + public boolean verifyPhone(String phone ){ + + if(phone.length() == 0){ + showToast(R.string.input_phone); + return false; + }else if(phone.length()<5 || !PhoneUtil.isMobileNO(phone)){ + showToast(R.string.str_phone_format_failed); + return false; + } + return true; + + } + + + /** + * 验证密码 + * @param pass + * @return + */ + public boolean verifyPass(String pass){ + return AlgorithmUtils.pwdLevel(pass)>1 && pass.length()>=6 && pass.length() <=12; + } +} diff --git a/app/src/main/java/com/runt/open/mvvm/ui/web/WebViewActivity.java b/app/src/main/java/com/runt/open/mvvm/ui/web/WebViewActivity.java new file mode 100644 index 0000000..d41521c --- /dev/null +++ b/app/src/main/java/com/runt/open/mvvm/ui/web/WebViewActivity.java @@ -0,0 +1,159 @@ +package com.runt.open.mvvm.ui.web; + +import android.os.Handler; +import android.view.View; +import android.view.ViewTreeObserver; +import android.view.animation.LayoutAnimationController; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.Toast; + +import com.runt.open.mvvm.base.activities.BaseActivity; +import com.runt.open.mvvm.base.model.BaseViewModel; +import com.runt.open.mvvm.databinding.ActivityWebBinding; +import com.runt.open.mvvm.util.MyAnimations; +import com.runt.open.mvvm.util.MyLog; + +/** + * My father is Object, ites purpose of + * + * @purpose Created by Runt (qingingrunt2010@qq.com) on 2020-9-16. + */ +public class WebViewActivity extends BaseActivity<ActivityWebBinding, BaseViewModel> { + + private String url; + private int linProgressWidth; + + @Override + public void initViews() { + url = getIntent().getSerializableExtra(PARAMS_URL)+""; + setTitle(getIntent().getSerializableExtra(PARAMS_TITLE)+""); + initCompent(); + } + + + int count = 100; + int index = 100; + private void initCompent(){ + binding.browser.getSettings().setJavaScriptEnabled(true); + binding.browser.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN); + //跳转至拼接好的地址 + //mBaseHandler.sendMessage(msg);//http://192.168.5.156:8080/MyFinance/gd16/1.html + binding.browser.loadUrl(url); + binding.browser.setWebViewClient(new myWebViewClient()); + binding.browser.setWebChromeClient(new WebChromeClient(){ + + @Override + public void onProgressChanged(WebView view,final int newProgress) { + MyLog.i("onProgressChanged","--newProgress:--"+newProgress); + MyLog.i("onProgressChanged","--binding.viewProgressbar:--"+binding.viewProgressbar.getWidth()); + final LayoutAnimationController.AnimationParameters animation= new LayoutAnimationController.AnimationParameters(); //得到一个LayoutAnimationController对象; + animation.index =index++ ; + animation.count = count++ ; + if (newProgress == 100) { + MyAnimations.hideAnimaInSitu(binding.linProgressbar); + MyAnimations.makeViewMove(binding.viewProgressbar.getTranslationX(),0,0,0,binding.viewProgressbar); + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + binding.linProgressbar.setVisibility(View.GONE); + } + },MyAnimations.ANIMA_TIME); + } else { + + if (View.VISIBLE != binding.linProgressbar.getVisibility()) { + MyAnimations.showAnimaInSitu(binding.linProgressbar); + if(linProgressWidth==0){ + final ViewTreeObserver vto = binding.linProgressbar.getViewTreeObserver(); + vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + public boolean onPreDraw() { + linProgressWidth = binding.linProgressbar.getMeasuredWidth(); + binding.viewProgressbar.setTranslationX(0-linProgressWidth); + binding.linProgressbar.getViewTreeObserver().removeOnPreDrawListener(this); + return true; + } + }); + }else{ + binding.viewProgressbar.setTranslationX(0-linProgressWidth); + } + + } + if(linProgressWidth!=0){ + MyAnimations.makeViewMove(binding.viewProgressbar.getTranslationX(),0-linProgressWidth+linProgressWidth/100*newProgress,0,0,binding.viewProgressbar,MyAnimations.ANIMA_TIME*3); + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + MyAnimations.makeViewMove(binding.viewProgressbar.getTranslationX(),binding.viewProgressbar.getTranslationX()+300,0,0,binding.viewProgressbar,MyAnimations.ANIMA_TIME*10); + } + },MyAnimations.ANIMA_TIME*3); + } + + } + super.onProgressChanged(view, newProgress); + } + + }); + + binding.browser.getSettings().setSavePassword(false); + //Toast.makeText(mContext,"进入浏览器",Toast.LENGTH_SHORT).show(); + String Scale = String.valueOf(binding.browser.getScale()); + MyLog.i("Runt","--Scale:--"+Scale); + int screenDensity=getResources().getDisplayMetrics().densityDpi; + MyLog.i("Runt", "--screenDensity:--"+String.valueOf(screenDensity)); //60-160-240 + } + + + + + private class myWebViewClient extends WebViewClient { + + /** + * 每加载一张图片资源执行一次 + */ + @Override + public void onLoadResource(WebView view, String url) { + // TODO Auto-generated method stub + super.onLoadResource(view, url); + //MyLog.i("WebView", "onLoadResource "+url); + } + + @Override + public void onPageFinished(WebView view, String url) { + hideProgressBar(); + //MyLog.i("WebView", "onPageFinished "+url); + } + + /** + * 获取页面跳转的链接 + */ + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + // TODO Auto-generated method stub + //MyLog.i("UrlLoading", "UrlLoading 正在跳转页面"+url); + view.loadUrl(url); + return true; + } + + @Override + public void onReceivedError(WebView view, int errorCode, + String description, String failingUrl) { + // TODO Auto-generated method stub + super.onReceivedError(view, errorCode, description, failingUrl); + Toast.makeText(mContext, "加载失败,请稍候再试", Toast.LENGTH_SHORT).show(); + hideProgressBar(); + } + } + + private void hideProgressBar(){ + MyAnimations.hideAnimaInSitu(binding.linProgressbar); + MyAnimations.makeViewMove(binding.viewProgressbar.getTranslationX(),0,0,0,binding.viewProgressbar); + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + binding.linProgressbar.setVisibility(View.GONE); + } + },MyAnimations.ANIMA_TIME*2); + } +} diff --git a/app/src/main/java/com/runt/open/mvvm/util/Configuration.java b/app/src/main/java/com/runt/open/mvvm/util/Configuration.java deleted file mode 100644 index c4adb9c..0000000 --- a/app/src/main/java/com/runt/open/mvvm/util/Configuration.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.runt.open.mvvm.util; - -/** - * Created by xanarry on 2016/5/22. - */ -public class Configuration { - - - public static final int REQUEST_CODE_PIC = 303; - - - public final static String MESS_TIP_NET_ERROR = "网络连接不畅,请稍后再试!!!"; - public final static String KEY_MES_CODE= "code"; - public final static String KEY_MES_TIME= "time"; - public final static String KEY_MES_MESSAGE= "msg"; - public final static String KEY_MES_ERROR= "error"; - public final static String KEY_CODE_SUCCESS= "0";//code 0 成功 - public final static int KEY_CODE_INFO= 101;//修改资料 - public final static String KEY_USER = "user"; - public final static String KEY_ADVERT= "advert"; - public final static String KEY_DATA= "data"; - public final static String KEY_FILES= "files"; - public final static String KEY_SCREEN_TYPE = "screen_type";//屏幕类型 - public final static String KEY_SCREEN_FILES= "screen_files";//播放的资源文件列表 - public final static String KEY_NAME= "name"; - public final static String KEY_MARk= "mark"; - public final static String KEY_ORDER= "order"; - public final static String FILENAME_MK = "fileName"; - public final static String FILEPATH = "path"; - public final static String STR_APPLY_DATA = "apply datas"; - public final static String STR_FILE_PLAN_FAILED = "file plan failed"; - public final static String STR_START_FILE_PLAN = "start file plan"; - public final static String STR_FINISHED_FILE_PLAN = "finished plan"; - public final static String FILESIZE_MK = "fileSize"; - - public static final String KEY_EXTRAS = "extras"; - public static final String KEY_USERID = "customerId"; - public static final String KEY_TOKEN = "token"; - public static final String KEY_USERNAME = "username"; - public static final String KEY_PHONE = "phone"; - public static final String KEY_USERPASS = "userpass"; - public static final String MESSAGE_RECEIVED_ACTION = "MESSAGE_RECEIVED_ACTION"; - - public static final String KEY_REGION = "region", - IS_LOGIN = "is_login"; - - -} diff --git a/app/src/main/java/com/runt/open/mvvm/util/MyAnimations.java b/app/src/main/java/com/runt/open/mvvm/util/MyAnimations.java new file mode 100644 index 0000000..b3faaac --- /dev/null +++ b/app/src/main/java/com/runt/open/mvvm/util/MyAnimations.java @@ -0,0 +1,477 @@ +package com.runt.open.mvvm.util; + +import android.animation.Animator; +import android.animation.AnimatorInflater; +import android.animation.ObjectAnimator; +import android.annotation.SuppressLint; +import android.content.Context; +import android.os.Handler; +import android.os.Message; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.view.animation.TranslateAnimation; +import android.widget.RelativeLayout; + +import com.facebook.rebound.SimpleSpringListener; +import com.facebook.rebound.Spring; +import com.facebook.rebound.SpringConfig; +import com.facebook.rebound.SpringSystem; +import com.runt.open.mvvm.R; + +/** + * Created by Administrator on 2017/11/30. + */ +public class MyAnimations { + + public static final int ANIMA_TIME = 300; + public static final float MOVE_SPACE = 1; + public static final float SITU = 0; + + + + /** + * 移动控件 + * @param x x初始位置 + * @param distanceX x移动的距离 + * @param y y初始位置 + * @param distanceY y移动的距离 + * @param view + */ + public static void makeViewMove(float x ,float distanceX , float y ,float distanceY, View view){ + setAnimator("translationY", y, distanceY,view,ANIMA_TIME); + setAnimator("translationX", x, distanceX,view,ANIMA_TIME); + } + /** + * 移动控件 + * @param x x初始位置 + * @param distanceX x移动的距离 + * @param y y初始位置 + * @param distanceY y移动的距离 + * @param view + */ + public static void makeViewMove(float x , float distanceX , float y , float distanceY, View view, int animTime){ + setAnimator("translationY", y, distanceY,view,animTime); + setAnimator("translationX", x, distanceX,view,animTime); + } + + private static void setAnimator(String attribute, float from, float to, View view, int animTime){ + ObjectAnimator.ofFloat(view, attribute, from, to).setDuration(animTime).start(); + } + public static void setLayoutMargin(View view, int left, int top, int right, int bottom) + { + //克隆view的width、height、margin的值生成margin对象 + ViewGroup.MarginLayoutParams margin=new ViewGroup.MarginLayoutParams(view.getLayoutParams()); + //设置新的边距 + margin.setMargins(left, top, right, bottom); + //把新的边距生成layoutParams对象 + RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(margin); + //设制view的新的位置 + view.setLayoutParams(layoutParams); + } + /** + * 原地不动 + * @return + */ + private static TranslateAnimation makeInSitu(){ + TranslateAnimation mAction = new TranslateAnimation(Animation.RELATIVE_TO_SELF,SITU,//大于0 则从右向当前位置移动,反之则从左 + Animation.RELATIVE_TO_SELF,SITU,//大于0 则从当前位置向右移动,反之则向左 + Animation.RELATIVE_TO_SELF,SITU,//大于0 则从下方向当前位置,反之则从上方 + Animation.RELATIVE_TO_SELF,SITU);//大于0从当前位置向下移动,反之则向上方 + mAction.setDuration(ANIMA_TIME); + return mAction; + } + + + /** + * 从顶部显示 + * @return + */ + private static TranslateAnimation makeInFromTop(){ + TranslateAnimation mAction = new TranslateAnimation(Animation.RELATIVE_TO_SELF,SITU,//大于0 则从右向当前位置移动,反之则从左 + Animation.RELATIVE_TO_SELF,SITU,//大于0 则从当前位置向右移动,反之则向左 + Animation.RELATIVE_TO_SELF,0-MOVE_SPACE,//大于0 则从下方向当前位置,反之则从上方 + Animation.RELATIVE_TO_SELF,SITU);//大于0从当前位置向下移动,反之则向上方 + mAction.setDuration(ANIMA_TIME); + return mAction; + } + + /** + * 从底部显示 + * @return + */ + private static TranslateAnimation makeInFromBottom(){ + TranslateAnimation mAction = new TranslateAnimation(Animation.RELATIVE_TO_SELF,SITU,//大于0 则从右向当前位置移动,反之则从左 + Animation.RELATIVE_TO_SELF,SITU,//大于0 则从当前位置向右移动,反之则向左 + Animation.RELATIVE_TO_SELF,MOVE_SPACE,//大于0 则从下方向当前位置,反之则从上方 + Animation.RELATIVE_TO_SELF,SITU);//大于0从当前位置向下移动,反之则向上方 + mAction.setDuration(ANIMA_TIME); + return mAction; + } + + /** + * 从左侧显示 + * @return + */ + private static TranslateAnimation makeInFromLeft(){ + TranslateAnimation mAction = new TranslateAnimation(Animation.RELATIVE_TO_SELF,0-MOVE_SPACE,//大于0 则从右向当前位置移动,反之则从左 + Animation.RELATIVE_TO_SELF,SITU,//大于0 则从当前位置向右移动,反之则向左 + Animation.RELATIVE_TO_SELF,SITU,//大于0 则从下方向当前位置,反之则从上方 + Animation.RELATIVE_TO_SELF,SITU);//大于0从当前位置向下移动,反之则向上方 + mAction.setDuration(ANIMA_TIME); + return mAction; + } + + /** + * 从右侧显示 + * @return + */ + private static TranslateAnimation makeInFromRight(){ + TranslateAnimation mAction = new TranslateAnimation(Animation.RELATIVE_TO_SELF,MOVE_SPACE,//大于0 则从右向当前位置移动,反之则从左 + Animation.RELATIVE_TO_SELF,SITU,//大于0 则从当前位置向右移动,反之则向左 + Animation.RELATIVE_TO_SELF,SITU,//大于0 则从下方向当前位置,反之则从上方 + Animation.RELATIVE_TO_SELF,SITU);//大于0从当前位置向下移动,反之则向上方 + mAction.setDuration(ANIMA_TIME); + return mAction; + } + + + /** + * 向上隐藏 + * @return + */ + private static TranslateAnimation makeOutToTop(){ + TranslateAnimation mAction = new TranslateAnimation(Animation.RELATIVE_TO_SELF,SITU,//大于0 则从右向当前位置移动,反之则从左 + Animation.RELATIVE_TO_SELF,SITU,//大于0 则从当前位置向右移动,反之则向左 + Animation.RELATIVE_TO_SELF,SITU,//大于0 则从下方向当前位置,反之则从上方 + Animation.RELATIVE_TO_SELF,0-MOVE_SPACE);//大于0从当前位置向下移动,反之则向上方 + mAction.setDuration(ANIMA_TIME); + return mAction; + } + + /** + * 向左隐藏 + * @return + */ + private static TranslateAnimation makeOutToLeft(){ + TranslateAnimation mAction = new TranslateAnimation(Animation.RELATIVE_TO_SELF,SITU,//大于0 则从右向当前位置移动,反之则从左 + Animation.RELATIVE_TO_SELF,0-MOVE_SPACE,//大于0 则从当前位置向右移动,反之则向左 + Animation.RELATIVE_TO_SELF,SITU,//大于0 则从下方向当前位置,反之则从上方 + Animation.RELATIVE_TO_SELF,SITU);//大于0从当前位置向下移动,反之则向上方 + mAction.setDuration(ANIMA_TIME); + return mAction; + } + + /** + * 向右隐藏 + * @return + */ + private static TranslateAnimation makeOutToRight(){ + TranslateAnimation mAction = new TranslateAnimation(Animation.RELATIVE_TO_SELF,SITU,//大于0 则从右向当前位置移动,反之则从左 + Animation.RELATIVE_TO_SELF,MOVE_SPACE,//大于0 则从当前位置向右移动,反之则向左 + Animation.RELATIVE_TO_SELF,SITU,//大于0 则从下方向当前位置,反之则从上方 + Animation.RELATIVE_TO_SELF,SITU);//大于0从当前位置向下移动,反之则向上方 + mAction.setDuration(ANIMA_TIME); + return mAction; + } + + /** + * 向下隐藏 + * @return + */ + private static TranslateAnimation makeOutToButtom(){ + TranslateAnimation mAction = new TranslateAnimation(Animation.RELATIVE_TO_SELF,SITU,//大于0 则从右向当前位置移动,反之则从左 + Animation.RELATIVE_TO_SELF,SITU,//大于0 则从当前位置向右移动,反之则向左 + Animation.RELATIVE_TO_SELF,SITU,//大于0 则从下方向当前位置,反之则从上方 + Animation.RELATIVE_TO_SELF,MOVE_SPACE);//大于0从当前位置向下移动,反之则向上方 + mAction.setDuration(ANIMA_TIME); + return mAction; + } + + + + /*** + * 动画显示 从右向左左显示 + * + * @param view + */ + public static void showAnimaRightToLeft(View view) { + view.setVisibility(View.VISIBLE); + Animation mAni; + mAni = makeInFromRight(); + mAni.setDuration(ANIMA_TIME); + view.setAnimation(mAni); + } + + + /*** + * 动画显示 从右向左左显示 + * + * @param view + */ + public static void showAnimaLeftToRight(View view) { + view.setVisibility(View.VISIBLE); + Animation mAni; + mAni = makeInFromLeft(); + mAni.setDuration(ANIMA_TIME); + view.setAnimation(mAni); + } + + /** + * 动画隐藏 从下往上 + * + * @param view + */ + public static void hideAnimaBottomToTop(View view) { + view.setVisibility(View.INVISIBLE); + Animation mAni; + mAni = makeOutToTop(); + mAni.setDuration(ANIMA_TIME); + view.setAnimation(mAni); + } + + /** + * 动画隐藏 从左往右 + * + * @param view + */ + public static void hideAnimaLeftToRight(View view) { + view.setVisibility(View.INVISIBLE); + Animation mAni; + mAni = makeOutToRight(); + mAni.setDuration(ANIMA_TIME); + view.setAnimation(mAni); + } + + /** + * 动画隐藏 从右往左 + * + * @param view + */ + public static void hideAnimaRightToLeft(View view) { + view.setVisibility(View.INVISIBLE); + Animation mAni; + mAni = makeOutToLeft(); + mAni.setDuration(ANIMA_TIME); + view.setAnimation(mAni); + } + + + /** + * 动画隐藏 原地 + * + * @param view + */ + public static void hideAnimaInSitu(View view) { + view.setVisibility(View.INVISIBLE); + Animation mAni; + mAni = makeInSitu(); + mAni.setDuration(ANIMA_TIME); + view.setAnimation(mAni); + } + + + /** + * 动画显示 原地 + * + * @param view + */ + public static void showAnimaInSitu(View view) { + view.setVisibility(View.VISIBLE); + Animation mAni; + mAni = makeInSitu(); + mAni.setDuration(ANIMA_TIME); + view.setAnimation(mAni); + } + + + + /** + * 动画显示 从上往下走 + * + * @param view + */ + public static void showAnimaTopToBottom(View view) { + view.setVisibility(View.VISIBLE); + Animation mAni; + mAni = makeInFromTop(); + mAni.setDuration(ANIMA_TIME); + view.setAnimation(mAni); + } + + /** + * 冒泡式显示控件 + * @param view + */ + public static void showReBound(final View view){ + Log.i("","showReBound view:"+view); + view.setVisibility(View.GONE); + showAnimaInSitu(view); + SpringSystem springSystem = SpringSystem.create(); + final Spring spring = springSystem.createSpring(); + spring.setSpringConfig(SpringConfig.fromOrigamiTensionAndFriction(100,7));//qcTension拉力和qcFriction摩擦力参数 + spring.addListener(new SimpleSpringListener() { + @Override + public void onSpringUpdate(Spring spring) { + float value = (float) spring.getCurrentValue(); + float scale = value; + view.setScaleX(scale); + view.setScaleY(scale); + } + }); + spring.setEndValue(1);//控件拉伸收缩的倍率 + } + + /** + * 冒泡式放大控件 + * @param view + */ + public static void showReBoundBig(final View view){ + Log.i("","showReBound view:"+view); + view.setVisibility(View.GONE); + showAnimaInSitu(view); + SpringSystem springSystem = SpringSystem.create(); + final Spring spring = springSystem.createSpring(); + spring.setSpringConfig(SpringConfig.fromOrigamiTensionAndFriction(100,7));//qcTension拉力和qcFriction摩擦力参数 + spring.addListener(new SimpleSpringListener() { + @Override + public void onSpringUpdate(Spring spring) { + float value = (float) spring.getCurrentValue(); + float scale = value; + view.setScaleX(scale); + view.setScaleY(scale); + } + }); + spring.setEndValue(3);//控件拉伸收缩的倍率 + } + + /** + * 收缩式 隐藏 + * @param view + * @param context + */ + public static void hideReBound(final View view, final Context context){ + /*showReBound(view); + @SuppressLint("ResourceType") Animator animator = AnimatorInflater.loadAnimator(context, R.anim.anima_make_none); + animator.setTarget(view); + animator.start();*/ + + final Handler handler = new Handler() { + + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + float value = (float) msg.obj; + if(value>2){ + @SuppressLint("ResourceType") Animator animator = AnimatorInflater.loadAnimator(context, R.anim.anima_make_none); + animator.setTarget(view); + animator.start(); + animator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationEnd(Animator animation, boolean isReverse) { + MyLog.i("hideReBound","onAnimationEnd "+animation+" "+isReverse); + view.setVisibility(View.GONE); + } + @Override + public void onAnimationStart(Animator animation, boolean isReverse) {} + @Override + public void onAnimationStart(Animator animator) { + } + @Override + public void onAnimationEnd(Animator animator) { + MyLog.i("hideReBound","onAnimationEnd "+animator); + view.setVisibility(View.GONE); + } + @Override + public void onAnimationCancel(Animator animator) {} + @Override + public void onAnimationRepeat(Animator animator) { } + }); + hideAnimaInSitu(view); + }else { + value = 1f + (value); + view.setScaleX(value); + view.setScaleY(value); + } + } + }; + new Thread(){ + @Override + public void run() { + try { + int sleep = 10; + for(int i =0 ; i < 100 ; i+=sleep){ + sleep(sleep); + Message msg = new Message(); + msg.obj = (float)i/100/3; + handler.sendMessage(msg); + } + + Message msg = new Message(); + msg.obj = 3f; + handler.sendMessage(msg); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }.start(); + } + + static int time = 0; + public static void animaScale(final Context context, final View view, final float x, final float y){ + + final Handler handler = new Handler() { + + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + float value = (float) msg.obj; + value = 1f + (value); + view.setScaleX(value); + view.setScaleY(value); + } + }; + new Thread(){ + @Override + public void run() { + try { + int sleep = 10; + for(int i =0 ; i < 100 ; i+=sleep){ + sleep(sleep); + Message msg = new Message(); + msg.obj = (float)i/100/3; + handler.sendMessage(msg); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }.start(); + } + + /** + * 冒泡式拉伸控件 + * @param view + */ + public static void scaleReBoundX(final View view, final int size){ + Log.i("","scaleReBound view:"+view); + SpringSystem springSystem = SpringSystem.create(); + final Spring spring = springSystem.createSpring(); + spring.setSpringConfig(SpringConfig.fromOrigamiTensionAndFriction(100,7));//qcTension拉力和qcFriction摩擦力参数 + spring.addListener(new SimpleSpringListener() { + @Override + public void onSpringUpdate(Spring spring) { + float value = (float) spring.getCurrentValue(); + float scale = value; + view.setScaleX(scale); + view.setScaleY(scale); + } + }); + spring.setEndValue(size);//控件拉伸收缩的倍率 + } + + public static void scalXAnima(final View view, float from, float to){ + setAnimator("scaleX",from,to,view,ANIMA_TIME); + } +} diff --git a/app/src/main/java/com/runt/open/mvvm/util/PhoneUtil.java b/app/src/main/java/com/runt/open/mvvm/util/PhoneUtil.java new file mode 100644 index 0000000..6c80502 --- /dev/null +++ b/app/src/main/java/com/runt/open/mvvm/util/PhoneUtil.java @@ -0,0 +1,77 @@ +package com.runt.open.mvvm.util; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * My father is Object, ites purpose of + * + * @purpose Created by Runt (qingingrunt2010@qq.com) on 2020-4-14. + */ +public class PhoneUtil { + /** + * 验证中国大陆手机号是否合法 + * @return + */ + public static boolean isCNMobileNO(String mobile){ + if (mobile.length() != 11) + { + return false; + }else{ + /** + * 移动号段正则表达式 + */ + String pat1 = "^((13[4-9])|(147)|(15[0-2,7-9])|(178)|(18[2-4,7-8]))\\d{8}|(1705)\\d{7}$"; + /** + * 联通号段正则表达式 + */ + String pat2 = "^((13[0-2])|(145)|(15[5-6])|(176)|(18[5,6]))\\d{8}|(1709)\\d{7}$"; + /** + * 电信号段正则表达式 + */ + String pat3 = "^((133)|(153)|(177)|(18[0,1,9])|(149))\\d{8}$"; + /** + * 虚拟运营商正则表达式 + */ + String pat4 = "^((170))\\d{8}|(1718)|(1719)\\d{7}$"; + + Pattern pattern1 = Pattern.compile(pat1); + Matcher match1 = pattern1.matcher(mobile); + boolean isMatch1 = match1.matches(); + if(isMatch1){ + return true; + } + Pattern pattern2 = Pattern.compile(pat2); + Matcher match2 = pattern2.matcher(mobile); + boolean isMatch2 = match2.matches(); + if(isMatch2){ + return true; + } + Pattern pattern3 = Pattern.compile(pat3); + Matcher match3 = pattern3.matcher(mobile); + boolean isMatch3 = match3.matches(); + if(isMatch3){ + return true; + } + Pattern pattern4 = Pattern.compile(pat4); + Matcher match4 = pattern4.matcher(mobile); + boolean isMatch4 = match4.matches(); + if(isMatch4){ + return true; + } + return false; + } + } + + public static boolean isMobileNO( String phone) { + //china phone + String regex = "^((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(166)|(17[0,1,3,5,6,7,8])|(18[0-9])|(19[8|9]))\\d{8}$"; + if (phone.length() != 11) { + return false; + } else { + Pattern p = Pattern.compile(regex); + Matcher m = p.matcher(phone); + return m.matches(); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/runt/open/mvvm/util/PreferencesUtils.java b/app/src/main/java/com/runt/open/mvvm/util/PreferencesUtils.java new file mode 100644 index 0000000..235dabd --- /dev/null +++ b/app/src/main/java/com/runt/open/mvvm/util/PreferencesUtils.java @@ -0,0 +1,352 @@ +package com.runt.open.mvvm.util; + +import android.content.Context; +import android.content.SharedPreferences; + +import androidx.collection.ArraySet; + +import java.util.Set; + +/** + * PreferencesUtils, easy to get or put data + * <ul> + * <strong>Preference Name</strong> + * <li>you can change preference name by {@link #PREFERENCE_NAME}</li> + * </ul> + * <ul> + * <strong>Put Value</strong> + * </ul> + * + * @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-3-6 + */ +public class PreferencesUtils { + + public static final String PREFERENCE_NAME="zipper"; + public static final String PROJECT = "project"; + public static final String USER = "user"; + public static final String VISITOR = "visitor"; + + private PreferencesUtils() { + throw new AssertionError(); + } + + public static boolean clearData(Context context, String keyShared){ + SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE); + return settings.edit().clear().commit(); + } + + + public static boolean clearData(Context context, String key, String keyShared){ + putString(context,key,null,keyShared); + return true; + } + + + + /** + * remove key preferences + * + * @param context + * @param key The name of the preference to modify + * @return True if the new values were successfully written to persistent storage. + */ + public static void removeKey(Context context, String key, String keyShared){ + + SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = settings.edit(); + editor.remove(key); + } + + /** + * remove value preferences + * + * @param context + * @param value The name of the preference to modify + * @return True if the new values were successfully written to persistent storage. + */ + public static void removeValue(Context context, String value, String keyShared){ + SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = settings.edit(); + editor.remove(value); + } + + + /** + * put string preferences + * + * @param context + * @param key The name of the preference to modify + * @param value The new value for the preference + * @return True if the new values were successfully written to persistent storage. + */ + public static boolean putString(Context context, String key, String value, String keyShared) { + SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = settings.edit(); + editor.putString(key, value); + return editor.commit(); + } + + /** + * get string preferences + * + * @param context + * @param key The name of the preference to retrieve + * @return The preference value if it exists, or null. Throws ClassCastException if there is a preference with this + * name that is not a string + * @see #getString(Context, String, String) + */ + public static String getString(Context context, String key, String keyShared) { + return getString(context, key, null,keyShared); + } + + /** + * get string preferences + * + * @param context + * @param key The name of the preference to retrieve + * @param defaultValue Value to return if this preference does not exist + * @return The preference value if it exists, or defValue. Throws ClassCastException if there is a preference with + * this name that is not a string + */ + public static String getString(Context context, String key, String defaultValue, String keyShared) { + SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE); + return settings.getString(key, defaultValue); + } + + /** + * put int preferences + * + * @param context + * @param key The name of the preference to modify + * @param value The new value for the preference + * @return True if the new values were successfully written to persistent storage. + */ + public static boolean putInt(Context context, String key, int value, String keyShared) { + SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = settings.edit(); + editor.putInt(key, value); + return editor.commit(); + } + + /** + * get int preferences + * + * @param context + * @param key The name of the preference to retrieve + * @return The preference value if it exists, or -1. Throws ClassCastException if there is a preference with this + * name that is not a int + */ + public static int getInt(Context context, String key, String keyShared) { + return getInt(context, key, -1,keyShared); + } + + /** + * get int preferences + * + * @param context + * @param key The name of the preference to retrieve + * @param defaultValue Value to return if this preference does not exist + * @return The preference value if it exists, or defValue. Throws ClassCastException if there is a preference with + * this name that is not a int + */ + public static int getInt(Context context, String key, int defaultValue, String keyShared) { + SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE); + try { + return settings.getInt(key, defaultValue); + }catch (ClassCastException e){ + try { + return Integer.parseInt(settings.getString(key,defaultValue+"")); + }catch (NumberFormatException en){ + return defaultValue; + } + } + } + + /** + * put long preferences + * + * @param context + * @param key The name of the preference to modify + * @param value The new value for the preference + * @return True if the new values were successfully written to persistent storage. + */ + public static boolean putLong(Context context, String key, long value, String keyShared) { + SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = settings.edit(); + editor.putLong(key, value); + return editor.commit(); + } + + /** + * get long preferences + * + * @param context + * @param key The name of the preference to retrieve + * @return The preference value if it exists, or -1. Throws ClassCastException if there is a preference with this + * name that is not a long + */ + public static long getLong(Context context, String key, String keyShared) { + return getLong(context, key, -1,keyShared); + } + + /** + * get long preferences + * + * @param context + * @param key The name of the preference to retrieve + * @param defaultValue Value to return if this preference does not exist + * @return The preference value if it exists, or defValue. Throws ClassCastException if there is a preference with + * this name that is not a long + */ + public static long getLong(Context context, String key, long defaultValue, String keyShared) { + SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE); + try { + return settings.getLong(key, defaultValue); + }catch (ClassCastException e){ + try { + return Long.parseLong(settings.getString(key,defaultValue+"")); + }catch (NumberFormatException en){ + return defaultValue; + } + } + } + + /** + * put float preferences + * + * @param context + * @param key The name of the preference to modify + * @param value The new value for the preference + * @return True if the new values were successfully written to persistent storage. + */ + public static boolean putFloat(Context context, String key, float value, String keyShared) { + SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = settings.edit(); + editor.putFloat(key, value); + return editor.commit(); + } + + /** + * get float preferences + * + * @param context + * @param key The name of the preference to retrieve + * @return The preference value if it exists, or -1. Throws ClassCastException if there is a preference with this + * name that is not a float + */ + public static float getFloat(Context context, String key, String keyShared) { + return getFloat(context, key, -1,keyShared); + } + + /** + * get float preferences + * + * @param context + * @param key The name of the preference to retrieve + * @param defaultValue Value to return if this preference does not exist + * @return The preference value if it exists, or defValue. Throws ClassCastException if there is a preference with + * this name that is not a float + */ + public static float getFloat(Context context, String key, float defaultValue, String keyShared) { + SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE); + try { + return settings.getFloat(key, defaultValue); + }catch (ClassCastException e){ + try { + return Float.parseFloat(settings.getString(key,defaultValue+"")); + }catch (NumberFormatException en){ + return defaultValue; + } + } + } + + /** + * put boolean preferences + * + * @param context + * @param key The name of the preference to modify + * @param value The new value for the preference + * @return True if the new values were successfully written to persistent storage. + */ + public static boolean putBoolean(Context context, String key, boolean value, String keyShared) { + SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = settings.edit(); + editor.putBoolean(key, value); + return editor.commit(); + } + + /** + * get boolean preferences, default is false + * + * @param context + * @param key The name of the preference to retrieve + * @return The preference value if it exists, or false. Throws ClassCastException if there is a preference with this + * name that is not a boolean + */ + public static boolean getBoolean(Context context, String key, String keyShared) { + return getBoolean(context, key, false,keyShared); + } + + /** + * get boolean preferences + * + * @param context + * @param key The name of the preference to retrieve + * @param defaultValue Value to return if this preference does not exist + * @return The preference value if it exists, or defValue. Throws ClassCastException if there is a preference with + * this name that is not a boolean + */ + public static boolean getBoolean(Context context, String key, boolean defaultValue, String keyShared) { + SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE); + try { + return settings.getBoolean(key, defaultValue); + }catch (ClassCastException e){ + try { + return Boolean.parseBoolean(settings.getString(key,defaultValue+"")); + }catch (NumberFormatException en){ + return defaultValue; + } + } + } + + /** + * put boolean preferences + * + * @param context + * @param key The name of the preference to modify + * @param value The new value for the preference , the value of set ,canot be the other class out of java collection + * @return True if the new values were successfully written to persistent storage. + */ + public static boolean putStringSet(Context context, String key, Set value, String keyShared) { + SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = settings.edit(); + editor.putStringSet(key, value); + return editor.commit(); + } + + /** + * get boolean preferences, default is false + * + * @param context + * @param key The name of the preference to retrieve + * @return The preference value if it exists, or false. Throws ClassCastException if there is a preference with this + * name that is not a boolean 获取出来的值最终被转换为hashset类型 + */ + public static Set getStringSet(Context context, String key, String keyShared) { + return getStringSet(context, key,new ArraySet(),keyShared); + } + + /** + * get boolean preferences + * + * @param context + * @param key The name of the preference to retrieve + * @param defaultValue Value to return if this preference does not exist + * @return The preference value if it exists, or defValue. Throws ClassCastException if there is a preference with + * this name that is not a boolean 获取出来的值最终被转换为hashset类型 + */ + public static Set getStringSet(Context context, String key, Set defaultValue, String keyShared) { + SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE); + return settings.getStringSet(key, defaultValue); + } +} diff --git a/app/src/main/res/color/btn_txt_normal.xml b/app/src/main/res/color/btn_txt_normal.xml new file mode 100644 index 0000000..05ff6ac --- /dev/null +++ b/app/src/main/res/color/btn_txt_normal.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:tools="http://schemas.android.com/tools" + xmlns:android="http://schemas.android.com/apk/res/android" + tools:ignore="MissingDefaultResource"> + <item android:state_enabled="false" android:color="@color/txt_enable"/> <!-- pressed --> + <item android:state_pressed="true" android:color="@color/txt_cusor_color"/> <!-- pressed --> + <item android:state_focused="true" android:color="@color/txt_hint"/> <!-- focused --> + <item android:color="@color/white"/> <!-- default --> +</selector> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml new file mode 100644 index 0000000..9cc3693 --- /dev/null +++ b/app/src/main/res/layout/activity_login.xml @@ -0,0 +1,138 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <com.runt.open.mvvm.widgets.TitleBarView + android:id="@+id/title_bar" + style="@style/titlebar" + app:leftDrawable="@mipmap/ic_arrow_back_black_24dp" + app:titleText="登录" + tools:ignore="MissingConstraints" /> + + + <ImageView + android:id="@+id/img_icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_marginTop="50dp" + android:src="@mipmap/app_icon" + android:adjustViewBounds="true" + app:layout_constraintTop_toBottomOf="@id/title_bar" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + /> + + <com.runt.open.mvvm.widgets.ClearEditText + android:id="@+id/edit_phone" + style="@style/login_edit" + android:hint="@string/input_phone" + android:inputType="phone" + app:layout_constraintTop_toBottomOf="@id/img_icon" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + /> + + + <com.runt.open.mvvm.widgets.ClearEditText + android:id="@+id/edit_verify_code" + style="@style/login_edit" + android:hint="@string/input_verify_code" + android:inputType="number" + app:layout_constraintTop_toBottomOf="@id/edit_phone" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent"/> + + + <TextView + android:id="@+id/txt_get_verify" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textColor="@color/link" + android:layout_marginRight="@dimen/default_margin_lr" + android:text="@string/get_verify_code" + android:gravity="center" + app:layout_constraintTop_toTopOf="@id/edit_verify_code" + app:layout_constraintRight_toRightOf="@id/edit_verify_code" + app:layout_constraintBottom_toBottomOf="@id/edit_verify_code"/> + + + <com.runt.open.mvvm.widgets.ClearEditText + android:id="@+id/edit_pass" + style="@style/login_edit" + android:inputType="textPassword" + android:hint="@string/input_pass" + app:layout_constraintTop_toBottomOf="@id/edit_verify_code" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" /> + + + <com.runt.open.mvvm.widgets.ClearEditText + android:id="@+id/edit_pass_repeat" + style="@style/login_edit" + android:hint="@string/str_input_repeat" + android:inputType="textPassword" + app:layout_constraintTop_toBottomOf="@id/edit_pass" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent"/> + + + <TextView + android:id="@+id/txt_forgot" + style="@style/login_link" + android:text="@string/forgot_pass" + app:layout_constraintTop_toBottomOf="@id/edit_pass_repeat" + app:layout_constraintLeft_toLeftOf="parent" /> + <TextView + android:id="@+id/txt_register" + style="@style/login_link" + android:text="@string/register" + app:layout_constraintTop_toBottomOf="@id/edit_pass_repeat" + app:layout_constraintLeft_toRightOf="@id/txt_forgot" + app:layout_constraintRight_toLeftOf="@id/txt_login" /> + <TextView + android:id="@+id/txt_login" + style="@style/login_link" + android:text="@string/login" + app:layout_constraintTop_toBottomOf="@id/edit_pass_repeat" + app:layout_constraintRight_toRightOf="parent" /> + + <androidx.appcompat.widget.AppCompatCheckBox + android:id="@+id/checkbox" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="@dimen/default_margin_lr" + android:layout_marginBottom="@dimen/default_margin_lr" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintBottom_toTopOf="@id/button"/> + <TextView + android:id="@+id/txt_privacy" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingTop="@dimen/default_margin_td" + android:paddingBottom="@dimen/default_margin_td" + android:paddingRight="@dimen/default_margin_lr" + android:background="@color/white" + android:textColor="@color/link" + android:text=" 我已阅读并同意《隐私条款》" + app:layout_constraintLeft_toRightOf="@id/checkbox" + app:layout_constraintTop_toTopOf="@id/checkbox" + app:layout_constraintBottom_toBottomOf="@id/checkbox"/> + <Button + android:id="@+id/button" + style="@style/btn_normal" + android:layout_marginBottom="@dimen/default_margin_lr" + android:text="@string/login" + android:layout_marginLeft="@dimen/default_margin_lr" + android:layout_marginRight="@dimen/default_margin_lr" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent"/> +</androidx.constraintlayout.widget.ConstraintLayout> + + + diff --git a/app/src/main/res/layout/activity_web.xml b/app/src/main/res/layout/activity_web.xml new file mode 100644 index 0000000..c3ad397 --- /dev/null +++ b/app/src/main/res/layout/activity_web.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <com.runt.open.mvvm.widgets.TitleBarView + android:id="@+id/title_bar" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + style="@style/titlebar" /> + + <LinearLayout + android:id="@+id/lin_progressbar" + android:layout_width="match_parent" + android:layout_height="2dp" + android:background="@drawable/bg_gradient_gray" + app:layout_constraintTop_toBottomOf="@id/title_bar" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + android:visibility="gone"> + <View + android:id="@+id/view_progressbar" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:animateLayoutChanges="true" + android:background="@drawable/bg_gradient_blue"/> + </LinearLayout> + + <WebView + android:id="@+id/browser" + app:layout_constraintTop_toBottomOf="@id/title_bar" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + android:layout_width="match_parent" + android:layout_height="0dp" /> + +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1c9793b..15ac25b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2,4 +2,71 @@ <string name="title_home">Home</string> <string name="title_dashboard">Dashboard</string> <string name="title_notifications">Notifications</string> + <string name="get_verify_code">获取验证码</string> + <string name="select_region">选择国家/地区</string> + <string name="input_phone">请输入手机号</string> + <string name="input_pass">请输入密码</string> + <string name="input_verify_code">请输入验证码</string> + <string name="input_invite_code">请输入邀请码</string> + <string name="forgot_pass">忘记密码?</string> + <string name="register">注册</string> + <string name="login">登录</string> + <string name="msg_login">短信登录</string> + <string name="str_input_old">请输入旧密码</string> + <string name="str_input_new">请输入新密码</string> + <string name="str_input_repeat">请再次输入新密码</string> + <string name="str_pass_format_failed">密码要求6-12位数(数字/英文大小写/符号混合)格式</string> + <string name="str_cannot_eques_old">新密码不能与旧密码相同</string> + <string name="str_new_verify_failed">新密码两次输入不相同</string> + <string name="str_edit_pass">修改密码</string> + <string name="str_confirm">确认</string> + <string name="str_invite">推荐码</string> + <string name="str_mine">个人中心</string> + <string name="str_setting">设置</string> + <string name="str_msg">消息中心</string> + <string name="str_version">版本号</string> + <string name="str_msg_detail">资讯详情</string> + <string name="str_copied">复制成功</string> + <string name="str_get_data_failed">获取数据失败</string> + <string name="str_phone_format_failed">输入手机格式不正确</string> + <string name="login_pass_failed">账号或者密码错误,请重新输入</string> + <string name="login_code_failed">验证码有误,请重新输入</string> + <string name="comming_soon">敬请期待</string> + <string name="notice">通知</string> + <string name="save_img">保存图片</string> + <string name="copy_url">复制链接</string> + <string name="toast_login">请先登录后再操作</string> + <string name="registed">账号已经注册了</string> + <string name="failed">操作失败</string> + <string name="none_account">账号不存在</string> + <string name="loading">加载中</string> + <string name="register_success">账号注册成功请登录</string> + <string name="verify_failed">验证码失效</string> + <string name="invite_error">错误的邀请码</string> + <string name="update_pass_sucess">密码修改成功</string> + <string name="update_pass_failed_old">旧密码错误</string> + <string name="update_pass_failed">密码修改失败</string> + <string name="login_success">登录成功</string> + <string name="login_failed">登录失败</string> + <string name="login_failed_pass">密码错误</string> + <string name="new_version">新版本更新</string> + <string name="str_cancel">取消</string> + <string name="logouted">登录失效,请重新登录</string> + + <string name="forgot_update_pwd">点击忘记密码去修改</string> + <string name="download">下载</string> + <string name="created_at">更新</string> + <string name="msg_deleted">消息已被删除</string> + <string name="logout">退出登录</string> + <string name="internet_failed">网络连接失败</string> + <string name="str_miner_running">正在挖矿</string> + <string name="str_apply">申请</string> + <string name="str_permission">需要获取文件存储权限才能查看</string> + <string name="str_wait">敬请期待</string> + <string name="str_node_l">您当前为三级节点</string> + <string name="str_email">官方邮箱:</string> + <string name="str_website">官方网站:</string> + <string name="str_restart">重启APP</string> + <string name="str_success">成功</string> + <string name="str_no_up">暂无更新</string> </resources> \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index db5c358..4884702 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -63,4 +63,48 @@ <style name="TransparentDialog" parent="Theme.AppCompat.Dialog"> <item name="android:windowBackground">@color/transparent</item> </style> + + <style name="titlebar"> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">?attr/actionBarSize</item> + <item name="android:background">@color/white</item> + <item name="titleTextColor">@color/txt_normal</item> + <item name="layout_constraintTop_toTopOf">parent</item> + <item name="layout_constraintLeft_toLeftOf">parent</item> + <item name="layout_constraintRight_toRightOf">parent</item> + <item name="android:paddingLeft">@dimen/default_margin_lr</item> + <item name="android:paddingRight">@dimen/default_margin_lr</item> + </style> + + + <style name="btn_normal"> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:background">@drawable/btn_circle_blue</item> + <item name="android:textColor">@color/btn_txt_normal</item> + <item name="android:textSize">@dimen/title_size</item> + </style> + + <style name="login_edit"> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">@dimen/title_height</item> + <item name="android:background">@drawable/bg_circle_default</item> + <item name="android:layout_marginTop">@dimen/default_margin_td</item> + <item name="android:paddingRight">@dimen/default_margin_lr</item> + <item name="android:paddingLeft">@dimen/default_margin_lr</item> + <item name="android:singleLine">true</item> + <item name="android:gravity">center_vertical</item> + <item name="android:layout_marginLeft">@dimen/default_margin_lr</item> + <item name="android:layout_marginRight">@dimen/default_margin_lr</item> + </style> + + <style name="login_link"> + <item name="android:layout_width">wrap_content</item> + <item name="android:layout_height">wrap_content</item> + <item name="android:paddingTop">@dimen/default_margin_td</item> + <item name="android:paddingBottom">@dimen/default_margin_td</item> + <item name="android:paddingRight">30dp</item> + <item name="android:paddingLeft">30dp</item> + <item name="android:textColor">@color/link</item> + </style> </resources> \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 99e3317..3765728 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -3,7 +3,7 @@ <style name="Theme.OpemMvvm" parent="Theme.MaterialComponents.Light.NoActionBar"> <!-- Primary brand color. --> <item name="colorPrimary">@color/sky</item> - <item name="colorPrimaryVariant">@color/red</item> + <item name="colorPrimaryVariant">@color/blue_sky</item> <item name="colorOnPrimary">@color/black</item> <!-- Secondary brand color. --> <item name="colorSecondary">@color/black_4</item> @@ -12,6 +12,9 @@ <!-- Status bar color. --> <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item> <!-- Customize your theme here. --> + <!--全局设置文本颜色和大小--> + <item name="android:textColor">@color/txt_normal</item> + <item name="android:textSize">@dimen/txt_size</item> </style> -- Gitblit v1.9.1