From 9fbcdc146440b49ef80714c1336c226e00727da8 Mon Sep 17 00:00:00 2001
From: Administrator <123>
Date: Thu, 28 Oct 2021 10:16:30 +0000
Subject: [PATCH] 其他部分框架方法及文件新增
---
app/src/main/java/com/duqing/missions/base/BaseActivity.java | 404 +++++++++++
app/src/main/java/com/duqing/missions/data/BasePageResult.java | 21
app/src/main/java/com/duqing/missions/source/HttpPageSource.java | 16
app/src/main/java/com/duqing/missions/util/SpUtils.java | 476 +++++++++++++
app/src/main/java/com/duqing/missions/data/BaseApiResult.java | 23
app/src/main/java/com/duqing/missions/ui/main/home/HomeFragment.java | 113 +++
app/src/main/java/com/duqing/missions/ui/main/home/adapter/MissiontTopAdapter.java | 18
app/src/main/res/layout/fragment_dashboard.xml | 2
app/src/main/res/layout/activity_main.xml | 31
app/src/main/java/com/duqing/missions/MainActivity.java | 2
app/src/main/java/com/duqing/missions/ui/main/notifications/NotificationsViewModel.java | 2
app/build.gradle | 10
app/src/main/java/com/duqing/missions/common/NullViewHolder.java | 18
app/src/main/res/navigation/mobile_navigation.xml | 6
app/src/main/java/com/duqing/missions/ui/main/home/model/TopItemViewModel.java | 11
app/src/main/AndroidManifest.xml | 1
app/src/main/java/com/duqing/missions/data/ApkUpGradeResult.java | 29
app/src/main/res/layout/fragment_home.xml | 17
app/src/main/java/com/duqing/missions/MyApplication.java | 136 +++
app/src/main/res/layout/fragment_notifications.xml | 2
app/src/main/java/com/duqing/missions/util/ResPonse.java | 15
app/src/main/java/com/duqing/missions/base/BaseFragment.java | 52 +
/dev/null | 19
app/src/main/java/com/duqing/missions/base/BaseAdapter.java | 154 ++++
app/src/main/java/com/duqing/missions/ui/main/notifications/NotificationsFragment.java | 2
app/src/main/java/com/duqing/missions/ui/main/Text.java | 7
app/src/main/java/com/duqing/missions/util/DeviceUtil.java | 374 ++++++++++
app/src/main/java/com/duqing/missions/ui/main/dashboard/DashboardFragment.java | 4
app/src/main/java/com/duqing/missions/ui/main/home/model/MissionDesc.java | 12
app/src/main/java/com/duqing/missions/util/MyLog.java | 42 +
app/src/main/java/com/duqing/missions/ui/main/home/HomeViewModel.java | 47 +
31 files changed, 2,012 insertions(+), 54 deletions(-)
diff --git a/app/build.gradle b/app/build.gradle
index d9ad186..79380c7 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -45,4 +45,14 @@
//// 注意:分包之后不会有默认的Header和Footer需要手动添加!还是原来的三种方法!
implementation 'com.scwang.smart:refresh-layout-kernel:2.0.1' //核心必须依赖
implementation 'com.scwang.smart:refresh-header-classics:2.0.1' //经典刷新头
+ implementation 'com.github.d-max:spots-dialog:1.1@aar'//loading view
+ implementation 'com.google.code.gson:gson:2.8.6'
+ implementation 'com.ansen.http:okhttpencapsulation:1.0.1'//版本更新下载
+ implementation 'com.squareup.okhttp3:okhttp:3.12.1'
+ implementation 'com.squareup.retrofit2:retrofit:2.3.0'
+ //RXjava和retrofit结合
+ implementation 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
+ implementation 'com.google.android.material:material:1.4.0'
+ implementation 'com.github.bumptech.glide:glide:4.12.0'
+ implementation 'com.permissionx.guolindev:permissionx:1.2.2' //权限依赖
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0d606cb..468dd29 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,6 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.duqing.missions" >
+ <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
diff --git a/app/src/main/java/com/duqing/missions/MainActivity.java b/app/src/main/java/com/duqing/missions/MainActivity.java
index 3d0f16a..6c2f39a 100644
--- a/app/src/main/java/com/duqing/missions/MainActivity.java
+++ b/app/src/main/java/com/duqing/missions/MainActivity.java
@@ -9,7 +9,6 @@
import com.duqing.missions.base.BaseActivity;
import com.duqing.missions.databinding.ActivityMainBinding;
-import com.google.android.material.bottomnavigation.BottomNavigationView;
public class MainActivity extends BaseActivity<ActivityMainBinding> {
@@ -18,7 +17,6 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- BottomNavigationView navView = binding.navView;
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
diff --git a/app/src/main/java/com/duqing/missions/MyApplication.java b/app/src/main/java/com/duqing/missions/MyApplication.java
new file mode 100644
index 0000000..ef0eda4
--- /dev/null
+++ b/app/src/main/java/com/duqing/missions/MyApplication.java
@@ -0,0 +1,136 @@
+package com.duqing.missions;
+
+import android.app.Activity;
+import android.app.Application;
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.duqing.missions.util.MyLog;
+import com.scwang.smart.refresh.footer.ClassicsFooter;
+import com.scwang.smart.refresh.header.ClassicsHeader;
+import com.scwang.smart.refresh.layout.SmartRefreshLayout;
+import com.scwang.smart.refresh.layout.api.RefreshFooter;
+import com.scwang.smart.refresh.layout.api.RefreshHeader;
+import com.scwang.smart.refresh.layout.api.RefreshLayout;
+import com.scwang.smart.refresh.layout.listener.DefaultRefreshFooterCreator;
+import com.scwang.smart.refresh.layout.listener.DefaultRefreshHeaderCreator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by Administrator on 2021/10/28 0028.
+ */
+public class MyApplication extends Application {
+
+ final String TAG = "MyApplication";
+ List<Activity> activities = new ArrayList<>();
+ private Activity currentActivity;//当前activity
+ private boolean isInfront; //是否前台运行
+ private static MyApplication application;
+ public static MyApplication getApplication() {
+ return application;
+ }
+
+ public Activity getCurrentActivity() {
+ return currentActivity;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ application = this;
+ //CrashReport.initCrashReport(getApplicationContext(), "8d88679ae9", false);//注册bugly
+ //设置全局的Header构建器
+ SmartRefreshLayout.setDefaultRefreshHeaderCreator(new DefaultRefreshHeaderCreator() {
+ @Override
+ public RefreshHeader createRefreshHeader(Context context, RefreshLayout layout) {
+ //layout.setPrimaryColorsId(R.color.colorPrimary, android.R.color.white);//全局设置主题颜色
+ return new ClassicsHeader(context);//.setTimeFormat(new DynamicTimeFormat("更新于 %s"));//指定为经典Header,默认是 贝塞尔雷达Header
+ }
+ });
+ //设置全局的Footer构建器
+ SmartRefreshLayout.setDefaultRefreshFooterCreator(new DefaultRefreshFooterCreator() {
+ @Override
+ public RefreshFooter createRefreshFooter(Context context, RefreshLayout layout) {
+ //指定为经典Footer,默认是 BallPulseFooter
+ return new ClassicsFooter(context).setDrawableSize(20);
+ }
+ });
+ registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
+ @Override
+ public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
+ MyLog.d(TAG,"onActivityCreated "+activity.getClass().getSimpleName());
+ if(!activities.contains(activity)){
+ activities.add(activity);
+ }
+ }
+
+ @Override
+ public void onActivityStarted(@NonNull Activity activity) {
+ MyLog.d(TAG,"onActivityStarted "+activity.getClass().getSimpleName());
+ currentActivity = activity;
+ }
+
+ @Override
+ public void onActivityResumed(@NonNull Activity activity) {
+ MyLog.d(TAG,"onActivityResumed "+activity.getClass().getSimpleName());
+ currentActivity = activity;
+ isInfront = true;
+ }
+
+ @Override
+ public void onActivityPaused(@NonNull Activity activity) {
+ MyLog.d(TAG,"onActivityPaused "+activity.getClass().getSimpleName());
+
+ }
+
+ @Override
+ public void onActivityStopped(@NonNull Activity activity) {
+ MyLog.d(TAG,"onActivityStopped "+activity.getClass().getSimpleName());
+
+ }
+
+ @Override
+ public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle bundle) {
+ MyLog.d(TAG,"onActivitySaveInstanceState "+activity.getClass().getSimpleName());
+ isInfront = false;
+
+ }
+
+ @Override
+ public void onActivityDestroyed(@NonNull Activity activity) {
+ MyLog.d(TAG,"onActivityDestroyed "+activity.getClass().getSimpleName());
+ if(activities.contains(activity)){
+ activities.remove(activity);
+ }
+ }
+ });
+ }
+
+ /**
+ * 退出程序
+ */
+ public void quitApp(){
+ for(Activity activity:activities){
+ activity.finish();
+ }
+ System.exit(0);
+ }
+
+ public void clearActivities(){
+ for(Activity activity:activities){
+ /*if(activity instanceof LoginActivity){
+ continue;
+ }*/
+ activity.finish();
+ }
+ }
+
+ public boolean isInfront(){
+ return isInfront;
+ }
+}
diff --git a/app/src/main/java/com/duqing/missions/base/BaseActivity.java b/app/src/main/java/com/duqing/missions/base/BaseActivity.java
index cd24d4d..ef14ad3 100644
--- a/app/src/main/java/com/duqing/missions/base/BaseActivity.java
+++ b/app/src/main/java/com/duqing/missions/base/BaseActivity.java
@@ -1,14 +1,56 @@
package com.duqing.missions.base;
+import android.Manifest;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
+import android.os.Environment;
+import android.provider.Settings;
+import android.util.Log;
import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.Toast;
+import androidx.annotation.ColorRes;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.content.FileProvider;
import androidx.viewbinding.ViewBinding;
+import com.duqing.missions.MyApplication;
+import com.duqing.missions.data.ApkUpGradeResult;
+import com.duqing.missions.util.MyLog;
+import com.duqing.missions.util.ResPonse;
+import com.duqing.missions.util.SpUtils;
+import com.permissionx.guolindev.PermissionX;
+import com.permissionx.guolindev.callback.ExplainReasonCallbackWithBeforeParam;
+import com.permissionx.guolindev.callback.ForwardToSettingsCallback;
+import com.permissionx.guolindev.callback.RequestCallback;
+import com.permissionx.guolindev.request.ExplainScope;
+import com.permissionx.guolindev.request.ForwardScope;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
+import java.util.Date;
+import java.util.List;
+
+import okhttp3.Call;
+import okhttp3.Callback;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
/**
* Created by Administrator on 2021/10/27 0027.
@@ -16,6 +58,41 @@
public abstract class BaseActivity<B extends ViewBinding> extends AppCompatActivity {
protected B binding;
+ protected String TAG ;
+ public final String[] FILE_PERMISSIONS = new String []{Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE};
+ 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 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;
+ public static final int REQUEST_CODE_LOGOUT = 20009,/*退出*/
+ REQUEST_CODE_ORDER = 10010,/*订单详情*/
+ REQUEST_CODE_LOGIN = 20010,/*登录*/
+ REQUEST_CODE_SCAN = 20011/*扫描请求*/,
+ REQUEST_CODE_PIC = 20012,/*选择图片*/
+ REQUEST_CODE_PAYPASS = 20112,/*支付验证*/
+ REQUEST_CODE_PAYPASS_FOR_ALIPAY = 20110,/*支付宝修改支付验证*/
+ REQUEST_CODE_PAYPASS_FOR_REALNAME = 20111,/*支付宝修改支付验证*/
+ REQUEST_CODE_PERMISSION = 20013,/*请求权限*/
+ REQUEST_VERSION_PERMISSION = 20013,/*检查更新*/
+ REQUEST_INSTALL_PERMISSION = 20014,/*请求安装权限*/
+ REQUEST_CODE_MANAGE_GROUP = 20015,/*选择分组*/
+ REQUEST_CODE_MANAGE_DEL = 20016,/*选择删除*/
+ REQUEST_CODE_MANAGE_EDIT = 20017,/*选择编辑*/
+ REQUEST_CODE_MANAGE_ADD = 20018,/*选择添加*/
+ REQUEST_CODE_MANAGE_DRAFT = 20019,/*选择草稿编辑*/
+ REQUEST_CODE_WEPAY = 20020,/*微信支付*/
+ REQUEST_CODE_ALIPAY = 20021,/*支付宝*/
+ REQUEST_CODE_PINKAGE = 20022,/*包邮设置*/
+ REQUEST_INSTALL_APK = 20200,/*请求安装权限*/
+ REQUEST_CODE_COMMENT_REFRESH = 20222,/*请求安装权限*/
+ RESULT_CODE_DRAFT = 4041/*草稿*/,
+ RESULT_CODE_UPDATED = 4042/*更新*/,
+ RESULT_CODE_FAILD = 4044/*失败*/,
+ RESULT_CODE_SUCESS = 4046/*成功*/,
+ RESULT_CODE_CANCEL = 4043/*取消*/;
+ protected Context mContext;
@Override
@@ -30,5 +107,332 @@
e.printStackTrace();
}
setContentView(binding.getRoot());
+ mContext = this;
+ try {
+ //设置坚屏 一定要放到try catch里面,否则会崩溃
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ } catch (Exception e) {
+ }
+ TAG = this.getClass().getSimpleName();
}
+
+
+ public void setStatusBarTransparent(boolean isBlack){
+ //透明状态栏
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ //透明导航栏
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
+ }
+
+ /**
+ * 修改状态栏颜色,支持4.4以上版本
+ * @param colorId
+ */
+ public void setStatusBarBgColor(@ColorRes int colorId) {
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ getWindow().setStatusBarColor(getResources().getColor(colorId));
+ }
+
+ /**
+ * 修改状态栏文本颜色
+ * @param isBlack
+ */
+ public void setStatusBarTextColor(boolean isBlack){
+ View decor = getWindow().getDecorView();
+ if (isBlack) {
+ decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+ } else {
+ decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+ }
+ }
+
+ /**
+ * 隐藏虚拟按键
+ */
+ public void hideBottomUIMenu() {
+ //隐藏虚拟按键
+ if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api
+ View v = getWindow().getDecorView();
+ v.setSystemUiVisibility(View.GONE);
+ } else if (Build.VERSION.SDK_INT >= 19) {
+ //for new api versions.
+ View decorView = getWindow().getDecorView();
+ int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY ;
+ decorView.setSystemUiVisibility(uiOptions);
+ }
+
+ }
+
+ /**
+ * 状态栏高度
+ * @return
+ */
+ public int getStatusBarHeight() {
+ int result = 0;
+ int resId = getResources().getIdentifier("status_bar_height", "dimen", "android");
+ if (resId > 0) {
+ result = getResources().getDimensionPixelOffset(resId);
+ }
+ return result;
+ }
+
+
+ long mExitTime= 0 ;
+ /**
+ * 返回键退出程序
+ */
+ public void backExit() {
+ if ((System.currentTimeMillis() - mExitTime) > 2000) {
+ Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show();
+ mExitTime = System.currentTimeMillis();
+ } else {
+ //此方法导致app关闭后重启
+ MyApplication.getApplication().quitApp();
+ System.exit(0);
+ //quitApp();
+ }
+ }
+ ApkUpGradeResult.AppInfo apkUpGrade;
+ ProgressDialog progressDialog ;
+
+ public void showUpdateDialog(){
+ if(apkUpGrade == null){
+ return;
+ }
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle("新版本").setMessage("有新版更新\n"+apkUpGrade.content)
+ .setPositiveButton("", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ okHttpDownload(apkUpGrade.url, new ResPonse<String>() {
+ @Override
+ public void doSuccess(String path) {
+ apkUpGrade.remark = path;
+ openAPK(new File(path));
+ }
+
+ @Override
+ public void doError(String path) {
+ if(apkUpGrade.isImportant==1){
+ showUpdateDialog();
+ }else {
+ if(path != null) {
+ apkUpGrade.remark = path;
+ openAPK(new File(path));
+ }
+ }
+ }
+ });
+ }
+ })
+ .setNegativeButton(apkUpGrade.isImportant==1?"退出":"取消", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if(apkUpGrade.isImportant==1){
+ MyApplication.getApplication().quitApp();
+ }else {
+ SpUtils.getInstance().putLongValOfProject(mContext,"version", new Date().getTime());//记录今天已经请求过更新 不在自动请求
+ }
+ }
+ });
+ }
+
+ /**
+ * okhttp下载文件
+ * @param downloadUrl
+ * @param resPonse
+ */
+ protected void okHttpDownload(final String downloadUrl, final ResPonse<String> resPonse){
+ PermissionX.init(this).permissions(FILE_PERMISSIONS).onExplainRequestReason(new ExplainReasonCallbackWithBeforeParam() {
+ @Override
+ public void onExplainReason(ExplainScope scope, List<String> deniedList, boolean beforeRequest) {
+ scope.showRequestReasonDialog(deniedList, "即将申请的权限是程序必须依赖的权限", "继续申请","我已明白");
+ }
+ }).onForwardToSettings(new ForwardToSettingsCallback() {
+ @Override
+ public void onForwardToSettings(ForwardScope scope, List<String> deniedList) {
+ scope.showForwardToSettingsDialog(deniedList, "您需要去应用程序设置当中手动开启权限", "去设置","我已明白");
+ }
+ }).request(new RequestCallback() {
+ @Override
+ public void onResult(boolean allGranted, List<String> grantedList, List<String> deniedList) {
+ if(allGranted){
+
+ OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
+
+ Request request = new Request.Builder()
+ .url(downloadUrl)
+ .get()
+ .build();
+
+ okHttpClient.newCall(request).enqueue(new Callback() {
+ @Override
+ public void onFailure(Call call, IOException e) {
+ Log.e("tag", "onFailure: " + e.getMessage());
+ }
+
+ @Override
+ public void onResponse(Call call, Response response) throws IOException {
+ ResponseBody body = response.body(); // 获取到请求体
+ InputStream inputStream = body.byteStream(); // 转换成字节流
+ progressDialog = new ProgressDialog(mContext);
+ progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ progressDialog.setTitle("正在下载...");
+ progressDialog.setCancelable(false);
+ progressDialog.show();
+ saveFile(inputStream, getSaveFilePath(downloadUrl), body.contentLength(),resPonse);
+ }
+ });
+ } else {
+ Toast.makeText(mContext, "您拒绝了权限申请!", Toast.LENGTH_SHORT).show();
+ }
+ }
+ });
+ }
+
+ /**
+ * @param inputStream
+ * @param filePath 存放的地址
+ * @param l 文件的长度
+ */
+ private void saveFile(InputStream inputStream, final String filePath, final long l, final ResPonse<String> resPonse) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ progressDialog.setMax((int)l);// 设置进度条最大值
+ }
+ });
+ long count = 0;
+ try {
+ File file = new File(filePath);
+ Log.i(TAG, "文件保存路径:" + filePath+" 文件是否存在:"+file.exists());
+ if (!file.exists()) {//文件不存在
+ file.createNewFile();
+ }else{
+ file.delete();
+ }
+ // 获取到输出流,写入到的地址
+ FileOutputStream outputStream = new FileOutputStream(file);
+ int length = -1;
+ byte[] bytes = new byte[1024 * 10];
+ while ((length = inputStream.read(bytes)) != -1) {
+ // 写入文件
+ outputStream.write(bytes, 0, length);
+ count += length;
+
+ final long finalCount = count;
+ final int finalLenght = length;
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ progressDialog.setProgress((int) finalCount); // 设置进度
+ }
+ });
+ }
+ inputStream.close(); // 关闭输入流
+ outputStream.close(); // 关闭输出流
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ // 如果写入的进度值完毕,Toast
+ progressDialog.dismiss();
+ resPonse.doSuccess(filePath);
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ /**
+ * 获取文件保存路径 sdcard根目录/download/文件名称
+ * @param fileUrl
+ * @return
+ */
+ public static String getSaveFilePath(String fileUrl){
+ String fileName=fileUrl.substring(fileUrl.lastIndexOf("/")+1,fileUrl.length());//获取文件名称
+ String storePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "Download";
+ File appDir = new File(storePath);
+ if (!appDir.exists()) {
+ appDir.mkdirs();
+ }
+ return storePath + File.separator +fileName;
+ }
+
+ /**
+ * 打开apk文件
+ * @param file
+ */
+ public void openAPK(final File file){
+
+ //android 8及以上需要设置权限
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !getPackageManager().canRequestPackageInstalls()) {
+ // 申请安装权限。
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle("需要允许安装权限").setMessage("应用需要手动设置,才能打开安装包升级应用").setCancelable(false)
+ .setNegativeButton("", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Uri packageUri = Uri.parse("package:" + getPackageName());
+ Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageUri);
+ startActivityForResult(intent, REQUEST_INSTALL_PERMISSION);
+ dialog.dismiss();
+ }
+ })
+ .setPositiveButton(apkUpGrade.isImportant==1?"退出":"取消", new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if(apkUpGrade.isImportant==1){
+ MyApplication.getApplication().quitApp();
+ }
+ }
+ }).create().show();
+ return;
+ }
+
+ Intent intent = new Intent();
+ intent.setAction(Intent.ACTION_VIEW);
+ Uri photoURI = null ;
+ if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.N) { //判读版本是否在7.0以上
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ photoURI = FileProvider.getUriForFile(mContext, mContext.getApplicationContext().getPackageName() + ".provider", file);//添加这一句表示对目标应用临时授权该Uri所代表的文件
+
+ }else{
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ photoURI = Uri.fromFile(file);
+ }
+ intent.setDataAndType(photoURI,"application/vnd.android.package-archive");
+ startActivityForResult(intent,REQUEST_INSTALL_APK);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ MyLog.i(TAG,String.format("onActivityResult requestCode:%s, resultCode:%s, data:%s",requestCode, resultCode, data));
+ if(requestCode == REQUEST_INSTALL_PERMISSION){
+ openAPK(new File(apkUpGrade.remark));
+ }else if(requestCode == REQUEST_INSTALL_APK && apkUpGrade.isImportant==1){
+ /*showDialog("强制更新", "需要安装新版本才能继续使用","安装","退出", new ResPonse() {
+ @Override
+ public void doSuccess(Object obj) {
+
+ }
+
+ @Override
+ public void doError(Object obj) {
+ super.doError(obj);
+ }
+ });*/
+ }
+ }
+
+
+ protected boolean onBackKeyDown() {
+ onBackPressed();
+ return false;
+ }
+
}
diff --git a/app/src/main/java/com/duqing/missions/base/BaseAdapter.java b/app/src/main/java/com/duqing/missions/base/BaseAdapter.java
new file mode 100644
index 0000000..520e455
--- /dev/null
+++ b/app/src/main/java/com/duqing/missions/base/BaseAdapter.java
@@ -0,0 +1,154 @@
+package com.duqing.missions.base;
+
+import android.graphics.drawable.Drawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.viewbinding.ViewBinding;
+
+import com.duqing.missions.R;
+import com.duqing.missions.common.NullViewHolder;
+import com.duqing.missions.databinding.LayoutNullBinding;
+import com.duqing.missions.util.DeviceUtil;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by Administrator on 2021/10/27 0027.
+ * T 数据类型
+ * V 适配器视图
+ */
+public abstract class BaseAdapter<B extends ViewBinding,A extends BaseActivity,T> extends RecyclerView.Adapter {
+
+ protected List<T> mData = new ArrayList<>();
+
+ protected Drawable nullDrawable;
+ protected String nullTxt="暂无数据";
+ protected String TAG = "BaseAdapter";
+ protected A activity;
+ protected LayoutNullBinding nullBinding;
+
+ public BaseAdapter(){
+ }
+
+ public BaseAdapter(@NonNull List<T> data){
+ mData = data;
+ }
+
+ public List<T> getData() {
+ return mData;
+ }
+
+ public void setData(@NonNull List<T> data){
+ mData = data;
+ notifyDataSetChanged();
+ }
+
+ @NonNull
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ // get genericity "B"
+ Class<B> entityClass = (Class<B>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
+ try {
+ /* for(Method method: entityClass.getMethods()){
+ StringBuilder sb = new StringBuilder();
+ for(Class type : method.getParameterTypes()){
+ sb.append(type.getSimpleName()+",");
+ }
+ Log.e(TAG,String.format("method:%s,return:%s,param:%s",method.getName(),method.getReturnType().getSimpleName(),sb.toString()));
+ }*/
+ Method method = entityClass.getMethod("inflate", LayoutInflater.class,ViewGroup.class,boolean.class);//get method from name "inflate";
+ B vBind = (B) method.invoke(entityClass,LayoutInflater.from(parent.getContext()),parent,false);//execute method to create a objct of viewbind;
+ return new ViewBindHolder(vBind);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return new NullViewHolder( LayoutNullBinding.inflate(LayoutInflater.from(parent.getContext())));
+ }
+
+ /**
+ *
+ * 创建视图
+ * @param parent
+ * @param layout 视图文件
+ * @param viewType 视图类型 1 加载正常视图 其他则加载空数据
+ * @return
+ */
+ protected View getRootView(@NonNull ViewGroup parent, @LayoutRes int layout,int viewType ){
+ //MyLog.i(TAG,"getRootView viewType:"+viewType);
+ return LayoutInflater.from(parent.getContext()).inflate(viewType==1?layout: R.layout.layout_null,parent,false);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+ //MyLog.i(TAG,"onBindViewHolder position:"+position+" "+mData.size()+" "+getItemViewType(position));
+ if(getItemViewType(position)==0){
+ return;
+ }
+ try {
+ activity = (A) holder.itemView.getContext();
+ }catch (Exception e){}
+ bindView((ViewBindHolder) holder,mData.size()==0?null:mData.get(position),position);
+ }
+
+ /**
+ * 设置最后一个底部间隔
+ * @param holder
+ * @param position
+ */
+ protected void setBottomMargin(ViewBindHolder holder, int position){
+ setBottomMargin(holder,position,23);
+ }
+
+ /**
+ * 设置最后一个底部间隔
+ * @param holder
+ * @param position 位置
+ * @param dp 间距
+ */
+ protected void setBottomMargin(RecyclerView.ViewHolder holder, int position,int dp){
+ setBottomMargin(holder,position,dp,0);
+ }
+ protected void setBottomMargin(RecyclerView.ViewHolder holder, int position, int dp, int defaultDp){
+ ViewGroup.MarginLayoutParams params1 = (ViewGroup.MarginLayoutParams) holder.itemView.getLayoutParams();
+ if(position == mData.size() -1){
+ params1.setMargins(params1.leftMargin, params1.topMargin, params1.rightMargin, DeviceUtil.convertDpToPixel(dp,holder.itemView.getContext()));
+ }else{
+ params1.setMargins(params1.leftMargin, params1.topMargin, params1.rightMargin, DeviceUtil.convertDpToPixel(defaultDp,holder.itemView.getContext()));
+ }
+ }
+ protected abstract void bindView(ViewBindHolder holder,T data,int position);
+
+
+ @Override
+ public int getItemCount() {
+ //默认显示空视图,若不显示空视图则重写该方法,返回mData.size()
+ return mData == null || mData.size() == 0 ?1:mData.size();
+ }
+
+
+ @Override
+ public int getItemViewType(int position) {
+ //当下标为0,数据集合为0 返回0(意味当前应显示空数据视图))
+ //MyLog.i(TAG,"getItemViewType position:"+position+" mdata:"+mData.size()+" "+(position ==0 && mData.size()==0));
+ return position ==0 && mData.size()==0?0:1;
+ }
+
+ public class ViewBindHolder extends RecyclerView.ViewHolder{
+
+ B binding;
+
+ public ViewBindHolder( B binding) {
+ super(binding.getRoot());
+ this.binding = binding;
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/duqing/missions/base/BaseFragment.java b/app/src/main/java/com/duqing/missions/base/BaseFragment.java
new file mode 100644
index 0000000..c4eccf8
--- /dev/null
+++ b/app/src/main/java/com/duqing/missions/base/BaseFragment.java
@@ -0,0 +1,52 @@
+package com.duqing.missions.base;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.viewbinding.ViewBinding;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+
+/**
+ * Created by Administrator on 2021/10/28 0028.
+ */
+public abstract class BaseFragment<A extends BaseActivity,B extends ViewBinding> extends Fragment {
+
+ protected A activity;
+ protected B binding;
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
+ // get genericity "B"
+ Class<B> entityClass = (Class<B>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
+ try {
+ Method method = entityClass.getMethod("inflate", LayoutInflater.class,ViewGroup.class,boolean.class);//get method from name "inflate";
+ binding = (B) method.invoke(entityClass,inflater,container,false);//execute method to create a objct of viewbind;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return binding.getRoot();
+ }
+
+ @Override
+ public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ activity = (A) getActivity();
+ initViews();
+ }
+
+ public abstract void initViews();
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ binding = null;
+ }
+
+}
diff --git a/app/src/main/java/com/duqing/missions/common/NullViewHolder.java b/app/src/main/java/com/duqing/missions/common/NullViewHolder.java
new file mode 100644
index 0000000..21bd137
--- /dev/null
+++ b/app/src/main/java/com/duqing/missions/common/NullViewHolder.java
@@ -0,0 +1,18 @@
+package com.duqing.missions.common;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.duqing.missions.databinding.LayoutNullBinding;
+
+/**
+ * 空数据显示
+ * Created by Administrator on 2021/10/28 0028.
+ */
+public class NullViewHolder extends RecyclerView.ViewHolder {
+ LayoutNullBinding binding;
+
+ public NullViewHolder(LayoutNullBinding binding) {
+ super(binding.getRoot());
+ this.binding = binding;
+ }
+}
diff --git a/app/src/main/java/com/duqing/missions/data/ApkUpGradeResult.java b/app/src/main/java/com/duqing/missions/data/ApkUpGradeResult.java
new file mode 100644
index 0000000..27a34a8
--- /dev/null
+++ b/app/src/main/java/com/duqing/missions/data/ApkUpGradeResult.java
@@ -0,0 +1,29 @@
+package com.duqing.missions.data;
+
+/**
+ * Created by Administrator on 2021/10/28 0028.
+ */
+public class ApkUpGradeResult extends BaseApiResult<ApkUpGradeResult.AppInfo> {
+
+ public class AppInfo {
+ //以下为声明的参数
+ public int type, isEnable, isImportant, id, code;
+ public String url,version, content, udate, remark;
+
+
+ @Override
+ public String toString() {
+ return "ApkUpGrade{" +
+ "type=" + type + "," +
+ "isEnable=" + isEnable + "," +
+ "isImportant=" + isImportant + "," +
+ "id=" + id + "," +
+ "url=" + url + "," +
+ "version=" + version + "," +
+ "content=" + content + "," +
+ "udate=" + udate + "," +
+ '}';
+ }
+
+ }
+}
diff --git a/app/src/main/java/com/duqing/missions/data/BaseApiResult.java b/app/src/main/java/com/duqing/missions/data/BaseApiResult.java
new file mode 100644
index 0000000..ecd9acc
--- /dev/null
+++ b/app/src/main/java/com/duqing/missions/data/BaseApiResult.java
@@ -0,0 +1,23 @@
+package com.duqing.missions.data;
+
+import java.io.Serializable;
+
+/**
+ * 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;
+
+
+ @Override
+ public String toString() {
+ return "BaseApiData{" +
+ "msg='" + msg + '\'' +
+ ", code=" + code +
+ ", data=" + data +
+ '}';
+ }
+
+}
diff --git a/app/src/main/java/com/duqing/missions/data/BasePageResult.java b/app/src/main/java/com/duqing/missions/data/BasePageResult.java
new file mode 100644
index 0000000..6ae8be0
--- /dev/null
+++ b/app/src/main/java/com/duqing/missions/data/BasePageResult.java
@@ -0,0 +1,21 @@
+package com.duqing.missions.data;
+
+import java.util.ArrayList;
+
+/**
+ * Created by Administrator on 2021/10/28 0028.
+ */
+public class BasePageResult<T> extends BaseApiResult<String>{
+ public int pages;
+ public int total;
+ public int pageNum;
+ public ArrayList<T> rows;
+
+ @Override
+ public String toString() {
+ return "PageBean{" +
+ ", total=" + total +
+ ", rows=" + rows +
+ '}';
+ }
+}
diff --git a/app/src/main/java/com/duqing/missions/source/HttpPageSource.java b/app/src/main/java/com/duqing/missions/source/HttpPageSource.java
new file mode 100644
index 0000000..fa15ca4
--- /dev/null
+++ b/app/src/main/java/com/duqing/missions/source/HttpPageSource.java
@@ -0,0 +1,16 @@
+package com.duqing.missions.source;
+
+import com.duqing.missions.data.BasePageResult;
+
+import java.util.Observable;
+
+/**
+ * Created by Administrator on 2021/10/28 0028.
+ */
+public interface HttpPageSource<T extends BasePageResult> {
+
+ Observable refresh();
+
+ Observable loadMore(int page,int size);
+
+}
diff --git a/app/src/main/java/com/duqing/missions/ui/dashboard/DashboardViewModel.java b/app/src/main/java/com/duqing/missions/ui/dashboard/DashboardViewModel.java
deleted file mode 100644
index 2b45769..0000000
--- a/app/src/main/java/com/duqing/missions/ui/dashboard/DashboardViewModel.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.duqing.missions.ui.dashboard;
-
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.MutableLiveData;
-import androidx.lifecycle.ViewModel;
-
-public class DashboardViewModel extends ViewModel {
-
- private MutableLiveData<String> mText;
-
- public DashboardViewModel() {
- mText = new MutableLiveData<>();
- mText.setValue("This is dashboard fragment");
- }
-
- public LiveData<String> getText() {
- return mText;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/duqing/missions/ui/home/HomeFragment.java b/app/src/main/java/com/duqing/missions/ui/home/HomeFragment.java
deleted file mode 100644
index 9e8e621..0000000
--- a/app/src/main/java/com/duqing/missions/ui/home/HomeFragment.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package com.duqing.missions.ui.home;
-
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-import androidx.lifecycle.Observer;
-import androidx.lifecycle.ViewModelProvider;
-import androidx.recyclerview.widget.GridLayoutManager;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.duqing.missions.databinding.FragmentHomeBinding;
-import com.scwang.smart.refresh.header.ClassicsHeader;
-import com.scwang.smart.refresh.layout.SmartRefreshLayout;
-
-public class HomeFragment extends Fragment {
-
- private HomeViewModel homeViewModel;
- private FragmentHomeBinding binding;
-
- public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- homeViewModel = new ViewModelProvider(this).get(HomeViewModel.class);
-
- binding = FragmentHomeBinding.inflate(inflater, container, false);
- View root = binding.getRoot();
- final SmartRefreshLayout smartRefresh = binding.smartRefresh;
- smartRefresh.setRefreshHeader(new ClassicsHeader(getContext()));
- final TextView textView = binding.textRecommend;
- final ImageView imgSearch = binding.imgSearch;
- RecyclerView recyclerClassify = binding.recyclerClassify;
- RecyclerView recyclerTop = binding.recyclerTop;
- final RecyclerView recyclerRecommend = binding.recyclerRecommend;
- recyclerRecommend.setLayoutManager(new LinearLayoutManager(getContext()));
- LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
- layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
- recyclerClassify.setLayoutManager(layoutManager);
- recyclerTop.setLayoutManager(new GridLayoutManager(getContext(),3));
-
- homeViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
- @Override
- public void onChanged(@Nullable String s) {
- textView.setText(s);
- }
- });
- return root;
- }
-
- @Override
- public void onDestroyView() {
- super.onDestroyView();
- binding = null;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/duqing/missions/ui/home/HomeViewModel.java b/app/src/main/java/com/duqing/missions/ui/home/HomeViewModel.java
deleted file mode 100644
index 59bff9d..0000000
--- a/app/src/main/java/com/duqing/missions/ui/home/HomeViewModel.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.duqing.missions.ui.home;
-
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.MutableLiveData;
-import androidx.lifecycle.ViewModel;
-
-public class HomeViewModel extends ViewModel {
-
- private MutableLiveData<String> mText;
-
- public HomeViewModel() {
- mText = new MutableLiveData<>();
- mText.setValue("This is home fragment");
- }
-
- public LiveData<String> getText() {
- return mText;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/duqing/missions/ui/main/Text.java b/app/src/main/java/com/duqing/missions/ui/main/Text.java
new file mode 100644
index 0000000..1ab6c35
--- /dev/null
+++ b/app/src/main/java/com/duqing/missions/ui/main/Text.java
@@ -0,0 +1,7 @@
+package com.duqing.missions.ui.main;
+
+/**
+ * Created by Administrator on 2021/10/28 0028.
+ */
+public class Text {
+}
diff --git a/app/src/main/java/com/duqing/missions/ui/dashboard/DashboardFragment.java b/app/src/main/java/com/duqing/missions/ui/main/dashboard/DashboardFragment.java
similarity index 91%
rename from app/src/main/java/com/duqing/missions/ui/dashboard/DashboardFragment.java
rename to app/src/main/java/com/duqing/missions/ui/main/dashboard/DashboardFragment.java
index a63d963..a0d8ef3 100644
--- a/app/src/main/java/com/duqing/missions/ui/dashboard/DashboardFragment.java
+++ b/app/src/main/java/com/duqing/missions/ui/main/dashboard/DashboardFragment.java
@@ -1,10 +1,9 @@
-package com.duqing.missions.ui.dashboard;
+package com.duqing.missions.ui.main.dashboard;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -12,7 +11,6 @@
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
-import com.duqing.missions.R;
import com.duqing.missions.databinding.FragmentDashboardBinding;
public class DashboardFragment extends Fragment {
diff --git a/app/src/main/java/com/duqing/missions/ui/main/home/HomeFragment.java b/app/src/main/java/com/duqing/missions/ui/main/home/HomeFragment.java
new file mode 100644
index 0000000..665138e
--- /dev/null
+++ b/app/src/main/java/com/duqing/missions/ui/main/home/HomeFragment.java
@@ -0,0 +1,113 @@
+package com.duqing.missions.ui.main.home;
+
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.lifecycle.Observer;
+import androidx.lifecycle.ViewModelProvider;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.duqing.missions.MainActivity;
+import com.duqing.missions.base.BaseFragment;
+import com.duqing.missions.databinding.FragmentHomeBinding;
+import com.duqing.missions.ui.main.home.adapter.MissiontTopAdapter;
+import com.duqing.missions.ui.main.home.model.MissionDesc;
+import com.scwang.smart.refresh.footer.ClassicsFooter;
+import com.scwang.smart.refresh.header.ClassicsHeader;
+import com.scwang.smart.refresh.layout.SmartRefreshLayout;
+import com.scwang.smart.refresh.layout.api.RefreshLayout;
+import com.scwang.smart.refresh.layout.listener.OnRefreshLoadMoreListener;
+
+import java.util.List;
+
+public class HomeFragment extends BaseFragment<MainActivity,FragmentHomeBinding> {
+
+ private HomeViewModel homeViewModel;
+ final String TAG = "HomeFragment";
+
+
+ @Override
+ public void initViews() {
+ homeViewModel = new ViewModelProvider(this).get(HomeViewModel.class);
+ final SmartRefreshLayout smartRefresh = binding.smartRefresh;
+ smartRefresh.setRefreshHeader(new ClassicsHeader(getContext()));
+ smartRefresh.setRefreshFooter(new ClassicsFooter(getContext()));
+ final TextView textView = binding.textRecommend;
+ final ImageView imgSearch = binding.imgSearch;
+ RecyclerView recyclerClassify = binding.recyclerClassify;
+ RecyclerView recyclerTop = binding.recyclerTop;
+ final RecyclerView recyclerRecommend = binding.recyclerRecommend;
+ recyclerRecommend.setLayoutManager(new LinearLayoutManager(getContext()));
+ LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
+ layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
+ recyclerClassify.setLayoutManager(layoutManager);
+ recyclerTop.setLayoutManager(new GridLayoutManager(getContext(),3));
+ smartRefresh.setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() {
+ @Override
+ public void onLoadMore(@NonNull RefreshLayout refreshLayout) {
+ homeViewModel.onLoadMore();
+ }
+
+ @Override
+ public void onRefresh(@NonNull RefreshLayout refreshLayout) {
+ homeViewModel.onRefresh();
+ }
+ });
+ final MissiontTopAdapter topAdapter = new MissiontTopAdapter();
+ recyclerTop.setAdapter(topAdapter);
+ homeViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
+ @Override
+ public void onChanged(@Nullable String s) {
+ textView.setText(s);
+ }
+ });
+ homeViewModel.getMissions().observe(getViewLifecycleOwner(), new Observer<List<MissionDesc>>() {
+ @Override
+ public void onChanged(List<MissionDesc> missionDescs) {
+ smartRefresh.finishRefresh();
+ smartRefresh.finishLoadMore();
+ topAdapter.setData(missionDescs);
+ }
+ });
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
+ Log.e(TAG,"onCreateView");
+ return super.onCreateView(inflater, container, savedInstanceState);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ Log.e(TAG,"onResume");
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ Log.e(TAG,"onPause");
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ Log.e(TAG,"onStop");
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ Log.e(TAG,"onDestroyView");
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/duqing/missions/ui/main/home/HomeViewModel.java b/app/src/main/java/com/duqing/missions/ui/main/home/HomeViewModel.java
new file mode 100644
index 0000000..e76862b
--- /dev/null
+++ b/app/src/main/java/com/duqing/missions/ui/main/home/HomeViewModel.java
@@ -0,0 +1,47 @@
+package com.duqing.missions.ui.main.home;
+
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.ViewModel;
+
+import com.duqing.missions.ui.main.home.model.MissionDesc;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class HomeViewModel extends ViewModel {
+
+ private MutableLiveData<String> mText;
+ private MutableLiveData<List<MissionDesc>> missions = new MutableLiveData<>();
+
+ public HomeViewModel() {
+ mText = new MutableLiveData<>();
+ mText.setValue("This is home fragment");
+ }
+
+ public LiveData<String> getText() {
+ return mText;
+ }
+
+ public MutableLiveData<List<MissionDesc>> getMissions() {
+ return missions;
+ }
+
+ public void onRefresh(){
+ List<MissionDesc> list = new ArrayList<>();
+ list.add(new MissionDesc());
+ list.add(new MissionDesc());
+ list.add(new MissionDesc());
+ list.add(new MissionDesc());
+ missions.setValue(list);
+ }
+
+ public void onLoadMore(){
+ List<MissionDesc> list = missions.getValue();
+ list.add(new MissionDesc());
+ list.add(new MissionDesc());
+ list.add(new MissionDesc());
+ list.add(new MissionDesc());
+ missions.postValue(list);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/duqing/missions/ui/main/home/adapter/MissiontTopAdapter.java b/app/src/main/java/com/duqing/missions/ui/main/home/adapter/MissiontTopAdapter.java
new file mode 100644
index 0000000..de21915
--- /dev/null
+++ b/app/src/main/java/com/duqing/missions/ui/main/home/adapter/MissiontTopAdapter.java
@@ -0,0 +1,18 @@
+package com.duqing.missions.ui.main.home.adapter;
+
+import com.duqing.missions.MainActivity;
+import com.duqing.missions.base.BaseAdapter;
+import com.duqing.missions.databinding.HomeItemTopBinding;
+import com.duqing.missions.ui.main.home.model.MissionDesc;
+
+/**
+ * Created by Administrator on 2021/10/28 0028.
+ */
+public class MissiontTopAdapter extends BaseAdapter<HomeItemTopBinding, MainActivity, MissionDesc> {
+
+
+ @Override
+ protected void bindView(ViewBindHolder holder, MissionDesc data, int position) {
+
+ }
+}
diff --git a/app/src/main/java/com/duqing/missions/ui/main/home/model/MissionDesc.java b/app/src/main/java/com/duqing/missions/ui/main/home/model/MissionDesc.java
new file mode 100644
index 0000000..a67b8ba
--- /dev/null
+++ b/app/src/main/java/com/duqing/missions/ui/main/home/model/MissionDesc.java
@@ -0,0 +1,12 @@
+package com.duqing.missions.ui.main.home.model;
+
+/**
+ * 任务列表数据数据
+ * Created by Administrator on 2021/10/27 0027.
+ */
+public class MissionDesc {
+ public String title,type,label;
+ public double price;
+ public int participants,remaining,total;
+
+}
diff --git a/app/src/main/java/com/duqing/missions/ui/main/home/model/TopItemViewModel.java b/app/src/main/java/com/duqing/missions/ui/main/home/model/TopItemViewModel.java
new file mode 100644
index 0000000..8b2ab82
--- /dev/null
+++ b/app/src/main/java/com/duqing/missions/ui/main/home/model/TopItemViewModel.java
@@ -0,0 +1,11 @@
+package com.duqing.missions.ui.main.home.model;
+
+import androidx.lifecycle.ViewModel;
+
+/**
+ * Created by Administrator on 2021/10/28 0028.
+ */
+public class TopItemViewModel extends ViewModel {
+
+
+}
diff --git a/app/src/main/java/com/duqing/missions/ui/notifications/NotificationsFragment.java b/app/src/main/java/com/duqing/missions/ui/main/notifications/NotificationsFragment.java
similarity index 95%
rename from app/src/main/java/com/duqing/missions/ui/notifications/NotificationsFragment.java
rename to app/src/main/java/com/duqing/missions/ui/main/notifications/NotificationsFragment.java
index 7ca38c9..e94c5af 100644
--- a/app/src/main/java/com/duqing/missions/ui/notifications/NotificationsFragment.java
+++ b/app/src/main/java/com/duqing/missions/ui/main/notifications/NotificationsFragment.java
@@ -1,4 +1,4 @@
-package com.duqing.missions.ui.notifications;
+package com.duqing.missions.ui.main.notifications;
import android.os.Bundle;
import android.view.LayoutInflater;
diff --git a/app/src/main/java/com/duqing/missions/ui/notifications/NotificationsViewModel.java b/app/src/main/java/com/duqing/missions/ui/main/notifications/NotificationsViewModel.java
similarity index 89%
rename from app/src/main/java/com/duqing/missions/ui/notifications/NotificationsViewModel.java
rename to app/src/main/java/com/duqing/missions/ui/main/notifications/NotificationsViewModel.java
index d28fa85..ed7c442 100644
--- a/app/src/main/java/com/duqing/missions/ui/notifications/NotificationsViewModel.java
+++ b/app/src/main/java/com/duqing/missions/ui/main/notifications/NotificationsViewModel.java
@@ -1,4 +1,4 @@
-package com.duqing.missions.ui.notifications;
+package com.duqing.missions.ui.main.notifications;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
diff --git a/app/src/main/java/com/duqing/missions/util/DeviceUtil.java b/app/src/main/java/com/duqing/missions/util/DeviceUtil.java
new file mode 100644
index 0000000..3679ee8
--- /dev/null
+++ b/app/src/main/java/com/duqing/missions/util/DeviceUtil.java
@@ -0,0 +1,374 @@
+package com.duqing.missions.util;
+
+import android.Manifest;
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.Point;
+import android.os.Build;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Display;
+import android.view.WindowManager;
+
+import androidx.core.app.ActivityCompat;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.math.BigDecimal;
+
+
+/**
+ * Created by EDZ on 2018/1/30.
+ */
+public class DeviceUtil {
+ public static final String TAG = "DeviceUtil";
+
+ /**
+ * 设备信息
+ *
+ * @param context
+ */
+ public static void getDisplay(Context context) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Version code is \n");
+ sb.append("设备的Android版本号:");//设备的Android版本号
+ sb.append(getSDKInt() + " " + getSDKVersion() + "\t");//设备的Android版本号
+ sb.append("设备型号:");//设备型号
+ sb.append(getDeviceModel() + "\t");//设备型号
+ sb.append("设备厂商:");//设备型号
+ sb.append(getDeviceBrand() + "\t");//设备型号
+ sb.append("程序版本号:" + getAppVersionCode(context) + " " + getAppVersionName(context) + "\t");//程序版本号
+ sb.append("设备唯一标识符:" + getSerialNumber(context));
+ sb.append("\n设备imei:" + getIMEI(context));
+ String str = sb.toString() + " \n";
+ str += getDisplayInfomation(context) + " \n";
+ str += getDensity(context) + " \n";
+ str += "屏幕大小:" + getScreenInch(context) + "英寸 \n";
+ str += getAndroiodScreenProperty(context) + "\n";
+ Log.i(TAG, str);
+ }
+
+ /**
+ * Double类型保留指定位数的小数,返回double类型(四舍五入)
+ * newScale 为指定的位数
+ */
+ private static double formatDouble(double d, int newScale) {
+ BigDecimal bd = new BigDecimal(d);
+ return bd.setScale(newScale, BigDecimal.ROUND_HALF_UP).doubleValue();
+ }
+
+ /**
+ * 设备型号
+ * @return
+ */
+ public static String getDeviceModel() {
+ return Build.MODEL;
+ }
+
+ /**
+ * 设备厂商
+ * @return
+ */
+ public static String getDeviceBrand() {
+ return Build.BRAND;
+ }
+
+ /**
+ * 设备的Android版本号
+ * @return
+ */
+ public static int getSDKInt() {
+ return Build.VERSION.SDK_INT;
+ }
+
+ /**
+ * 设备的Android版本号
+ * @return
+ */
+ public static String getSDKVersion() {
+ return Build.VERSION.RELEASE;
+ }
+
+ /**
+ * 程序版本号
+ * @param context
+ * @return
+ */
+ public static int getAppVersionCode(Context context) {
+ try {
+ return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode;
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ return 1;
+ }
+
+ /**
+ * 程序版本号
+ *
+ * @param context
+ * @return
+ */
+ public static String getAppVersionName(Context context) {
+ try {
+ return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+
+ /**
+ * 屏幕像素px
+ */
+ @SuppressLint("NewApi")
+ public static String getDisplayInfomation(Context context) {
+ Point point = new Point();
+ ((Activity) context).getWindowManager().getDefaultDisplay().getSize(point);
+ Log.d(TAG, "the screen size is " + point.toString());
+ ((Activity) context).getWindowManager().getDefaultDisplay().getRealSize(point);
+ Log.d(TAG, "the screen real size is " + point.toString());
+ return point.toString();
+ }
+
+ /**
+ * 屏幕信息
+ * @param context
+ * @return
+ */
+ public static String getAndroiodScreenProperty(Context context) {
+ int width = getScreenPixel(context).widthPixels; // 屏幕宽度(像素)
+ int height = getScreenPixel(context).heightPixels; // 屏幕高度(像素)
+ float density = getDensity(getScreenPixel(context)); // 屏幕密度(0.75 / 1.0 / 1.5)
+ int densityDpi = getDpi(context); // 屏幕密度dpi(120 / 160 / 240)
+ // 屏幕宽度算法:屏幕宽度(像素)/屏幕密度
+ int screenWidth = getDp(context)[0]; // 屏幕宽度(dp)
+ int screenHeight = getDp(context)[1];// 屏幕高度(dp)
+
+
+ Log.d("h_bl", "屏幕宽度(像素):" + width);
+ Log.d("h_bl", "屏幕高度(像素):" + height);
+ Log.d("h_bl", "屏幕密度(0.75 / 1.0 / 1.5):" + density);
+ Log.d("h_bl", "屏幕密度dpi(120 / 160 / 240):" + densityDpi);
+ Log.d("h_bl", "屏幕宽度(dp):" + screenWidth); // 屏幕适配文件夹(例:layout-sw300dp),是以该属性为准则
+ Log.d("h_bl", "屏幕高度(dp):" + screenHeight);
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("屏幕宽度(像素):" + width + "\n");
+ sb.append("屏幕高度(像素):" + height + "\n");
+ sb.append("屏幕密度(0.75 / 1.0 / 1.5):" + density + "\n");
+ sb.append("屏幕密度dpi(120 / 160 / 240):" + densityDpi + "\n");
+ sb.append("屏幕宽度(dp):" + screenWidth + "\n");
+ sb.append("屏幕高度(dp):" + screenHeight + "\n");
+ return sb.toString();
+
+ }
+
+ /**
+ * 通知栏高度
+ * @param context
+ * @return
+ */
+ public static int getStatusBarHeight(Context context) {
+ Class<?> c = null;
+ Object obj = null;
+ Field field = null;
+ int x = 0, statusBarHeight = 0;
+ try {
+ c = Class.forName("com.android.internal.R$dimen");
+ obj = c.newInstance();
+ field = c.getField("status_bar_height");
+ x = Integer.parseInt(field.get(obj).toString());
+ statusBarHeight = context.getResources().getDimensionPixelSize(x);
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ return statusBarHeight;
+ }
+
+ /**
+ * 屏幕密度dpi
+ */
+ public static int getDpi(Context context) {
+ WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ DisplayMetrics dm = new DisplayMetrics();
+ wm.getDefaultDisplay().getMetrics(dm);
+ return dm.densityDpi;
+ }
+
+
+ /**
+ * 屏幕像素px
+ */
+ @SuppressLint("NewApi")
+ public static Point getDisplayPixel(Context context) {
+ Point point = new Point();
+ ((Activity) context).getWindowManager().getDefaultDisplay().getSize(point);
+ Log.d(TAG, "the screen size is " + point.toString());
+ ((Activity) context).getWindowManager().getDefaultDisplay().getRealSize(point);
+ Log.d(TAG, "the screen real size is " + point.toString());
+ return point;
+ }
+
+ /**
+ * 屏幕像素px
+ */
+ public static DisplayMetrics getScreenPixel(Context context) {
+ WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ DisplayMetrics dm = new DisplayMetrics();
+ wm.getDefaultDisplay().getMetrics(dm);
+ return dm;
+ }
+
+ /**
+ * 屏幕dp
+ */
+ public static int[] getDp(Context context) {
+ int width = getScreenPixel(context).widthPixels; // 屏幕宽度(像素)
+ int height = getScreenPixel(context).heightPixels; // 屏幕高度(像素)
+ float density = getDensity(getScreenPixel(context)); // 屏幕密度(0.75 / 1.0 / 1.5)
+ // 屏幕宽度算法:屏幕宽度(像素)/屏幕密度
+ int screenWidth = (int) (width / density); // 屏幕宽度(dp)
+ int screenHeight = (int) (height / density);// 屏幕高度(dp)
+ return new int[]{screenWidth, screenHeight};
+ }
+
+ /**
+ * 屏幕密度
+ */
+ public static float getDensity(DisplayMetrics dm) {
+ return dm.density; // 屏幕密度(0.75 / 1.0 / 1.5);
+ }
+
+ /**
+ * 屏幕密度dpi
+ */
+ public static String getDensity(Context context) {
+ DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ Log.d(TAG, "Density is " + displayMetrics.density + " densityDpi is " + displayMetrics.densityDpi + " height: " + displayMetrics.heightPixels +
+ " width: " + displayMetrics.widthPixels);
+ return "Density is " + displayMetrics.density + " densityDpi is " + displayMetrics.densityDpi + " height: " + displayMetrics.heightPixels +
+ " width: " + displayMetrics.widthPixels;
+ }
+
+
+ /**
+ * 屏幕尺寸inch
+ */
+ public static double getScreenInch(Context context) {
+
+ try {
+ int realWidth = 0, realHeight = 0;
+ Display display = ((Activity) context).getWindowManager().getDefaultDisplay();
+ DisplayMetrics metrics = new DisplayMetrics();
+ display.getMetrics(metrics);
+ if (Build.VERSION.SDK_INT >= 17) {
+ Point size = new Point();
+ display.getRealSize(size);
+ realWidth = size.x;
+ realHeight = size.y;
+ } else if (Build.VERSION.SDK_INT < 17
+ && Build.VERSION.SDK_INT >= 14) {
+ Method mGetRawH = Display.class.getMethod("getRawHeight");
+ Method mGetRawW = Display.class.getMethod("getRawWidth");
+ realWidth = (Integer) mGetRawW.invoke(display);
+ realHeight = (Integer) mGetRawH.invoke(display);
+ } else {
+ realWidth = metrics.widthPixels;
+ realHeight = metrics.heightPixels;
+ }
+
+ return formatDouble(Math.sqrt((realWidth / metrics.xdpi) * (realWidth / metrics.xdpi) + (realHeight / metrics.ydpi) * (realHeight / metrics.ydpi)), 1);
+
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return 0;
+ }
+
+ /**
+ * dp获取dip
+ * @param dp
+ * @return
+ */
+ public static int convertDpToPixel(float dp, Context context) {
+ DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ return (int) (dp * displayMetrics.density);
+ }
+
+ /***
+ * px获取dip
+ * @param pixel
+ * @return
+ */
+ public static int convertPixelToDp(int pixel, Context context) {
+ DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ return (int) (pixel / displayMetrics.density);
+ }
+
+ public static String getSerialNumber(Context context) {
+ String serial = "";
+ try {
+ if (Build.VERSION.SDK_INT >= 28) {//9.0+
+ if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
+ Log.i(TAG, "getMEID meid: READ_PHONE_STATE" );
+ ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.READ_PHONE_STATE}, 1567);
+ } else {
+ serial = Build.getSerial();
+ }
+ } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {//8.0+
+ serial = Build.SERIAL;
+ } else {//8.0-
+ Class<?> c = Class.forName("android.os.SystemProperties");
+ Method get = c.getMethod("get", String.class);
+ serial = (String) get.invoke(c, "ro.serialno");
+ }
+ } catch (Exception e) {
+ Log.e("e", "读取设备序列号异常:" + e.toString());
+ }
+ return serial;
+ }
+
+ public static String getIMEI(Context context) {
+ String deviceId = "";
+ TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+ if (null != tm) {
+ if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
+ Log.i(TAG, "getMEID meid: READ_PHONE_STATE" );
+ ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.READ_PHONE_STATE}, 1567);
+ } else {
+ if (tm.getDeviceId() != null) {
+ deviceId = tm.getDeviceId();
+ } else {
+ deviceId = Settings.Secure.getString(context.getApplicationContext().getContentResolver(), Settings.Secure.ANDROID_ID);
+ }
+ }
+ Log.d("deviceId--->", deviceId);
+ }
+ return "";
+ }
+
+ public static String getMEID() {
+ try {
+ Class clazz = Class.forName("android.os.SystemProperties");
+ Method method = clazz.getMethod("get", String.class, String.class);
+
+ String meid = (String) method.invoke(null, "ril.cdma.meid", "");
+ if (!TextUtils.isEmpty(meid)) {
+ Log.d(TAG, "getMEID meid: " + meid);
+ return meid;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.w(TAG, "getMEID error : " + e.getMessage());
+ }
+ return "";
+ }
+}
diff --git a/app/src/main/java/com/duqing/missions/util/MyLog.java b/app/src/main/java/com/duqing/missions/util/MyLog.java
new file mode 100644
index 0000000..521c63f
--- /dev/null
+++ b/app/src/main/java/com/duqing/missions/util/MyLog.java
@@ -0,0 +1,42 @@
+package com.duqing.missions.util;
+
+import android.util.Log;
+
+import com.duqing.missions.BuildConfig;
+
+
+/**
+ * My father is Object, ites purpose of
+ *
+ * @purpose Created by Runt (qingingrunt2010@qq.com) on 2020-4-5.
+ */
+public class MyLog {
+
+
+ public static void i(String tag,String msg){
+ if(BuildConfig.DEBUG) {
+ Log.i(tag, BuildConfig.BUILD_TYPE +" "+ msg);
+ }
+ }
+
+ public static void e(String tag,String msg){
+ if(BuildConfig.DEBUG) {
+ Log.e(tag, msg);
+ }
+ }
+
+
+ public static void d(String tag,String msg){
+ if(BuildConfig.DEBUG) {
+ Log.d(tag, msg);
+ }
+ }
+
+
+ public static void v(String tag,String msg){
+ if(BuildConfig.DEBUG) {
+ Log.v(tag, msg);
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/duqing/missions/util/ResPonse.java b/app/src/main/java/com/duqing/missions/util/ResPonse.java
new file mode 100644
index 0000000..e7e53b5
--- /dev/null
+++ b/app/src/main/java/com/duqing/missions/util/ResPonse.java
@@ -0,0 +1,15 @@
+package com.duqing.missions.util;
+
+import java.io.Serializable;
+
+/**
+ * Created by Administrator on 2018/5/25.
+ */
+
+public abstract class ResPonse<T> implements Serializable {
+
+ public abstract void doSuccess(T obj);
+
+ public void doError(T obj){};
+
+}
diff --git a/app/src/main/java/com/duqing/missions/util/SpUtils.java b/app/src/main/java/com/duqing/missions/util/SpUtils.java
new file mode 100644
index 0000000..f3fd2fd
--- /dev/null
+++ b/app/src/main/java/com/duqing/missions/util/SpUtils.java
@@ -0,0 +1,476 @@
+package com.duqing.missions.util;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import androidx.collection.ArraySet;
+
+import java.util.Set;
+
+/**
+ * Created by Administrator on 2021/10/28 0028.
+ */
+public class SpUtils {
+
+ static SpUtils instance;
+
+ /**
+ * 获取SP实例
+ *
+ * @return {@link SpUtils}
+ */
+ public static SpUtils getInstance() {
+ if(instance == null){
+ instance = new SpUtils();
+ }
+ return instance;
+ }
+
+
+ public final String PROJECT = "project";
+ public final String USER = "user";
+
+
+ public boolean clearData(Context context, String keyShared){
+ SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE);
+ return settings.edit().clear().commit();
+ }
+
+
+ public 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 Set getStringSet(Context context, String key, Set defaultValue, String keyShared) {
+ SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE);
+ return settings.getStringSet(key, defaultValue);
+ }
+
+ public boolean getBooleanValOfUser(Context context, String key){
+ return getBoolean(context,key,false,USER);
+ }
+
+ public boolean getBooleanValOfProject(Context context, String key){
+ return getBoolean(context,key,false,PROJECT);
+ }
+
+ public String getStringValOfUser(Context context, String key){
+ return getString(context,key,"",USER);
+ }
+
+ public String getStringValOfProject(Context context, String key){
+ return getString(context,key,"",PROJECT);
+ }
+
+ public int getIntValOfProject(Context context, String key){
+ return getInt(context,key,0,PROJECT);
+ }
+
+ public Long getLongValOfProject(Context context, String key){
+ return getLong(context,key,0,PROJECT);
+ }
+
+ public float getFloatValOfProject(Context context, String key){
+ return getFloat(context,key,0,PROJECT);
+ }
+
+ public Set getStringSetValOfProject(Context context, String key){
+ return getStringSet(context,key,PROJECT);
+ }
+
+ public int getIntValOfUser(Context context, String key){
+ return getInt(context,key,0,USER);
+ }
+
+ public Long getLongValOfUser(Context context, String key){
+ return getLong(context,key,0,USER);
+ }
+
+ public float getFloatValOfUser(Context context, String key){
+ return getFloat(context,key,0,USER);
+ }
+
+ public Set getStringSetValOfUser(Context context, String key){
+ return getStringSet(context,key,USER);
+ }
+
+
+ public void putBooleanValOfUser(Context context, String key ,Boolean value){
+ putBoolean(context,key,value,USER);
+ }
+
+ public void putBooleanValOfProject(Context context, String key,Boolean value){
+ putBoolean(context,key,value,PROJECT);
+ }
+
+ public void putStringValOfUser(Context context,String key,String value){
+ putString(context,key,value,USER);
+ }
+
+ public void putStringValOfProject(Context context,String key,String value){
+ putString(context,key,value,PROJECT);
+ }
+
+ public void putIntValOfProject(Context context,String key,int value){
+ putInt(context,key,value,PROJECT);
+ }
+
+ public void putLongValOfProject(Context context,String key,long value){
+ putLong(context,key,value,PROJECT);
+ }
+
+ public void putFloatValOfProject(Context context,String key,float value){
+ putFloat(context,key,value,PROJECT);
+ }
+
+ public void putStringSetValOfProject(Context context,String key,Set value){
+ putStringSet(context,key,value,PROJECT);
+ }
+
+ public void putIntValOfUser(Context context,String key,int value){
+ putInt(context,key,value,USER);
+ }
+
+ public void putLongValOfUser(Context context,String key,long value){
+ putLong(context,key,value,USER);
+ }
+
+ public void putFloatValOfUser(Context context,String key,float value){
+ putFloat(context,key,value,USER);
+ }
+
+ public void putStringSetValOfUser(Context context,String key, Set value){
+ putStringSet(context,key,value,USER);
+ }
+
+
+ public void removeUserKey(Context context, String key){
+ removeKey(context,key,USER);
+ }
+
+ public void removeProjectKey(Context context, String key){
+ removeKey(context,key,PROJECT);
+ }
+
+ public void removeUserValue(Context context, String Value){
+ removeValue(context,Value,USER);
+ }
+
+ public void removeProjectValue(Context context, String Value){
+ removeValue(context,Value,PROJECT);
+ }
+
+
+ public void clearProjectData(Context context){
+ clearData(context,PROJECT);
+ }
+ public void clearUserData(Context context){
+ clearData(context,USER);
+ }
+
+}
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 035ff13..177d7d2 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,34 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container"
android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <com.google.android.material.bottomnavigation.BottomNavigationView
- android:id="@+id/nav_view"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginStart="0dp"
- android:layout_marginEnd="0dp"
- android:background="?android:attr/windowBackground"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintRight_toRightOf="parent"
- app:menu="@menu/bottom_nav_menu"/>
+ android:layout_height="match_parent"
+ android:orientation="vertical">
<fragment
android:id="@+id/nav_host_fragment_activity_main"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:layout_weight="1"
app:defaultNavHost="true"
- app:layout_constraintBottom_toTopOf="@id/nav_view"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/mobile_navigation"
/>
-</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
+ <com.google.android.material.bottomnavigation.BottomNavigationView
+ android:id="@+id/nav_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/windowBackground"
+ app:menu="@menu/bottom_nav_menu"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_dashboard.xml b/app/src/main/res/layout/fragment_dashboard.xml
index c55e1b8..f1fff12 100644
--- a/app/src/main/res/layout/fragment_dashboard.xml
+++ b/app/src/main/res/layout/fragment_dashboard.xml
@@ -5,7 +5,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context=".ui.dashboard.DashboardFragment" >
+ tools:context=".ui.main.dashboard.DashboardFragment" >
<com.google.android.material.tabs.TabLayout
android:id="@+id/tablayout"
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
index 47973db..6ed5bfb 100644
--- a/app/src/main/res/layout/fragment_home.xml
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
+<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"
tools:ignore="MissingConstraints"
- tools:context=".ui.home.HomeFragment"
+ tools:context=".ui.main.home.HomeFragment"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent">
@@ -12,11 +12,17 @@
android:id="@+id/img_search"
android:layout_width="39dp"
android:layout_height="35dp"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/smart_refresh"
android:src="@android:drawable/ic_search_category_default"/>
<com.scwang.smart.refresh.layout.SmartRefreshLayout
android:id="@+id/smart_refresh"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="0dp"
+ app:layout_constraintTop_toBottomOf="@id/img_search"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
>
<androidx.constraintlayout.widget.ConstraintLayout
@@ -28,6 +34,7 @@
android:id="@+id/recycler_top"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:overScrollMode="never"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:spanCount="3"
tools:itemCount="3"
@@ -38,6 +45,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
+ android:overScrollMode="never"
tools:listitem="@layout/home_item_classify"
app:layout_constraintTop_toBottomOf="@id/recycler_top"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
@@ -61,6 +69,7 @@
android:id="@+id/recycler_recommend"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:overScrollMode="never"
tools:listitem="@layout/homt_item_recommend"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_recommend"
@@ -69,4 +78,4 @@
</androidx.constraintlayout.widget.ConstraintLayout>
</com.scwang.smart.refresh.layout.SmartRefreshLayout>
-</LinearLayout>
\ No newline at end of file
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_notifications.xml b/app/src/main/res/layout/fragment_notifications.xml
index 47368bf..734378a 100644
--- a/app/src/main/res/layout/fragment_notifications.xml
+++ b/app/src/main/res/layout/fragment_notifications.xml
@@ -6,7 +6,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white_2"
- tools:context=".ui.notifications.NotificationsFragment">
+ tools:context=".ui.main.notifications.NotificationsFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml
index 567dacb..ebb9ec8 100644
--- a/app/src/main/res/navigation/mobile_navigation.xml
+++ b/app/src/main/res/navigation/mobile_navigation.xml
@@ -7,19 +7,19 @@
<fragment
android:id="@+id/navigation_home"
- android:name="com.duqing.missions.ui.home.HomeFragment"
+ android:name="com.duqing.missions.ui.main.home.HomeFragment"
android:label="@string/title_home"
tools:layout="@layout/fragment_home" />
<fragment
android:id="@+id/navigation_dashboard"
- android:name="com.duqing.missions.ui.dashboard.DashboardFragment"
+ android:name="com.duqing.missions.ui.main.dashboard.DashboardFragment"
android:label="@string/title_dashboard"
tools:layout="@layout/fragment_dashboard" />
<fragment
android:id="@+id/navigation_notifications"
- android:name="com.duqing.missions.ui.notifications.NotificationsFragment"
+ android:name="com.duqing.missions.ui.main.notifications.NotificationsFragment"
android:label="@string/title_notifications"
tools:layout="@layout/fragment_notifications" />
</navigation>
\ No newline at end of file
--
Gitblit v1.9.1