Просмотр исходного кода

首页消息红点
学生端选择声部
修改绑定银行卡部分
网络检测
设备检测

Ryan8057 2 лет назад
Родитель
Сommit
2c448be1a0
100 измененных файлов с 5301 добавлено и 57 удалено
  1. 51 0
      BaseLibrary/src/main/java/com/cooleshow/base/bean/EquipmentTestingBean.java
  2. 287 0
      BaseLibrary/src/main/java/com/cooleshow/base/recorder/AudioRecorder.java
  3. 3 0
      BaseLibrary/src/main/java/com/cooleshow/base/router/RouterPath.kt
  4. 27 0
      BaseLibrary/src/main/java/com/cooleshow/base/utils/FileUtils.java
  5. 227 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/BaseDialog.java
  6. 72 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/CommonDialog.java
  7. 89 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/DensityUtil.java
  8. 32 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/DialogUtil.java
  9. 315 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/RoundProgressBar.java
  10. 41 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/ViewConvertListener.java
  11. 64 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/ViewHolder.java
  12. 39 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/LoadDialog.java
  13. 123 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/SpinKitView.java
  14. 31 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/SpriteFactory.java
  15. 18 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/Style.java
  16. 54 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/AnimationUtils.java
  17. 46 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/FloatProperty.java
  18. 46 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/IntProperty.java
  19. 215 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/SpriteAnimatorBuilder.java
  20. 12 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/interpolator/Ease.java
  21. 54 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/interpolator/KeyFrameInterpolator.java
  22. 87 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/interpolator/PathInterpolatorCompat.java
  23. 49 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/interpolator/PathInterpolatorCompatApi21.java
  24. 43 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/interpolator/PathInterpolatorCompatBase.java
  25. 111 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/interpolator/PathInterpolatorDonut.java
  26. 36 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/sprite/CircleLayoutContainer.java
  27. 26 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/sprite/CircleSprite.java
  28. 66 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/sprite/ShapeSprite.java
  29. 455 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/sprite/Sprite.java
  30. 109 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/sprite/SpriteContainer.java
  31. 50 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/style/Circle.java
  32. 47 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/style/FadingCircle.java
  33. 73 0
      BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/style/ThreeBounce.java
  34. BIN
      BaseLibrary/src/main/res/drawable-xxhdpi/ic_dash_line.png
  35. BIN
      BaseLibrary/src/main/res/drawable-xxhdpi/ic_network_error.png
  36. BIN
      BaseLibrary/src/main/res/drawable-xxhdpi/icon_testing_closea.png
  37. BIN
      BaseLibrary/src/main/res/drawable-xxhdpi/icon_testing_default.png
  38. BIN
      BaseLibrary/src/main/res/drawable-xxhdpi/icon_testing_success.png
  39. BIN
      BaseLibrary/src/main/res/drawable-xxhdpi/icon_testing_wait.png
  40. 6 0
      BaseLibrary/src/main/res/drawable/bg_white_default_shape.xml
  41. 5 0
      BaseLibrary/src/main/res/drawable/shape_corner.xml
  42. 132 0
      BaseLibrary/src/main/res/layout/common_popu_stu.xml
  43. 34 0
      BaseLibrary/src/main/res/layout/load.xml
  44. 3 0
      BaseLibrary/src/main/res/values/colors.xml
  45. 1 0
      BaseLibrary/src/main/res/values/strings.xml
  46. 96 0
      BaseLibrary/src/main/res/values/styles.xml
  47. 12 1
      student/src/main/AndroidManifest.xml
  48. 68 0
      student/src/main/java/com/cooleshow/student/adapter/TeachableInstrumentAdapter.java
  49. 63 0
      student/src/main/java/com/cooleshow/student/adapter/TeachableInstrumentItemAdapter.java
  50. 115 0
      student/src/main/java/com/cooleshow/student/adapter/TestingListAdapter.java
  51. 26 0
      student/src/main/java/com/cooleshow/student/api/APIService.java
  52. 55 0
      student/src/main/java/com/cooleshow/student/bean/TeachableInstrumentBean.java
  53. 3 3
      student/src/main/java/com/cooleshow/student/bean/weixinpay/WeixinPayInfo.java
  54. 17 0
      student/src/main/java/com/cooleshow/student/contract/EquipmentTestContract.java
  55. 11 0
      student/src/main/java/com/cooleshow/student/contract/HomeContract.java
  56. 17 0
      student/src/main/java/com/cooleshow/student/contract/NetworkMonitoringContract.java
  57. 23 0
      student/src/main/java/com/cooleshow/student/contract/TeachableInstrumentContract.java
  58. 51 0
      student/src/main/java/com/cooleshow/student/presenter/main/HomePresenter.java
  59. 13 0
      student/src/main/java/com/cooleshow/student/presenter/mine/EquipmentTestPresenter.java
  60. 14 0
      student/src/main/java/com/cooleshow/student/presenter/mine/NetworkMonitoringPresenter.java
  61. 56 0
      student/src/main/java/com/cooleshow/student/presenter/mine/TeachableInstrumentPresenter.java
  62. 84 8
      student/src/main/java/com/cooleshow/student/ui/main/HomeFragment.java
  63. 17 0
      student/src/main/java/com/cooleshow/student/ui/main/MainActivity.java
  64. 38 2
      student/src/main/java/com/cooleshow/student/ui/main/MineFragment.java
  65. 394 0
      student/src/main/java/com/cooleshow/student/ui/mine/EquipmentTestActivity.java
  66. 359 0
      student/src/main/java/com/cooleshow/student/ui/mine/NetworkMonitoringActivity.java
  67. 6 42
      student/src/main/java/com/cooleshow/student/ui/mine/PayTestActivity.java
  68. 150 0
      student/src/main/java/com/cooleshow/student/ui/mine/TeachableInstrumentActivity.java
  69. 1 1
      student/src/main/java/com/cooleshow/student/wxapi/WXPayEntryActivity.java
  70. BIN
      student/src/main/res/drawable-xhdpi/icon_check_normal.png
  71. BIN
      student/src/main/res/drawable-xhdpi/icon_check_select.png
  72. BIN
      student/src/main/res/drawable-xhdpi/icon_device_initialize.png
  73. BIN
      student/src/main/res/drawable-xhdpi/icon_line_initialize.png
  74. BIN
      student/src/main/res/drawable-xhdpi/icon_line_test_initialize.png
  75. BIN
      student/src/main/res/drawable-xhdpi/icon_network_normal.png
  76. BIN
      student/src/main/res/drawable-xhdpi/icon_recorder_success.png
  77. BIN
      student/src/main/res/drawable-xhdpi/icon_root_initialize.png
  78. BIN
      student/src/main/res/drawable-xhdpi/icon_testing_network.png
  79. BIN
      student/src/main/res/drawable-xhdpi/icon_testing_notice.png
  80. BIN
      student/src/main/res/drawable-xhdpi/icon_testing_phone.png
  81. BIN
      student/src/main/res/drawable-xhdpi/icon_testing_play.png
  82. BIN
      student/src/main/res/drawable-xhdpi/icon_testing_recorder.png
  83. BIN
      student/src/main/res/drawable-xxhdpi/icon_check_normal.png
  84. BIN
      student/src/main/res/drawable-xxhdpi/icon_check_select.png
  85. BIN
      student/src/main/res/drawable-xxhdpi/icon_device_initialize.png
  86. BIN
      student/src/main/res/drawable-xxhdpi/icon_line_initialize.png
  87. BIN
      student/src/main/res/drawable-xxhdpi/icon_line_test_initialize.png
  88. BIN
      student/src/main/res/drawable-xxhdpi/icon_network_normal.png
  89. BIN
      student/src/main/res/drawable-xxhdpi/icon_recorder_success.png
  90. BIN
      student/src/main/res/drawable-xxhdpi/icon_root_initialize.png
  91. BIN
      student/src/main/res/drawable-xxhdpi/icon_testing_network.png
  92. BIN
      student/src/main/res/drawable-xxhdpi/icon_testing_notice.png
  93. BIN
      student/src/main/res/drawable-xxhdpi/icon_testing_phone.png
  94. BIN
      student/src/main/res/drawable-xxhdpi/icon_testing_play.png
  95. BIN
      student/src/main/res/drawable-xxhdpi/icon_testing_recorder.png
  96. 7 0
      student/src/main/res/drawable/border_corner_2dc7aa.xml
  97. 8 0
      student/src/main/res/drawable/mark_2dc7aa_3radius.xml
  98. 135 0
      student/src/main/res/layout/activity_equipment_test.xml
  99. 239 0
      student/src/main/res/layout/activity_network_monitoring.xml
  100. 44 0
      student/src/main/res/layout/activity_teachable_instrument.xml

+ 51 - 0
BaseLibrary/src/main/java/com/cooleshow/base/bean/EquipmentTestingBean.java

@@ -0,0 +1,51 @@
+package com.cooleshow.base.bean;
+
+/**
+ * Description:
+ * Copyright  : Copyright (c) 2019
+ * Company    : 大雅乐盟
+ * Author     : r
+ * Date       : 2019/9/11 18:31
+ */
+public class EquipmentTestingBean {
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    private String name;
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    private String content;
+
+    public int getState() {
+        return state;
+    }
+
+    public void setState(int state) {
+        this.state = state;
+    }
+
+    private int state;
+
+    public int getIcon() {
+        return icon;
+    }
+
+    public void setIcon(int icon) {
+        this.icon = icon;
+    }
+
+    private int icon;
+
+}

+ 287 - 0
BaseLibrary/src/main/java/com/cooleshow/base/recorder/AudioRecorder.java

@@ -0,0 +1,287 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016 Piasy
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.cooleshow.base.recorder;
+
+import android.media.MediaRecorder;
+import android.util.Log;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.WorkerThread;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Encapsulate {@link MediaRecorder},
+ * <em>NOTE: To avoid multi-thread call on native method which causing silent crash like:
+ * A/libc: Fatal signal 11 (SIGSEGV) at 0x00000010 (code=1), thread 9302 (RxComputationTh)
+ * this class simply use singleton and synchronized to keep thread safety.
+ * refer to the comment under StackOverflow question:
+ * http://stackoverflow.com/questions/14023291/fatal-signal-11-sigsegv-at-0x00000000-code-1-phonegap
+ * </em>
+ */
+
+@SuppressWarnings({"unused", "WeakerAccess", "UnusedReturnValue"})
+public final class AudioRecorder {
+    public static final int DEFAULT_SAMPLE_RATE = 44100;
+    public static final int DEFAULT_BIT_RATE    = 192000;
+    public static final int ERROR_SDCARD_ACCESS = 1;
+    public static final int ERROR_INTERNAL      = 2;
+    public static final int ERROR_NOT_PREPARED  = 3;
+
+    private static final String TAG                            = "AudioRecorder";
+    private static final int    STOP_AUDIO_RECORD_DELAY_MILLIS = 300;
+    private static final int    STATE_IDLE                     = 0;
+    private static final int    STATE_PREPARED                 = 1;
+    private static final int    STATE_RECORDING                = 2;
+
+    private int             mState       = STATE_IDLE;
+    private OnErrorListener mOnErrorListener;
+    private long            mSampleStart = 0;       // time at which latest record or play operation started
+    private MediaRecorder   mRecorder;
+    private boolean         mStarted     = false;
+
+    private AudioRecorder() {
+        // singleton
+    }
+
+    public static AudioRecorder getInstance() {
+        return RxAndroidAudioHolder.INSTANCE;
+    }
+
+    public void setOnErrorListener(OnErrorListener listener) {
+        mOnErrorListener = listener;
+    }
+
+    public synchronized int getMaxAmplitude() {
+        if (mState != STATE_RECORDING) {
+            return 0;
+        }
+        try {
+            return mRecorder.getMaxAmplitude();
+        } catch (Exception e) {
+            return 0;
+        }
+
+    }
+
+    public int progress() {
+        if (mState == STATE_RECORDING) {
+            return (int) ((System.currentTimeMillis() - mSampleStart) / 1000);
+        }
+        return 0;
+    }
+
+    /**
+     * Directly start record, including prepare and start.
+     * MediaRecorder.AudioSource.MIC
+     * MediaRecorder.OutputFormat.MPEG_4
+     * MediaRecorder.AudioEncoder.AAC
+     */
+    @WorkerThread
+    public synchronized boolean startRecord(int audioSource, int outputFormat, int audioEncoder,
+                                            int sampleRate, int bitRate, File outputFile) {
+        stopRecord();
+
+        mRecorder = new MediaRecorder();
+        mRecorder.setAudioSource(audioSource);
+        mRecorder.setOutputFormat(outputFormat);
+        mRecorder.setAudioSamplingRate(sampleRate);
+        mRecorder.setAudioEncodingBitRate(bitRate);
+        mRecorder.setAudioEncoder(audioEncoder);
+        mRecorder.setOutputFile(outputFile.getAbsolutePath());
+
+        // Handle IOException
+        try {
+            mRecorder.prepare();
+        } catch (IOException | RuntimeException exception) {
+            Log.w(TAG, "startRecord fail, prepare fail: " + exception.getMessage());
+            setError(ERROR_INTERNAL);
+            mRecorder.reset();
+            mRecorder.release();
+            mRecorder = null;
+            return false;
+        }
+        // Handle RuntimeException if the recording couldn't start
+        try {
+            mRecorder.start();
+            mStarted = true;
+        } catch (RuntimeException exception) {
+            Log.w(TAG, "startRecord fail, start fail: " + exception.getMessage());
+            setError(ERROR_INTERNAL);
+            mRecorder.reset();
+            mRecorder.release();
+            mRecorder = null;
+            mStarted = false;
+            return false;
+        }
+        mSampleStart = System.currentTimeMillis();
+        mState = STATE_RECORDING;
+        return true;
+    }
+
+    /**
+     * prepare for a new audio record, with default sample rate and bit rate.
+     */
+    @WorkerThread
+    public synchronized boolean prepareRecord(int audioSource, int outputFormat, int audioEncoder,
+                                              File outputFile) {
+        return prepareRecord(audioSource, outputFormat, audioEncoder, DEFAULT_SAMPLE_RATE,
+                DEFAULT_BIT_RATE, outputFile);
+    }
+
+    /**
+     * prepare for a new audio record.
+     */
+    @WorkerThread
+    public synchronized boolean prepareRecord(int audioSource, int outputFormat, int audioEncoder,
+                                              int sampleRate, int bitRate, File outputFile) {
+        stopRecord();
+
+        mRecorder = new MediaRecorder();
+        mRecorder.setAudioSource(audioSource);//音频来源
+        mRecorder.setOutputFormat(outputFormat);//输入编码格式
+        mRecorder.setAudioSamplingRate(sampleRate);//设置采样率
+        mRecorder.setAudioEncodingBitRate(bitRate);//设置录音的音频编码比特率
+        mRecorder.setAudioEncoder(audioEncoder);//编码格式
+        mRecorder.setOutputFile(outputFile.getAbsolutePath());//文件保存路径名字
+
+        // Handle IOException
+        try {
+            mRecorder.prepare();
+        } catch (IOException exception) {
+            Log.w(TAG, "startRecord fail, prepare fail: " + exception.getMessage());
+            setError(ERROR_INTERNAL);
+            mRecorder.reset();
+            mRecorder.release();
+            mRecorder = null;
+            return false;
+        }
+        mState = STATE_PREPARED;
+        return true;
+    }
+
+    /**
+     * After prepared, start record now.
+     */
+    @WorkerThread
+    public synchronized boolean startRecord() {
+        if (mRecorder == null || mState != STATE_PREPARED) {
+            setError(ERROR_NOT_PREPARED);
+            return false;
+        }
+        // Handle RuntimeException if the recording couldn't start
+        try {
+            mRecorder.start();
+            mStarted = true;
+        } catch (RuntimeException exception) {
+            Log.w(TAG, "startRecord fail, start fail: " + exception.getMessage());
+            setError(ERROR_INTERNAL);
+            mRecorder.reset();
+            mRecorder.release();
+            mRecorder = null;
+            mStarted = false;
+            return false;
+        }
+        mSampleStart = System.currentTimeMillis();
+        mState = STATE_RECORDING;
+        return true;
+    }
+
+    /**
+     * stop record, and save audio file.
+     * @return record audio length in seconds, -1 if not a successful record.
+     */
+    @WorkerThread
+    public synchronized int stopRecord() {
+        if (mRecorder == null) {
+            mState = STATE_IDLE;
+            return -1;
+        }
+
+        int length = -1;
+        switch (mState) {
+            case STATE_RECORDING:
+                try {
+                    // seems to be a bug in Android's AAC based audio encoders
+                    // ref: http://stackoverflow.com/a/24092524/3077508
+                    Thread.sleep(STOP_AUDIO_RECORD_DELAY_MILLIS);
+                    mRecorder.stop();
+                    mStarted = false;
+                    length = (int) ((System.currentTimeMillis() - mSampleStart) / 1000);
+                } catch (RuntimeException e) {
+                    Log.w(TAG, "stopRecord fail, stop fail(no audio data recorded): " +
+                            e.getMessage());
+                } catch (InterruptedException e) {
+                    Log.w(TAG,
+                            "stopRecord fail, stop fail(InterruptedException): " + e.getMessage());
+                }
+                // fall down
+            case STATE_PREPARED:
+                // fall down
+            case STATE_IDLE:
+                // fall down
+            default:
+                try {
+                    mRecorder.reset();
+                } catch (RuntimeException e) {
+                    Log.w(TAG, "stopRecord fail, reset fail " + e.getMessage());
+                }
+                mRecorder.release();
+                mRecorder = null;
+                mState = STATE_IDLE;
+                break;
+        }
+
+        return length;
+    }
+
+    private void setError(int error) {
+        if (mOnErrorListener != null) {
+            mOnErrorListener.onError(error);
+        }
+    }
+
+    /* returns recorder is started or not */
+    public boolean isStarted() {
+        return mStarted;
+    }
+
+    @IntDef(value = {ERROR_SDCARD_ACCESS, ERROR_INTERNAL, ERROR_NOT_PREPARED})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Error {
+    }
+
+    public interface OnErrorListener {
+        @WorkerThread
+        void onError(@Error int error);
+    }
+
+    private static class RxAndroidAudioHolder {
+        private static final AudioRecorder INSTANCE = new AudioRecorder();
+    }
+}

+ 3 - 0
BaseLibrary/src/main/java/com/cooleshow/base/router/RouterPath.kt

@@ -71,6 +71,7 @@ object RouterPath {
             const val TEACHER_MINE_WITHDRAWAL = "/teacher/ui/income/WithdrawalActivity"
             const val TEACHER_MINE_WITHDRAWAL_SUCCESS = "/teacher/ui/income/WithdrawalSuccessActivity"
             const val TEACHER_MINE_WITHDRAWAL_RECORD = "/teacher/ui/income/WithdrawalRecordActivity"
+            const val TEACHER_MINE_EARNING_STATISTICS= "/teacher/ui/income/EarningStatisticsActivity"
         }
     }
     //消息模块
@@ -119,6 +120,8 @@ object RouterPath {
             const val MINE_BIND_CARD_SUCCESS = "/teacher/ui/mine/BindCardSuccessActivity"
             const val TEACHER_MINE_CREATE_COURSE = "/teacher/ui/mine/CreateLiveActivity"
             const val MINE_PAY_TEST = "/teacher/ui/mine/PayTestActivity"
+            const val MINE_NETWORK_MONITORING = "/ui/mine/NetworkMonitoringActivity"
+            const val MINE_EQUIPMENT_TEST = "/ui/mine/EquipmentTestActivity"
         }
     }
 }

+ 27 - 0
BaseLibrary/src/main/java/com/cooleshow/base/utils/FileUtils.java

@@ -51,6 +51,11 @@ public final class FileUtils {
     public static final String examDownloadDirectory = "examDownload";
     private static final String LINE_SEP = System.getProperty("line.separator");
 
+    public static String getCacheDir(Context context) {
+        String cacheDir = context.getExternalCacheDir().getAbsolutePath();
+        return cacheDir;
+    }
+
     private FileUtils() {
         throw new UnsupportedOperationException("u can't instantiate me...");
     }
@@ -542,7 +547,29 @@ public final class FileUtils {
     private static boolean deleteFile(final File file) {
         return file != null && (!file.exists() || file.isFile() && file.delete());
     }
+    /**
+     * 删除文件
+     *
+     * @param file
+     */
+    public static void deleteFile1(File file) {
+        try {
+            if (!file.exists()) {
+                return;
+            }
+            if (file.isFile()) {
+                file.delete();
+            } else if (file.isDirectory()) {
+                File files[] = file.listFiles();
+                for (int i = 0; i < files.length; i++) {
+                    deleteFile(files[i]);
+                }
+            }
+            file.delete();
+        } catch (Exception e) {
+        }
 
+    }
     /**
      * Delete the all in directory.
      *

+ 227 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/BaseDialog.java

@@ -0,0 +1,227 @@
+package com.cooleshow.base.widgets;
+
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+
+import androidx.annotation.LayoutRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.StyleRes;
+import androidx.fragment.app.DialogFragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentTransaction;
+
+import com.cooleshow.base.R;
+
+
+/**
+ * Dialog通用样式
+ */
+public abstract class BaseDialog extends DialogFragment {
+
+    private static final String MARGIN  = "margin";
+    private static final String WIDTH   = "width";
+    private static final String HEIGHT  = "height";
+    private static final String DIM     = "dim_amount";
+    private static final String GRAVITY = "gravity";
+    private static final String CANCEL  = "out_cancel";
+    private static final String THEME   = "theme";
+    private static final String ANIM    = "anim_style";
+    private static final String LAYOUT  = "layout_id";
+
+    private   int     margin;//左右边距
+    private   int     width;//宽度
+    private   int     height;//高度
+    private   float   dimAmount = 0.5f;//灰度深浅
+    private   int     gravity   = Gravity.CENTER;//显示的位置
+    private   boolean outCancel = true;//是否点击外部取消
+    @StyleRes
+    protected int     theme     = R.style.BaseDialog; // dialog主题
+    @StyleRes
+    private   int     animStyle;
+    @LayoutRes
+    protected int     layoutId;
+
+    public abstract int intLayoutId();
+
+    public abstract void convertView(ViewHolder holder, BaseDialog dialog);
+
+    public int initTheme() {
+        return theme;
+    }
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setStyle(DialogFragment.STYLE_NO_TITLE, initTheme());
+
+        //恢复保存的数据
+        if (savedInstanceState != null) {
+            margin = savedInstanceState.getInt(MARGIN);
+            width = savedInstanceState.getInt(WIDTH);
+            height = savedInstanceState.getInt(HEIGHT);
+            dimAmount = savedInstanceState.getFloat(DIM);
+            gravity = savedInstanceState.getInt(GRAVITY);
+            outCancel = savedInstanceState.getBoolean(CANCEL);
+            theme = savedInstanceState.getInt(THEME);
+            animStyle = savedInstanceState.getInt(ANIM);
+            layoutId = savedInstanceState.getInt(LAYOUT);
+        }
+    }
+
+    @Nullable
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+        layoutId = intLayoutId();
+        View view = inflater.inflate(layoutId, container, false);
+        convertView(ViewHolder.create(view), this);
+        return view;
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        initParams();
+    }
+
+
+    /**
+     * 屏幕旋转等导致DialogFragment销毁后重建时保存数据
+     * @param outState
+     */
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putInt(MARGIN, margin);
+        outState.putInt(WIDTH, width);
+        outState.putInt(HEIGHT, height);
+        outState.putFloat(DIM, dimAmount);
+        outState.putInt(GRAVITY, gravity);
+        outState.putBoolean(CANCEL, outCancel);
+        outState.putInt(THEME, theme);
+        outState.putInt(ANIM, animStyle);
+        outState.putInt(LAYOUT, layoutId);
+    }
+
+    @Override
+    public void onConfigurationChanged(@NonNull Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        initParams();
+    }
+
+    private void initParams() {
+        Window window = getDialog().getWindow();
+        if (window != null) {
+            WindowManager.LayoutParams lp = window.getAttributes();
+            //调节灰色背景透明度[0-1],默认0.5f
+            lp.dimAmount = dimAmount;
+            if (gravity != 0) {
+                lp.gravity = gravity;
+            }
+            switch (gravity) {
+                case Gravity.LEFT:
+                case (Gravity.LEFT | Gravity.BOTTOM):
+                case (Gravity.LEFT | Gravity.TOP):
+                    if (animStyle == 0) {
+                        animStyle = R.style.LeftAnimation;
+                    }
+                    break;
+                case Gravity.TOP:
+                    if (animStyle == 0) {
+                        animStyle = R.style.TopAnimation;
+                    }
+                    break;
+                case Gravity.RIGHT:
+                case (Gravity.RIGHT | Gravity.BOTTOM):
+                case (Gravity.RIGHT | Gravity.TOP):
+                    if (animStyle == 0) {
+                        animStyle = R.style.RightAnimation;
+                    }
+                    break;
+                case Gravity.BOTTOM:
+                    if (animStyle == 0) {
+                        animStyle = R.style.BottomAnimation;
+                    }
+                    break;
+                default:
+                    break;
+
+            }
+
+            //设置dialog宽度
+            if (width == 0) {
+                lp.width = DensityUtil.getScreenWidth(getContext()) - 2 * DensityUtil.dp2px(getContext(), margin);
+            } else if (width == -1) {
+                lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
+            } else {
+                lp.width = DensityUtil.dp2px(getContext(), width);
+            }
+
+            //设置dialog高度
+            if (height == 0) {
+                lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
+            } else {
+                lp.height = DensityUtil.dp2px(getContext(), height);
+            }
+
+            //设置dialog进入、退出的动画
+            window.setWindowAnimations(animStyle);
+            window.setAttributes(lp);
+        }
+        setCancelable(outCancel);
+    }
+
+    public BaseDialog setMargin(int margin) {
+        this.margin = margin;
+        return this;
+    }
+
+    public BaseDialog setWidth(int width) {
+        this.width = width;
+        return this;
+    }
+
+    public BaseDialog setHeight(int height) {
+        this.height = height;
+        return this;
+    }
+
+    public BaseDialog setDimAmount(float dimAmount) {
+        this.dimAmount = dimAmount;
+        return this;
+    }
+
+    public BaseDialog setGravity(int gravity) {
+        this.gravity = gravity;
+        return this;
+    }
+
+    public BaseDialog setOutCancel(boolean outCancel) {
+        this.outCancel = outCancel;
+        return this;
+    }
+
+    public BaseDialog setAnimStyle(@StyleRes int animStyle) {
+        this.animStyle = animStyle;
+        return this;
+    }
+
+    public BaseDialog show(FragmentManager manager) {
+
+        FragmentTransaction ft = manager.beginTransaction();
+        if (this.isAdded()) {
+            ft.remove(this).commit();
+        }
+        ft.add(this, String.valueOf(System.currentTimeMillis()));
+        ft.addToBackStack(null); // 为解决该问题  Can not perform this action after onSaveInstanceState
+        ft.commitAllowingStateLoss();
+        return this;
+    }
+
+}

+ 72 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/CommonDialog.java

@@ -0,0 +1,72 @@
+package com.cooleshow.base.widgets;
+
+import android.os.Bundle;
+
+import androidx.annotation.LayoutRes;
+import androidx.annotation.Nullable;
+import androidx.annotation.StyleRes;
+
+public class CommonDialog extends BaseDialog {
+    private ViewConvertListener convertListener;
+
+    public static CommonDialog init() {
+        return new CommonDialog();
+    }
+
+    @Override
+    public int initTheme() {
+        return theme;
+    }
+
+    @Override
+    public int intLayoutId() {
+        return layoutId;
+    }
+
+    @Override
+    public void convertView(ViewHolder holder, BaseDialog dialog) {
+        if (convertListener != null) {
+            convertListener.convertView(holder, dialog);
+        }
+    }
+
+    public CommonDialog setTheme(@StyleRes int theme) {
+        this.theme = theme;
+        return this;
+    }
+
+    public CommonDialog setLayoutId(@LayoutRes int layoutId) {
+        this.layoutId = layoutId;
+        return this;
+    }
+
+    public CommonDialog setConvertListener(ViewConvertListener convertListener) {
+        this.convertListener = convertListener;
+        return this;
+    }
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (savedInstanceState != null) {
+            convertListener = savedInstanceState.getParcelable("listener");
+        }
+    }
+
+    /**
+     * 保存接口
+     *
+     * @param outState
+     */
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putParcelable("listener", convertListener);
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        convertListener = null;
+    }
+}

+ 89 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/DensityUtil.java

@@ -0,0 +1,89 @@
+package com.cooleshow.base.widgets;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * dp,px 相互转化工具类
+ */
+public class DensityUtil {
+
+    private DensityUtil() {
+        throw new UnsupportedOperationException("cannot be instantiated");
+    }
+
+    /**
+     * dp转px
+     */
+    public static int dp2px(Context context, float dpVal) {
+        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                dpVal, context.getResources().getDisplayMetrics());
+    }
+
+    /**
+     * sp转px
+     */
+    public static int sp2px(Context context, float spVal) {
+        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
+                spVal, context.getResources().getDisplayMetrics());
+    }
+
+    /**
+     * px转dp
+     */
+    public static float px2dp(Context context, float pxVal) {
+        final float scale = context.getResources().getDisplayMetrics().density;
+        return (pxVal / scale);
+    }
+
+
+    /**
+     * px转sp
+     */
+    public static float px2sp(Context context, float pxVal) {
+        return (pxVal / context.getResources().getDisplayMetrics().scaledDensity);
+    }
+
+    /**
+     * px转dp
+     */
+    public static float getDensity(Context context) {
+        final float scale = context.getResources().getDisplayMetrics().density;
+        return scale;
+    }
+
+    public static int getScreenWidth(Context context) {
+        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+        int widthPixels = displayMetrics.widthPixels;
+        return widthPixels;
+    }
+
+    public static int getScreenHeight(Context context) {
+        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+        return displayMetrics.heightPixels;
+    }
+
+    public static void setViewSize(View view, int width, int height) {
+        ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
+        if (null == layoutParams)
+            return;
+        layoutParams.width = width;
+        layoutParams.height = height;
+        view.setLayoutParams(layoutParams);
+    }
+
+    /**
+     * 判断是否平板设备
+     * @param context
+     * @return true:平板,false:手机
+     */
+    private boolean isTabletDevice(Context context) {
+        return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >=
+                Configuration.SCREENLAYOUT_SIZE_LARGE;
+    }
+}
+

+ 32 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/DialogUtil.java

@@ -0,0 +1,32 @@
+package com.cooleshow.base.widgets;
+
+import android.view.Gravity;
+
+import androidx.fragment.app.FragmentManager;
+
+import com.cooleshow.base.utils.PopupUtil;
+
+/**
+ * 创建日期:2022/6/1 15:31
+ *
+ * @author Ryan
+ * 类说明:
+ */
+public class DialogUtil {
+    public interface ShowListener {
+        void onShow(ViewHolder holder, BaseDialog dialog);
+    }
+    /*居中显示*/
+    public static void showInCenter(FragmentManager fragmentmanager, int resourcesId, ShowListener showListener) {
+        CommonDialog.init().setLayoutId(resourcesId)
+                .setConvertListener(new ViewConvertListener() {
+                    @Override
+                    public void convertView(ViewHolder holder, BaseDialog dialog) {
+                        showListener.onShow(holder, dialog);
+                    }
+                })
+                .setDimAmount(0.5f)
+                .setGravity(Gravity.CENTER)
+                .show(fragmentmanager);
+    }
+}

+ 315 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/RoundProgressBar.java

@@ -0,0 +1,315 @@
+package com.cooleshow.base.widgets;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.graphics.Typeface;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.cooleshow.base.R;
+
+
+/**
+ *
+ * @author xiaanming
+ * http://blog.csdn.net/xiaanming/article/details/10298163
+ */
+public class RoundProgressBar extends View {
+    /**
+     * 画笔对象的引用
+     */
+    private Paint paint;
+
+    /**
+     * 圆环的颜色
+     */
+    private int roundColor;
+
+    /**
+     * 圆环进度的颜色
+     */
+    private int roundProgressColor;
+
+    /**
+     * 中间进度百分比的字符串的颜色
+     */
+    private int textColor;
+
+    /**
+     * 中间进度百分比的字符串的字体
+     */
+    private float textSize;
+
+    /**
+     * 圆环的宽度
+     */
+    private float roundWidth;
+
+    /**
+     * 最大进度
+     */
+    private int max;
+
+    /**
+     * 当前进度
+     */
+    private int     progress = 0;
+    /**
+     * 是否显示中间的进度
+     */
+    private boolean textIsDisplayable;
+
+    /**
+     * 进度的风格,实心或者空心
+     */
+    private int style;
+
+    /**
+     * 进度开始的角度数
+     */
+    private int startAngle;
+
+    private int    backColor;
+    private String type = "检测中";
+
+
+    public static final int STROKE = 0;
+    public static final int FILL   = 1;
+
+    public RoundProgressBar(Context context) {
+        this(context, null);
+    }
+
+    public RoundProgressBar(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public RoundProgressBar(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        paint = new Paint();
+
+
+        TypedArray mTypedArray = context.obtainStyledAttributes(attrs,
+                R.styleable.RoundProgressBar);
+
+        //获取自定义属性和默认值,第一个参数是从用户属性中得到的设置,如果用户没有设置,那么就用默认的属性,即:第二个参数
+        //圆环的颜色
+        roundColor = mTypedArray.getColor(R.styleable.RoundProgressBar_roundColor, Color.RED);
+        //圆环进度条的颜色
+        roundProgressColor = mTypedArray.getColor(R.styleable.RoundProgressBar_roundProgressColor, Color.GREEN);
+        //文字的颜色
+        textColor = mTypedArray.getColor(R.styleable.RoundProgressBar_textColor, Color.GREEN);
+        //文字的大小
+        textSize = mTypedArray.getDimension(R.styleable.RoundProgressBar_textSize, 15);
+        //圆环的宽度
+        roundWidth = mTypedArray.getDimension(R.styleable.RoundProgressBar_roundWidth, 5);
+        //最大进度
+        max = mTypedArray.getInteger(R.styleable.RoundProgressBar_max, 100);
+        //是否显示中间的进度
+        textIsDisplayable = mTypedArray.getBoolean(R.styleable.RoundProgressBar_textIsDisplayable, true);
+        //进度的风格,实心或者空心
+        style = mTypedArray.getInt(R.styleable.RoundProgressBar_style, 0);
+        //进度开始的角度数 
+        startAngle = mTypedArray.getInt(R.styleable.RoundProgressBar_startAngle, -90);
+        // 圆形颜色
+        backColor = mTypedArray.getColor(R.styleable.RoundProgressBar_backColor, 0);
+        mTypedArray.recycle();
+    }
+
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        int centre = getWidth() / 2; //获取圆心的x坐标
+        int radius = (int) (centre - roundWidth / 2); //圆环的半径
+        paint.setStyle(Paint.Style.STROKE); // 设置绘制的圆为空心
+        paint.setColor(roundProgressColor);
+        paint.setAlpha(80);
+        paint.setStrokeWidth(roundWidth / 4);//画笔宽度
+        canvas.drawCircle(centre, centre, radius, paint); // 画底部的空心圆
+
+
+        int roundRadius = (int) (radius - roundWidth * 5 / 4);
+        paint.setColor(roundColor); //设置圆环的颜色
+        paint.setStyle(Paint.Style.STROKE); //设置空心
+        paint.setStrokeWidth(roundWidth); //设置圆环的宽度
+        paint.setAntiAlias(true);  //消除锯齿
+        canvas.drawCircle(centre, centre, roundRadius, paint); //画出圆环
+
+        //Log.e("log", centre + "");
+        if (backColor != 0) {
+            paint.setAntiAlias(true);
+            paint.setColor(backColor);
+            paint.setStyle(Paint.Style.FILL);
+            canvas.drawCircle(centre, centre, roundRadius, paint);
+        }
+
+        /**
+         * 画进度百分比
+         */
+        paint.setStrokeWidth(0);
+        paint.setColor(textColor);
+        paint.setTextSize(textSize);
+        paint.setTypeface(Typeface.DEFAULT); //设置字体
+        int percent = (int) (((float) progress / (float) max) * 100);  //中间的进度百分比,先转换成float在进行除法运算,不然都为0
+        float textWidth = paint.measureText(percent + "%");   //测量字体宽度,我们需要根据字体的宽度设置在圆环中间
+
+        if (textIsDisplayable && percent != 0 && style == STROKE) {
+            canvas.drawText(percent + "%", centre - textWidth / 2, centre + textSize / 8, paint); //画出进度百分比
+        }
+
+        paint.setStrokeWidth(0);
+        paint.setColor(textColor);
+        paint.setAlpha(200);
+        paint.setTextSize(textSize / 2);
+        paint.setTypeface(Typeface.DEFAULT); //设置字体
+
+        float typeTextWidth = paint.measureText(type);   //测量字体宽度,我们需要根据字体的宽度设置在圆环中间
+
+        if (textIsDisplayable && style == STROKE) {
+            canvas.drawText(type, centre - typeTextWidth / 2, centre + textSize * 5 / 6, paint); //画出进度百分比
+        }
+
+
+        /**
+         * 画圆弧 ,画圆环的进度
+         */
+        //设置进度是实心还是空心
+        paint.setStrokeWidth(roundWidth); //设置圆环的宽度
+        paint.setColor(roundProgressColor);  //设置进度的颜色
+        RectF oval = new RectF(centre - roundRadius, centre - roundRadius, centre
+                + roundRadius, centre + roundRadius);  //用于定义的圆弧的形状和大小的界限
+
+        switch (style) {
+            case STROKE: {
+                paint.setStyle(Paint.Style.STROKE);
+
+                        /*第二个参数是进度开始的角度,-90表示从12点方向开始走进度,如果是0表示从三点钟方向走进度,依次类推
+                         *public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)
+                            oval :指定圆弧的外轮廓矩形区域。
+                            startAngle: 圆弧起始角度,单位为度。
+                            sweepAngle: 圆弧扫过的角度,顺时针方向,单位为度。
+                            useCenter: 如果为True时,在绘制圆弧时将圆心包括在内,通常用来绘制扇形。
+                            paint: 绘制圆弧的画板属性,如颜色,是否填充等
+                         *
+                        */
+                canvas.drawArc(oval, startAngle, 360 * progress / max, false, paint);  //根据进度画圆弧
+                break;
+            }
+            case FILL: {
+                paint.setStyle(Paint.Style.FILL_AND_STROKE);
+                if (progress != 0)
+                    canvas.drawArc(oval, startAngle, 360 * progress / max, true, paint);  //根据进度画圆弧
+                break;
+            }
+        }
+
+
+    }
+
+    public synchronized int getMax() {
+        return max;
+    }
+
+    /**
+     * 设置进度的最大值
+     * @param max
+     */
+    public synchronized void setMax(int max) {
+        if (max < 0) {
+            throw new IllegalArgumentException("max not less than 0");
+        }
+        this.max = max;
+    }
+
+    /**
+     * 获取进度.需要同步
+     * @return
+     */
+    public synchronized int getProgress() {
+        return progress;
+    }
+
+    /**
+     * 设置进度,此为线程安全控件,由于考虑多线的问题,需要同步
+     * 刷新界面调用postInvalidate()能在非UI线程刷新
+     * @param progress
+     */
+    public synchronized void setProgress(int progress) {
+        if (progress < 0) {
+            throw new IllegalArgumentException("progress not less than 0");
+        }
+        if (progress > max) {
+            progress = max;
+        }
+        if (progress <= max) {
+            this.progress = progress;
+            postInvalidate();
+            onProgressListener.onProgress(progress);
+        }
+    }
+
+    public OnProgressListener onProgressListener;
+
+    public void setOnProgressListener(OnProgressListener onItemClickListener) {
+        this.onProgressListener = onItemClickListener;
+    }
+
+    public interface OnProgressListener {
+        void onProgress(int position);
+    }
+
+
+    public synchronized void setType(String type) {
+        this.type = type;
+        postInvalidate();
+    }
+
+
+    public int getCircleColor() {
+        return roundColor;
+    }
+
+    public void setCircleColor(int CircleColor) {
+        this.roundColor = CircleColor;
+    }
+
+    public int getCircleProgressColor() {
+        return roundProgressColor;
+    }
+
+    public void setCircleProgressColor(int CircleProgressColor) {
+        this.roundProgressColor = CircleProgressColor;
+    }
+
+    public int getTextColor() {
+        return textColor;
+    }
+
+    public void setTextColor(int textColor) {
+        this.textColor = textColor;
+    }
+
+    public float getTextSize() {
+        return textSize;
+    }
+
+    public void setTextSize(float textSize) {
+        this.textSize = textSize;
+    }
+
+    public float getRoundWidth() {
+        return roundWidth;
+    }
+
+    public void setRoundWidth(float roundWidth) {
+        this.roundWidth = roundWidth;
+    }
+
+
+}

+ 41 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/ViewConvertListener.java

@@ -0,0 +1,41 @@
+package com.cooleshow.base.widgets;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public abstract class ViewConvertListener implements Parcelable {
+
+    public abstract void convertView(ViewHolder holder, BaseDialog dialog);
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+    }
+
+    public ViewConvertListener() {
+    }
+
+    protected ViewConvertListener(Parcel in) {
+    }
+
+    public static final Creator<ViewConvertListener> CREATOR = new Creator<ViewConvertListener>() {
+        @Override
+        public ViewConvertListener createFromParcel(Parcel source) {
+            return new ViewConvertListener(source){
+                @Override
+                public void convertView(ViewHolder holder, BaseDialog dialog) {
+
+                }
+            };
+        }
+
+        @Override
+        public ViewConvertListener[] newArray(int size) {
+            return new ViewConvertListener[size];
+        }
+    };
+}

+ 64 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/ViewHolder.java

@@ -0,0 +1,64 @@
+package com.cooleshow.base.widgets;
+
+import android.util.SparseArray;
+import android.view.View;
+import android.widget.TextView;
+
+public class ViewHolder {
+
+    private SparseArray<View> views;
+    private View convertView;
+
+    private ViewHolder(View view) {
+        convertView = view;
+        views = new SparseArray<>();
+    }
+
+    public static ViewHolder create(View view) {
+        return new ViewHolder(view);
+    }
+
+    public <T extends View> T getView(int viewId) {
+        View view = views.get(viewId);
+        if (view == null) {
+            view = convertView.findViewById(viewId);
+            views.put(viewId, view);
+        }
+        return (T) view;
+    }
+
+    public View getConvertView() {
+        return convertView;
+    }
+
+    public void setText(int viewId, String text) {
+        TextView textView = getView(viewId);
+        textView.setText(text);
+    }
+
+    public void setText(int viewId, int textId) {
+        TextView textView = getView(viewId);
+        textView.setText(textId);
+    }
+
+    public void setTextColor(int viewId, int colorId) {
+        TextView textView = getView(viewId);
+        textView.setTextColor(colorId);
+    }
+
+    public void setOnClickListener(int viewId, View.OnClickListener clickListener) {
+        View view = getView(viewId);
+        view.setOnClickListener(clickListener);
+    }
+
+    public void setBackgroundResource(int viewId, int resId) {
+        View view = getView(viewId);
+        view.setBackgroundResource(resId);
+    }
+
+    public void setBackgroundColor(int viewId, int colorId) {
+        View view = getView(viewId);
+        view.setBackgroundColor(colorId);
+    }
+    }
+ 

+ 39 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/LoadDialog.java

@@ -0,0 +1,39 @@
+package com.cooleshow.base.widgets.loading;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+
+import androidx.annotation.Nullable;
+import androidx.fragment.app.DialogFragment;
+
+import com.cooleshow.base.R;
+
+
+/**
+ * Created by Administrator on 2017/4/24.
+ */
+
+public class LoadDialog extends DialogFragment {
+
+    public static LoadDialog getInstance()
+    {
+        return FirstQuote.instance;
+    }
+
+    //在第一次被引用时被加载
+    static class FirstQuote {
+        private static LoadDialog instance = new LoadDialog();
+    }
+
+    @Nullable
+    @Override
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+        getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
+        getDialog().setCanceledOnTouchOutside(false);
+        View view = inflater.inflate(R.layout.load, container);
+        return view;
+    }
+}

+ 123 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/SpinKitView.java

@@ -0,0 +1,123 @@
+package com.cooleshow.base.widgets.loading;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ProgressBar;
+
+import com.cooleshow.base.R;
+import com.cooleshow.base.widgets.loading.sprite.Sprite;
+
+
+/**
+ * Created by ybq.
+ */
+public class SpinKitView extends ProgressBar {
+
+    private Style  mStyle;
+    private int    mColor;
+    private Sprite mSprite;
+
+    public SpinKitView(Context context) {
+        this(context, null);
+    }
+
+    public SpinKitView(Context context, AttributeSet attrs) {
+        this(context, attrs, R.attr.SpinKitViewStyle);
+    }
+
+    public SpinKitView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, R.style.SpinKitView);
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public SpinKitView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SpinKitView, defStyleAttr,
+                defStyleRes);
+        mStyle = Style.values()[a.getInt(R.styleable.SpinKitView_SpinKit_Style, 1)];
+        mColor = a.getColor(R.styleable.SpinKitView_SpinKit_Color, Color.WHITE);
+        a.recycle();
+        init();
+        setIndeterminate(true);
+    }
+
+    private void init() {
+        Sprite sprite = SpriteFactory.create(mStyle);
+        sprite.setColor(mColor);
+        setIndeterminateDrawable(sprite);
+    }
+
+    @Override
+    public void setIndeterminateDrawable(Drawable d) {
+        if (!(d instanceof Sprite)) {
+            throw new IllegalArgumentException("this d must be instanceof Sprite");
+        }
+        setIndeterminateDrawable((Sprite) d);
+    }
+
+    public void setIndeterminateDrawable(Sprite d) {
+        super.setIndeterminateDrawable(d);
+        mSprite = d;
+        if (mSprite.getColor() == 0) {
+
+            mSprite.setColor(mColor);
+        }
+        onSizeChanged(getWidth(), getHeight(), getWidth(), getHeight());
+        if (getVisibility() == VISIBLE) {
+
+            mSprite.start();
+        }
+    }
+
+    @Override
+    public Sprite getIndeterminateDrawable() {
+        return mSprite;
+    }
+
+    public void setColor(int color) {
+        this.mColor = color;
+        if (mSprite != null) {
+
+            mSprite.setColor(color);
+        }
+        invalidate();
+    }
+
+    @Override
+    public void unscheduleDrawable(Drawable who) {
+        super.unscheduleDrawable(who);
+        if (who instanceof Sprite) {
+
+            ((Sprite) who).stop();
+        }
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasWindowFocus) {
+        super.onWindowFocusChanged(hasWindowFocus);
+        if (hasWindowFocus) {
+            if (mSprite != null && getVisibility() == VISIBLE) {
+
+                mSprite.start();
+            }
+        }
+    }
+
+    @Override
+    public void onScreenStateChanged(int screenState) {
+        super.onScreenStateChanged(screenState);
+        if (screenState == View.SCREEN_STATE_OFF) {
+
+            if (mSprite != null) {
+
+                mSprite.stop();
+            }
+        }
+    }
+}

+ 31 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/SpriteFactory.java

@@ -0,0 +1,31 @@
+package com.cooleshow.base.widgets.loading;
+
+
+import com.cooleshow.base.widgets.loading.sprite.Sprite;
+import com.cooleshow.base.widgets.loading.style.Circle;
+import com.cooleshow.base.widgets.loading.style.FadingCircle;
+import com.cooleshow.base.widgets.loading.style.ThreeBounce;
+
+/**
+ * Created by ybq.
+ */
+public class SpriteFactory {
+
+    public static Sprite create(Style style) {
+        Sprite sprite = null;
+        switch (style) {
+            case CIRCLE:
+                sprite = new Circle();
+                break;
+            case FADING_CIRCLE:
+                sprite = new FadingCircle();
+                break;
+            case THREE_BOUNCE:
+                sprite = new ThreeBounce();
+                break;
+            default:
+                break;
+        }
+        return sprite;
+    }
+}

+ 18 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/Style.java

@@ -0,0 +1,18 @@
+package com.cooleshow.base.widgets.loading;
+
+/**
+ * Created by ybq.
+ */
+public enum Style {
+
+
+    CIRCLE(0),
+    FADING_CIRCLE(1),
+    THREE_BOUNCE(2);
+    @SuppressWarnings({"FieldCanBeLocal", "unused"})
+    private int value;
+
+    Style(int value) {
+        this.value = value;
+    }
+}

+ 54 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/AnimationUtils.java

@@ -0,0 +1,54 @@
+package com.cooleshow.base.widgets.loading.animation;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+
+import com.cooleshow.base.widgets.loading.sprite.Sprite;
+
+
+/**
+ * Created by ybq.
+ */
+public class AnimationUtils {
+
+    public static void start(Animator animator) {
+        if (animator != null && !animator.isStarted()) {
+            animator.start();
+        }
+    }
+
+    public static void stop(Animator animator) {
+        if (animator != null && !animator.isRunning()) {
+            animator.end();
+        }
+    }
+
+    public static void start(Sprite... sprites) {
+        for (Sprite sprite : sprites) {
+            sprite.start();
+        }
+    }
+
+    public static void stop(Sprite... sprites) {
+        for (Sprite sprite : sprites) {
+            sprite.stop();
+        }
+    }
+
+    public static boolean isRunning(Sprite... sprites) {
+        for (Sprite sprite : sprites) {
+            if (sprite.isRunning()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean isRunning(ValueAnimator animator) {
+        return animator != null && animator.isRunning();
+    }
+
+    public static boolean isStarted(ValueAnimator animator) {
+        return animator != null && animator.isStarted();
+    }
+}

+ 46 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/FloatProperty.java

@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cooleshow.base.widgets.loading.animation;
+
+import android.util.Property;
+
+/**
+ * An implementation of {@link Property} to be used specifically with fields of type
+ * <code>float</code>. This type-specific subclass enables performance benefit by allowing
+ * calls to a {@link #set(Object, Float) set()} function that takes the primitive
+ * <code>float</code> type and avoids autoboxing and other overhead associated with the
+ * <code>Float</code> class.
+ *
+ * @param <T> The class on which the Property is declared.
+ */
+public abstract class FloatProperty<T> extends Property<T, Float> {
+
+    public FloatProperty(String name) {
+        super(Float.class, name);
+    }
+
+    /**
+     * A type-specific override of the {@link #set(Object, Float)} that is faster when dealing
+     * with fields of type <code>float</code>.
+     */
+    public abstract void setValue(T object, float value);
+
+    @Override
+    final public void set(T object, Float value) {
+        setValue(object, value);
+    }
+
+}

+ 46 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/IntProperty.java

@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cooleshow.base.widgets.loading.animation;
+
+import android.util.Property;
+
+/**
+ * An implementation of {@link Property} to be used specifically with fields of type
+ * <code>int</code>. This type-specific subclass enables performance benefit by allowing
+ * calls to a {@link #set(Object, Integer) set()} function that takes the primitive
+ * <code>int</code> type and avoids autoboxing and other overhead associated with the
+ * <code>Integer</code> class.
+ *
+ * @param <T> The class on which the Property is declared.
+ */
+public abstract class IntProperty<T> extends Property<T, Integer> {
+
+    public IntProperty(String name) {
+        super(Integer.class, name);
+    }
+
+    /**
+     * A type-specific override of the {@link #set(Object, Integer)} that is faster when dealing
+     * with fields of type <code>int</code>.
+     */
+    public abstract void setValue(T object, int value);
+
+    @Override
+    final public void set(T object, Integer value) {
+        setValue(object, value);
+    }
+
+}

+ 215 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/SpriteAnimatorBuilder.java

@@ -0,0 +1,215 @@
+package com.cooleshow.base.widgets.loading.animation;
+
+import android.animation.Keyframe;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.util.Log;
+import android.util.Property;
+import android.view.animation.Animation;
+import android.view.animation.Interpolator;
+
+
+import com.cooleshow.base.widgets.loading.animation.interpolator.KeyFrameInterpolator;
+import com.cooleshow.base.widgets.loading.sprite.Sprite;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Created by ybq.
+ */
+public class SpriteAnimatorBuilder {
+
+    private static final String                 TAG         = "SpriteAnimatorBuilder";
+    private              Sprite                 sprite;
+    private              Interpolator           interpolator;
+    private              int                    repeatCount = Animation.INFINITE;
+    private              long                   duration    = 2000;
+    private              int                    startFrame  = 0;
+    private              Map<String, FrameData> fds         = new HashMap<>();
+
+
+    class FrameData<T> {
+        public FrameData(float[] fractions, Property property, T[] values) {
+            this.fractions = fractions;
+            this.property = property;
+            this.values = values;
+        }
+
+        float[]  fractions;
+        Property property;
+        T[]      values;
+    }
+
+    class IntFrameData extends FrameData<Integer> {
+
+        public IntFrameData(float[] fractions, Property property, Integer[] values) {
+            super(fractions, property, values);
+        }
+    }
+
+    class FloatFrameData extends FrameData<Float> {
+
+        public FloatFrameData(float[] fractions, Property property, Float[] values) {
+            super(fractions, property, values);
+        }
+    }
+
+    public SpriteAnimatorBuilder(Sprite sprite) {
+        this.sprite = sprite;
+    }
+
+    public SpriteAnimatorBuilder scale(float fractions[], Float... scale) {
+        holder(fractions, Sprite.SCALE, scale);
+        return this;
+    }
+
+    public SpriteAnimatorBuilder alpha(float fractions[], Integer... alpha) {
+        holder(fractions, Sprite.ALPHA, alpha);
+        return this;
+    }
+
+    @SuppressWarnings("unused")
+    public SpriteAnimatorBuilder scaleX(float fractions[], Float... scaleX) {
+        holder(fractions, Sprite.SCALE, scaleX);
+        return this;
+    }
+
+    public SpriteAnimatorBuilder scaleY(float fractions[], Float... scaleY) {
+        holder(fractions, Sprite.SCALE_Y, scaleY);
+        return this;
+    }
+
+    public SpriteAnimatorBuilder rotateX(float fractions[], Integer... rotateX) {
+        holder(fractions, Sprite.ROTATE_X, rotateX);
+        return this;
+    }
+
+    public SpriteAnimatorBuilder rotateY(float fractions[], Integer... rotateY) {
+        holder(fractions, Sprite.ROTATE_Y, rotateY);
+        return this;
+    }
+
+    @SuppressWarnings("unused")
+    public SpriteAnimatorBuilder translateX(float fractions[], Integer... translateX) {
+        holder(fractions, Sprite.TRANSLATE_X, translateX);
+        return this;
+    }
+
+
+    @SuppressWarnings("unused")
+    public SpriteAnimatorBuilder translateY(float fractions[], Integer... translateY) {
+        holder(fractions, Sprite.TRANSLATE_Y, translateY);
+        return this;
+    }
+
+
+    public SpriteAnimatorBuilder rotate(float fractions[], Integer... rotate) {
+        holder(fractions, Sprite.ROTATE, rotate);
+        return this;
+    }
+
+    public SpriteAnimatorBuilder translateXPercentage(float fractions[], Float... translateXPercentage) {
+        holder(fractions, Sprite.TRANSLATE_X_PERCENTAGE, translateXPercentage);
+        return this;
+    }
+
+    public SpriteAnimatorBuilder translateYPercentage(float[] fractions, Float... translateYPercentage) {
+        holder(fractions, Sprite.TRANSLATE_Y_PERCENTAGE, translateYPercentage);
+        return this;
+    }
+
+    private void holder(float[] fractions, Property property, Float[] values) {
+        ensurePair(fractions.length, values.length);
+        fds.put(property.getName(), new FloatFrameData(fractions, property, values));
+    }
+
+
+    private void holder(float[] fractions, Property property, Integer[] values) {
+        ensurePair(fractions.length, values.length);
+        fds.put(property.getName(), new IntFrameData(fractions, property, values));
+    }
+
+    private void ensurePair(int fractionsLength, int valuesLength) {
+        if (fractionsLength != valuesLength) {
+            throw new IllegalStateException(String.format(
+                    Locale.getDefault(),
+                    "The fractions.length must equal values.length, " +
+                            "fraction.length[%d], values.length[%d]",
+                    fractionsLength,
+                    valuesLength));
+        }
+    }
+
+
+    public SpriteAnimatorBuilder interpolator(Interpolator interpolator) {
+        this.interpolator = interpolator;
+        return this;
+    }
+
+    public SpriteAnimatorBuilder easeInOut(float... fractions) {
+        interpolator(KeyFrameInterpolator.easeInOut(
+                fractions
+        ));
+        return this;
+    }
+
+
+    public SpriteAnimatorBuilder duration(long duration) {
+        this.duration = duration;
+        return this;
+    }
+
+    @SuppressWarnings("unused")
+    public SpriteAnimatorBuilder repeatCount(int repeatCount) {
+        this.repeatCount = repeatCount;
+        return this;
+    }
+
+    public SpriteAnimatorBuilder startFrame(int startFrame) {
+        if (startFrame < 0) {
+            Log.w(TAG, "startFrame should always be non-negative");
+            startFrame = 0;
+        }
+        this.startFrame = startFrame;
+        return this;
+    }
+
+    public ObjectAnimator build() {
+
+        PropertyValuesHolder[] holders = new PropertyValuesHolder[fds.size()];
+        int i = 0;
+        for (Map.Entry<String, FrameData> fd : fds.entrySet()) {
+            FrameData data = fd.getValue();
+            Keyframe[] keyframes = new Keyframe[data.fractions.length];
+            float[] fractions = data.fractions;
+            float startF = fractions[startFrame];
+            for (int j = startFrame; j < (startFrame + data.values.length); j++) {
+                int key = j - startFrame;
+                int vk = j % data.values.length;
+                float fraction = fractions[vk] - startF;
+                if (fraction < 0) {
+                    fraction = fractions[fractions.length - 1] + fraction;
+                }
+                if (data instanceof IntFrameData) {
+                    keyframes[key] = Keyframe.ofInt(fraction, (Integer) data.values[vk]);
+                } else if (data instanceof FloatFrameData) {
+                    keyframes[key] = Keyframe.ofFloat(fraction, (Float) data.values[vk]);
+                } else {
+                    keyframes[key] = Keyframe.ofObject(fraction, data.values[vk]);
+                }
+            }
+            holders[i] = PropertyValuesHolder.ofKeyframe(data.property, keyframes);
+            i++;
+        }
+
+        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(sprite,
+                holders);
+        animator.setDuration(duration);
+        animator.setRepeatCount(repeatCount);
+        animator.setInterpolator(interpolator);
+        return animator;
+    }
+
+}

+ 12 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/interpolator/Ease.java

@@ -0,0 +1,12 @@
+package com.cooleshow.base.widgets.loading.animation.interpolator;
+
+import android.view.animation.Interpolator;
+
+/**
+ * Created by ybq.
+ */
+public class Ease {
+    public static Interpolator inOut() {
+        return PathInterpolatorCompat.create(0.42f, 0f, 0.58f, 1f);
+    }
+}

+ 54 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/interpolator/KeyFrameInterpolator.java

@@ -0,0 +1,54 @@
+package com.cooleshow.base.widgets.loading.animation.interpolator;
+
+import android.animation.TimeInterpolator;
+import android.view.animation.Interpolator;
+
+/**
+ * Created by ybq.
+ */
+public class KeyFrameInterpolator implements Interpolator {
+
+    private TimeInterpolator interpolator;
+    private float[]          fractions;
+
+
+    public static KeyFrameInterpolator easeInOut(float... fractions) {
+        KeyFrameInterpolator interpolator = new KeyFrameInterpolator(Ease.inOut());
+        interpolator.setFractions(fractions);
+        return interpolator;
+    }
+
+    public static KeyFrameInterpolator pathInterpolator(float controlX1, float controlY1,
+                                                        float controlX2, float controlY2,
+                                                        float... fractions) {
+        KeyFrameInterpolator interpolator = new KeyFrameInterpolator(PathInterpolatorCompat.create(controlX1, controlY1, controlX2, controlY2));
+        interpolator.setFractions(fractions);
+        return interpolator;
+    }
+
+    public KeyFrameInterpolator(TimeInterpolator interpolator, float... fractions) {
+        this.interpolator = interpolator;
+        this.fractions = fractions;
+    }
+
+    public void setFractions(float... fractions) {
+        this.fractions = fractions;
+    }
+
+    @Override
+    public synchronized float getInterpolation(float input) {
+        if (fractions.length > 1) {
+            for (int i = 0; i < fractions.length - 1; i++) {
+                float start = fractions[i];
+                float end = fractions[i + 1];
+                float duration = end - start;
+                if (input >= start && input <= end) {
+                    input = (input - start) / duration;
+                    return start + (interpolator.getInterpolation(input)
+                            * duration);
+                }
+            }
+        }
+        return interpolator.getInterpolation(input);
+    }
+}

+ 87 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/interpolator/PathInterpolatorCompat.java

@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.cooleshow.base.widgets.loading.animation.interpolator;
+
+import android.graphics.Path;
+import android.os.Build;
+import android.view.animation.Interpolator;
+
+/**
+ * Helper for creating path-based {@link Interpolator} instances. On API 21 or newer, the
+ * platform implementation will be used and on older platforms a compatible alternative
+ * implementation will be used.
+ */
+public class PathInterpolatorCompat {
+
+    private PathInterpolatorCompat() {
+        // prevent instantiation
+    }
+
+    /**
+     * Create an {@link Interpolator} for an arbitrary {@link Path}. The {@link Path}
+     * must begin at {@code (0, 0)} and end at {@code (1, 1)}. The x-coordinate along the
+     * {@link Path} is the input value and the output is the y coordinate of the line at that
+     * point. This means that the Path must conform to a function {@code y = f(x)}.
+     * <p>
+     * The {@link Path} must not have gaps in the x direction and must not
+     * loop back on itself such that there can be two points sharing the same x coordinate.
+     *
+     * @param path the {@link Path} to use to make the line representing the {@link Interpolator}
+     * @return the {@link Interpolator} representing the {@link Path}
+     */
+    @SuppressWarnings("unused")
+    public static Interpolator create(Path path) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            return PathInterpolatorCompatApi21.create(path);
+        }
+        return PathInterpolatorCompatBase.create(path);
+    }
+
+    /**
+     * Create an {@link Interpolator} for a quadratic Bezier curve. The end points
+     * {@code (0, 0)} and {@code (1, 1)} are assumed.
+     *
+     * @param controlX the x coordinate of the quadratic Bezier control point
+     * @param controlY the y coordinate of the quadratic Bezier control point
+     * @return the {@link Interpolator} representing the quadratic Bezier curve
+     */
+    @SuppressWarnings("unused")
+    public static Interpolator create(float controlX, float controlY) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            return PathInterpolatorCompatApi21.create(controlX, controlY);
+        }
+        return PathInterpolatorCompatBase.create(controlX, controlY);
+    }
+
+    /**
+     * Create an {@link Interpolator} for a cubic Bezier curve.  The end points
+     * {@code (0, 0)} and {@code (1, 1)} are assumed.
+     *
+     * @param controlX1 the x coordinate of the first control point of the cubic Bezier
+     * @param controlY1 the y coordinate of the first control point of the cubic Bezier
+     * @param controlX2 the x coordinate of the second control point of the cubic Bezier
+     * @param controlY2 the y coordinate of the second control point of the cubic Bezier
+     * @return the {@link Interpolator} representing the cubic Bezier curve
+     */
+    public static Interpolator create(float controlX1, float controlY1,
+                                      float controlX2, float controlY2) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            return PathInterpolatorCompatApi21.create(controlX1, controlY1, controlX2, controlY2);
+        }
+        return PathInterpolatorCompatBase.create(controlX1, controlY1, controlX2, controlY2);
+    }
+}

+ 49 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/interpolator/PathInterpolatorCompatApi21.java

@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.cooleshow.base.widgets.loading.animation.interpolator;
+
+import android.annotation.TargetApi;
+import android.graphics.Path;
+import android.os.Build;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+
+/**
+ * API 21+ implementation for path interpolator compatibility.
+ */
+class PathInterpolatorCompatApi21 {
+
+    private PathInterpolatorCompatApi21() {
+        // prevent instantiation
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public static Interpolator create(Path path) {
+        return new PathInterpolator(path);
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public static Interpolator create(float controlX, float controlY) {
+        return new PathInterpolator(controlX, controlY);
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public static Interpolator create(float controlX1, float controlY1,
+                                      float controlX2, float controlY2) {
+        return new PathInterpolator(controlX1, controlY1, controlX2, controlY2);
+    }
+}

+ 43 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/interpolator/PathInterpolatorCompatBase.java

@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.cooleshow.base.widgets.loading.animation.interpolator;
+
+import android.graphics.Path;
+import android.view.animation.Interpolator;
+
+/**
+ * Base implementation for path interpolator compatibility.
+ */
+class PathInterpolatorCompatBase {
+
+    private PathInterpolatorCompatBase() {
+        // prevent instantiation
+    }
+
+    public static Interpolator create(Path path) {
+        return new PathInterpolatorDonut(path);
+    }
+
+    public static Interpolator create(float controlX, float controlY) {
+        return new PathInterpolatorDonut(controlX, controlY);
+    }
+
+    public static Interpolator create(float controlX1, float controlY1,
+                                      float controlX2, float controlY2) {
+        return new PathInterpolatorDonut(controlX1, controlY1, controlX2, controlY2);
+    }
+}

+ 111 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/animation/interpolator/PathInterpolatorDonut.java

@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cooleshow.base.widgets.loading.animation.interpolator;
+
+import android.graphics.Path;
+import android.graphics.PathMeasure;
+import android.view.animation.Interpolator;
+
+/**
+ * A path interpolator implementation compatible with API 4+.
+ */
+class PathInterpolatorDonut implements Interpolator {
+
+    /**
+     * Governs the accuracy of the approximation of the {@link Path}.
+     */
+    private static final float PRECISION = 0.002f;
+
+    private final float[] mX;
+    private final float[] mY;
+
+    public PathInterpolatorDonut(Path path) {
+        final PathMeasure pathMeasure = new PathMeasure(path, false /* forceClosed */);
+
+        final float pathLength = pathMeasure.getLength();
+        final int numPoints = (int) (pathLength / PRECISION) + 1;
+
+        mX = new float[numPoints];
+        mY = new float[numPoints];
+
+        final float[] position = new float[2];
+        for (int i = 0; i < numPoints; ++i) {
+            final float distance = (i * pathLength) / (numPoints - 1);
+            pathMeasure.getPosTan(distance, position, null /* tangent */);
+
+            mX[i] = position[0];
+            mY[i] = position[1];
+        }
+    }
+
+    public PathInterpolatorDonut(float controlX, float controlY) {
+        this(createQuad(controlX, controlY));
+    }
+
+    public PathInterpolatorDonut(float controlX1, float controlY1,
+                                 float controlX2, float controlY2) {
+        this(createCubic(controlX1, controlY1, controlX2, controlY2));
+    }
+
+    @Override
+    public float getInterpolation(float t) {
+        if (t <= 0.0f) {
+            return 0.0f;
+        } else if (t >= 1.0f) {
+            return 1.0f;
+        }
+
+        // Do a binary search for the correct x to interpolate between.
+        int startIndex = 0;
+        int endIndex = mX.length - 1;
+        while (endIndex - startIndex > 1) {
+            int midIndex = (startIndex + endIndex) / 2;
+            if (t < mX[midIndex]) {
+                endIndex = midIndex;
+            } else {
+                startIndex = midIndex;
+            }
+        }
+
+        final float xRange = mX[endIndex] - mX[startIndex];
+        if (xRange == 0) {
+            return mY[startIndex];
+        }
+
+        final float tInRange = t - mX[startIndex];
+        final float fraction = tInRange / xRange;
+
+        final float startY = mY[startIndex];
+        final float endY = mY[endIndex];
+
+        return startY + (fraction * (endY - startY));
+    }
+
+    private static Path createQuad(float controlX, float controlY) {
+        final Path path = new Path();
+        path.moveTo(0.0f, 0.0f);
+        path.quadTo(controlX, controlY, 1.0f, 1.0f);
+        return path;
+    }
+
+    private static Path createCubic(float controlX1, float controlY1,
+                                    float controlX2, float controlY2) {
+        final Path path = new Path();
+        path.moveTo(0.0f, 0.0f);
+        path.cubicTo(controlX1, controlY1, controlX2, controlY2, 1.0f, 1.0f);
+        return path;
+    }
+}

+ 36 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/sprite/CircleLayoutContainer.java

@@ -0,0 +1,36 @@
+package com.cooleshow.base.widgets.loading.sprite;
+
+import android.graphics.Canvas;
+import android.graphics.Rect;
+
+/**
+ * Created by ybq.
+ */
+public abstract class CircleLayoutContainer extends SpriteContainer {
+
+    @Override
+    public void drawChild(Canvas canvas) {
+        for (int i = 0; i < getChildCount(); i++) {
+            Sprite sprite = getChildAt(i);
+            int count = canvas.save();
+            canvas.rotate(i * 360 / getChildCount(),
+                    getBounds().centerX(),
+                    getBounds().centerY());
+            sprite.draw(canvas);
+            canvas.restoreToCount(count);
+        }
+    }
+
+    @Override
+    protected void onBoundsChange(Rect bounds) {
+        super.onBoundsChange(bounds);
+        bounds = clipSquare(bounds);
+        int radius = (int) (bounds.width() * Math.PI / 3.6f / getChildCount());
+        int left = bounds.centerX() - radius;
+        int right = bounds.centerX() + radius;
+        for (int i = 0; i < getChildCount(); i++) {
+            Sprite sprite = getChildAt(i);
+            sprite.setDrawBounds(left, bounds.top, right, bounds.top + radius * 2);
+        }
+    }
+}

+ 26 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/sprite/CircleSprite.java

@@ -0,0 +1,26 @@
+package com.cooleshow.base.widgets.loading.sprite;
+
+import android.animation.ValueAnimator;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+/**
+ * Created by ybq.
+ */
+public class CircleSprite extends ShapeSprite {
+
+    @Override
+    public ValueAnimator onCreateAnimation() {
+        return null;
+    }
+
+    @Override
+    public void drawShape(Canvas canvas, Paint paint) {
+        if (getDrawBounds() != null) {
+            int radius = Math.min(getDrawBounds().width(), getDrawBounds().height()) / 2;
+            canvas.drawCircle(getDrawBounds().centerX(),
+                    getDrawBounds().centerY(),
+                    radius, paint);
+        }
+    }
+}

+ 66 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/sprite/ShapeSprite.java

@@ -0,0 +1,66 @@
+package com.cooleshow.base.widgets.loading.sprite;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+
+/**
+ * Created by ybq.
+ */
+public abstract class ShapeSprite extends Sprite {
+
+    private Paint mPaint;
+    private int   mUseColor;
+    private int   mBaseColor;
+
+    public ShapeSprite() {
+        setColor(Color.WHITE);
+        mPaint = new Paint();
+        mPaint.setAntiAlias(true);
+        mPaint.setColor(mUseColor);
+    }
+
+    @Override
+    public void setColor(int color) {
+        mBaseColor = color;
+        updateUseColor();
+    }
+
+    @Override
+    public int getColor() {
+        return mBaseColor;
+    }
+
+    @SuppressWarnings("unused")
+    public int getUseColor() {
+        return mUseColor;
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+        super.setAlpha(alpha);
+        updateUseColor();
+    }
+
+    private void updateUseColor() {
+        int alpha = getAlpha();
+        alpha += alpha >> 7;
+        final int baseAlpha = mBaseColor >>> 24;
+        final int useAlpha = baseAlpha * alpha >> 8;
+        mUseColor = (mBaseColor << 8 >>> 8) | (useAlpha << 24);
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter colorFilter) {
+        mPaint.setColorFilter(colorFilter);
+    }
+
+    @Override
+    protected final void drawSelf(Canvas canvas) {
+        mPaint.setColor(mUseColor);
+        drawShape(canvas, mPaint);
+    }
+
+    public abstract void drawShape(Canvas canvas, Paint paint);
+}

+ 455 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/sprite/Sprite.java

@@ -0,0 +1,455 @@
+package com.cooleshow.base.widgets.loading.sprite;
+
+import android.animation.ValueAnimator;
+import android.graphics.Camera;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Matrix;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Drawable;
+import android.util.Property;
+
+import com.cooleshow.base.widgets.loading.animation.AnimationUtils;
+import com.cooleshow.base.widgets.loading.animation.FloatProperty;
+import com.cooleshow.base.widgets.loading.animation.IntProperty;
+
+
+/**
+ * Created by ybq.
+ */
+public abstract class Sprite extends Drawable implements
+        ValueAnimator.AnimatorUpdateListener
+        , Animatable
+        , Drawable.Callback {
+
+    private              float         scale            = 1;
+    private              float         scaleX           = 1;
+    private              float         scaleY           = 1;
+    private              float         pivotX;
+    private              float         pivotY;
+    private              int           animationDelay;
+    private              int           rotateX;
+    private              int           rotateY;
+    private              int           translateX;
+    private              int           translateY;
+    private              int           rotate;
+    private              float         translateXPercentage;
+    private              float         translateYPercentage;
+    private              ValueAnimator animator;
+    private              int           alpha            = 255;
+    private static final Rect          ZERO_BOUNDS_RECT = new Rect();
+    protected            Rect          drawBounds       = ZERO_BOUNDS_RECT;
+    private              Camera        mCamera;
+    private              Matrix        mMatrix;
+
+    public Sprite() {
+        mCamera = new Camera();
+        mMatrix = new Matrix();
+    }
+
+    public abstract int getColor();
+
+    public abstract void setColor(int color);
+
+    @Override
+    public void setAlpha(int alpha) {
+        this.alpha = alpha;
+    }
+
+    @Override
+    public int getAlpha() {
+        return alpha;
+    }
+
+    @Override
+    public int getOpacity() {
+        return PixelFormat.TRANSLUCENT;
+    }
+
+    public float getTranslateXPercentage() {
+        return translateXPercentage;
+    }
+
+    public void setTranslateXPercentage(float translateXPercentage) {
+        this.translateXPercentage = translateXPercentage;
+    }
+
+    public float getTranslateYPercentage() {
+        return translateYPercentage;
+    }
+
+    public void setTranslateYPercentage(float translateYPercentage) {
+        this.translateYPercentage = translateYPercentage;
+    }
+
+    public int getTranslateX() {
+        return translateX;
+    }
+
+    public void setTranslateX(int translateX) {
+        this.translateX = translateX;
+    }
+
+    public int getTranslateY() {
+        return translateY;
+    }
+
+    public void setTranslateY(int translateY) {
+        this.translateY = translateY;
+    }
+
+    public int getRotate() {
+        return rotate;
+    }
+
+    public void setRotate(int rotate) {
+        this.rotate = rotate;
+    }
+
+    public float getScale() {
+        return scale;
+    }
+
+    public void setScale(float scale) {
+        this.scale = scale;
+        setScaleX(scale);
+        setScaleY(scale);
+    }
+
+    public float getScaleX() {
+        return scaleX;
+    }
+
+    public void setScaleX(float scaleX) {
+        this.scaleX = scaleX;
+    }
+
+    public float getScaleY() {
+        return scaleY;
+    }
+
+    public void setScaleY(float scaleY) {
+        this.scaleY = scaleY;
+    }
+
+    public int getRotateX() {
+        return rotateX;
+    }
+
+    public void setRotateX(int rotateX) {
+        this.rotateX = rotateX;
+    }
+
+    public int getRotateY() {
+        return rotateY;
+    }
+
+    public void setRotateY(int rotateY) {
+        this.rotateY = rotateY;
+    }
+
+    public float getPivotX() {
+        return pivotX;
+    }
+
+    public void setPivotX(float pivotX) {
+        this.pivotX = pivotX;
+    }
+
+    public float getPivotY() {
+        return pivotY;
+    }
+
+    public void setPivotY(float pivotY) {
+        this.pivotY = pivotY;
+    }
+
+    @SuppressWarnings("unused")
+    public int getAnimationDelay() {
+        return animationDelay;
+    }
+
+    public Sprite setAnimationDelay(int animationDelay) {
+        this.animationDelay = animationDelay;
+        return this;
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter colorFilter) {
+
+    }
+
+    public abstract ValueAnimator onCreateAnimation();
+
+    @Override
+    public void start() {
+        if (AnimationUtils.isStarted(animator)) {
+            return;
+        }
+
+        animator = obtainAnimation();
+        if (animator == null) {
+            return;
+        }
+
+        AnimationUtils.start(animator);
+        invalidateSelf();
+    }
+
+    public ValueAnimator obtainAnimation() {
+        if (animator == null) {
+            animator = onCreateAnimation();
+        }
+        if (animator != null) {
+            animator.addUpdateListener(this);
+            animator.setStartDelay(animationDelay);
+        }
+        return animator;
+    }
+
+    @Override
+    public void stop() {
+        if (AnimationUtils.isStarted(animator)) {
+            animator.removeAllUpdateListeners();
+            animator.end();
+            reset();
+        }
+    }
+
+    protected abstract void drawSelf(Canvas canvas);
+
+    public void reset() {
+        scale = 1;
+        rotateX = 0;
+        rotateY = 0;
+        translateX = 0;
+        translateY = 0;
+        rotate = 0;
+        translateXPercentage = 0f;
+        translateYPercentage = 0f;
+    }
+
+    @Override
+    public boolean isRunning() {
+        return AnimationUtils.isRunning(animator);
+    }
+
+    @Override
+    protected void onBoundsChange(Rect bounds) {
+        super.onBoundsChange(bounds);
+        setDrawBounds(bounds);
+    }
+
+    public void setDrawBounds(Rect drawBounds) {
+        setDrawBounds(drawBounds.left, drawBounds.top, drawBounds.right, drawBounds.bottom);
+    }
+
+    public void setDrawBounds(int left, int top, int right, int bottom) {
+        this.drawBounds = new Rect(left, top, right, bottom);
+        setPivotX(getDrawBounds().centerX());
+        setPivotY(getDrawBounds().centerY());
+    }
+
+    @Override
+    public void invalidateDrawable(Drawable who) {
+        invalidateSelf();
+    }
+
+    @Override
+    public void scheduleDrawable(Drawable who, Runnable what, long when) {
+
+    }
+
+    @Override
+    public void unscheduleDrawable(Drawable who, Runnable what) {
+
+    }
+
+    @Override
+    public void onAnimationUpdate(ValueAnimator animation) {
+        final Callback callback = getCallback();
+        if (callback != null) {
+            callback.invalidateDrawable(this);
+        }
+    }
+
+    public Rect getDrawBounds() {
+        return drawBounds;
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        int tx = getTranslateX();
+        tx = tx == 0 ? (int) (getBounds().width() * getTranslateXPercentage()) : tx;
+        int ty = getTranslateY();
+        ty = ty == 0 ? (int) (getBounds().height() * getTranslateYPercentage()) : ty;
+        canvas.translate(tx, ty);
+        canvas.scale(getScaleX(), getScaleY(), getPivotX(), getPivotY());
+        canvas.rotate(getRotate(), getPivotX(), getPivotY());
+
+        if (getRotateX() != 0 || getRotateY() != 0) {
+            mCamera.save();
+            mCamera.rotateX(getRotateX());
+            mCamera.rotateY(getRotateY());
+            mCamera.getMatrix(mMatrix);
+            mMatrix.preTranslate(-getPivotX(), -getPivotY());
+            mMatrix.postTranslate(getPivotX(), getPivotY());
+            mCamera.restore();
+            canvas.concat(mMatrix);
+        }
+        drawSelf(canvas);
+    }
+
+    public Rect clipSquare(Rect rect) {
+        int w = rect.width();
+        int h = rect.height();
+        int min = Math.min(w, h);
+        int cx = rect.centerX();
+        int cy = rect.centerY();
+        int r = min / 2;
+        return new Rect(
+                cx - r,
+                cy - r,
+                cx + r,
+                cy + r
+        );
+    }
+
+    public static final Property<Sprite, Integer> ROTATE_X = new IntProperty<Sprite>("rotateX") {
+        @Override
+        public void setValue(Sprite object, int value) {
+            object.setRotateX(value);
+        }
+
+        @Override
+        public Integer get(Sprite object) {
+            return object.getRotateX();
+        }
+    };
+
+    public static final Property<Sprite, Integer> ROTATE = new IntProperty<Sprite>("rotate") {
+        @Override
+        public void setValue(Sprite object, int value) {
+            object.setRotate(value);
+        }
+
+        @Override
+        public Integer get(Sprite object) {
+            return object.getRotate();
+        }
+    };
+
+    public static final Property<Sprite, Integer> ROTATE_Y = new IntProperty<Sprite>("rotateY") {
+        @Override
+        public void setValue(Sprite object, int value) {
+            object.setRotateY(value);
+        }
+
+        @Override
+        public Integer get(Sprite object) {
+            return object.getRotateY();
+        }
+    };
+
+    @SuppressWarnings("unused")
+    public static final Property<Sprite, Integer> TRANSLATE_X = new IntProperty<Sprite>("translateX") {
+        @Override
+        public void setValue(Sprite object, int value) {
+            object.setTranslateX(value);
+        }
+
+        @Override
+        public Integer get(Sprite object) {
+            return object.getTranslateX();
+        }
+    };
+
+    @SuppressWarnings("unused")
+    public static final Property<Sprite, Integer> TRANSLATE_Y = new IntProperty<Sprite>("translateY") {
+        @Override
+        public void setValue(Sprite object, int value) {
+            object.setTranslateY(value);
+        }
+
+        @Override
+        public Integer get(Sprite object) {
+            return object.getTranslateY();
+        }
+    };
+
+    public static final Property<Sprite, Float> TRANSLATE_X_PERCENTAGE = new FloatProperty<Sprite>("translateXPercentage") {
+        @Override
+        public void setValue(Sprite object, float value) {
+            object.setTranslateXPercentage(value);
+        }
+
+        @Override
+        public Float get(Sprite object) {
+            return object.getTranslateXPercentage();
+        }
+    };
+
+    public static final Property<Sprite, Float> TRANSLATE_Y_PERCENTAGE = new FloatProperty<Sprite>("translateYPercentage") {
+        @Override
+        public void setValue(Sprite object, float value) {
+            object.setTranslateYPercentage(value);
+        }
+
+        @Override
+        public Float get(Sprite object) {
+            return object.getTranslateYPercentage();
+        }
+    };
+
+    @SuppressWarnings("unused")
+    public static final Property<Sprite, Float> SCALE_X = new FloatProperty<Sprite>("scaleX") {
+        @Override
+        public void setValue(Sprite object, float value) {
+            object.setScaleX(value);
+        }
+
+        @Override
+        public Float get(Sprite object) {
+            return object.getScaleX();
+        }
+    };
+
+    public static final Property<Sprite, Float> SCALE_Y = new FloatProperty<Sprite>("scaleY") {
+        @Override
+        public void setValue(Sprite object, float value) {
+            object.setScaleY(value);
+        }
+
+        @Override
+        public Float get(Sprite object) {
+            return object.getScaleY();
+        }
+    };
+
+    public static final Property<Sprite, Float> SCALE = new FloatProperty<Sprite>("scale") {
+        @Override
+        public void setValue(Sprite object, float value) {
+            object.setScale(value);
+        }
+
+        @Override
+        public Float get(Sprite object) {
+            return object.getScale();
+        }
+    };
+
+    public static final Property<Sprite, Integer> ALPHA = new IntProperty<Sprite>("alpha") {
+        @Override
+        public void setValue(Sprite object, int value) {
+            object.setAlpha(value);
+        }
+
+        @Override
+        public Integer get(Sprite object) {
+            return object.getAlpha();
+        }
+    };
+
+}

+ 109 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/sprite/SpriteContainer.java

@@ -0,0 +1,109 @@
+package com.cooleshow.base.widgets.loading.sprite;
+
+import android.animation.ValueAnimator;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+
+import com.cooleshow.base.widgets.loading.animation.AnimationUtils;
+
+
+/**
+ * Created by ybq.
+ */
+public abstract class SpriteContainer extends Sprite {
+
+    private Sprite[] sprites;
+
+    private int color;
+
+    public SpriteContainer() {
+        sprites = onCreateChild();
+        initCallBack();
+        onChildCreated(sprites);
+    }
+
+    private void initCallBack() {
+        if (sprites != null) {
+            for (Sprite sprite : sprites) {
+                sprite.setCallback(this);
+            }
+        }
+    }
+
+    public void onChildCreated(Sprite... sprites) {
+
+    }
+
+    public int getChildCount() {
+        return sprites == null ? 0 : sprites.length;
+    }
+
+    public Sprite getChildAt(int index) {
+        return sprites == null ? null : sprites[index];
+    }
+
+    @Override
+    public void setColor(int color) {
+        this.color = color;
+        for (int i = 0; i < getChildCount(); i++) {
+            getChildAt(i).setColor(color);
+        }
+    }
+
+    @Override
+    public int getColor() {
+        return color;
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        super.draw(canvas);
+        drawChild(canvas);
+    }
+
+    public void drawChild(Canvas canvas) {
+        if (sprites != null) {
+            for (Sprite sprite : sprites) {
+                int count = canvas.save();
+                sprite.draw(canvas);
+                canvas.restoreToCount(count);
+            }
+        }
+    }
+
+    @Override
+    protected void drawSelf(Canvas canvas) {
+    }
+
+    @Override
+    protected void onBoundsChange(Rect bounds) {
+        super.onBoundsChange(bounds);
+        for (Sprite sprite : sprites) {
+            sprite.setBounds(bounds);
+        }
+    }
+
+    @Override
+    public void start() {
+        super.start();
+        AnimationUtils.start(sprites);
+    }
+
+    @Override
+    public void stop() {
+        super.stop();
+        AnimationUtils.stop(sprites);
+    }
+
+    @Override
+    public boolean isRunning() {
+        return AnimationUtils.isRunning(sprites) || super.isRunning();
+    }
+
+    public abstract Sprite[] onCreateChild();
+
+    @Override
+    public ValueAnimator onCreateAnimation() {
+        return null;
+    }
+}

+ 50 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/style/Circle.java

@@ -0,0 +1,50 @@
+package com.cooleshow.base.widgets.loading.style;
+
+import android.animation.ValueAnimator;
+import android.os.Build;
+
+import com.cooleshow.base.widgets.loading.animation.SpriteAnimatorBuilder;
+import com.cooleshow.base.widgets.loading.sprite.CircleLayoutContainer;
+import com.cooleshow.base.widgets.loading.sprite.CircleSprite;
+import com.cooleshow.base.widgets.loading.sprite.Sprite;
+
+
+/**
+ * Created by ybq.
+ */
+public class Circle extends CircleLayoutContainer {
+
+    @Override
+    public Sprite[] onCreateChild() {
+        Dot[] dots = new Dot[8];
+        for (int i = 0; i < dots.length; i++) {
+            dots[i] = new Dot();
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+                dots[i].setAnimationDelay(1200 / 8 * i);
+            } else {
+                dots[i].setAnimationDelay(1200 / 8 * i + -1200);
+            }
+        }
+        return dots;
+    }
+
+    private class Dot extends CircleSprite {
+
+        Dot() {
+            setScale(0f);
+            setAlpha(200);
+        }
+
+        @Override
+        public ValueAnimator onCreateAnimation() {
+            float fractions[] = new float[]{0.6f, 1f};
+            return new SpriteAnimatorBuilder(this)
+                    .scale(fractions, 1f, 0.6f)
+                    .alpha(fractions, 200, 20)
+                    .duration(1200)
+                    .easeInOut(fractions)
+                    .build();
+        }
+
+    }
+}

+ 47 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/style/FadingCircle.java

@@ -0,0 +1,47 @@
+package com.cooleshow.base.widgets.loading.style;
+
+import android.animation.ValueAnimator;
+import android.os.Build;
+
+import com.cooleshow.base.widgets.loading.animation.SpriteAnimatorBuilder;
+import com.cooleshow.base.widgets.loading.sprite.CircleLayoutContainer;
+import com.cooleshow.base.widgets.loading.sprite.CircleSprite;
+import com.cooleshow.base.widgets.loading.sprite.Sprite;
+
+
+/**
+ * Created by ybq.
+ */
+public class FadingCircle extends CircleLayoutContainer {
+
+    @Override
+    public Sprite[] onCreateChild() {
+        Dot[] dots = new Dot[8];
+        for (int i = 0; i < dots.length; i++) {
+            dots[i] = new Dot();
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+                dots[i].setAnimationDelay(1500 / 8 * i);
+            } else {
+                dots[i].setAnimationDelay(1500 / 8 * i + -1500);
+            }
+        }
+        return dots;
+    }
+
+    private class Dot extends CircleSprite {
+
+        Dot() {
+            setAlpha(240);
+        }
+
+        @Override
+        public ValueAnimator onCreateAnimation() {
+            float fractions[] = new float[]{0.1f,  1f};
+            return new SpriteAnimatorBuilder(this).
+                    alpha(fractions,  240, 20).
+                    duration(1500).
+                    easeInOut(fractions)
+                    .build();
+        }
+    }
+}

+ 73 - 0
BaseLibrary/src/main/java/com/cooleshow/base/widgets/loading/style/ThreeBounce.java

@@ -0,0 +1,73 @@
+package com.cooleshow.base.widgets.loading.style;
+
+import android.animation.ValueAnimator;
+import android.graphics.Rect;
+
+import com.cooleshow.base.widgets.loading.animation.SpriteAnimatorBuilder;
+import com.cooleshow.base.widgets.loading.sprite.CircleSprite;
+import com.cooleshow.base.widgets.loading.sprite.Sprite;
+import com.cooleshow.base.widgets.loading.sprite.SpriteContainer;
+
+
+/**
+ * Created by ybq.
+ */
+public class ThreeBounce extends SpriteContainer {
+
+    @Override
+    public Sprite[] onCreateChild() {
+        return new Sprite[]{
+                new Bounce(),
+                new Bounce(),
+                new Bounce()
+        };
+    }
+
+    @Override
+    public void onChildCreated(Sprite... sprites) {
+        super.onChildCreated(sprites);
+        sprites[1].setAnimationDelay(160);
+        sprites[2].setAnimationDelay(320);
+    }
+
+    @Override
+    protected void onBoundsChange(Rect bounds) {
+        super.onBoundsChange(bounds);
+        bounds = clipSquare(bounds);
+        int radius = bounds.width() / 14;
+        int top = bounds.centerY() - radius;
+        int bottom = bounds.centerY() + radius;
+
+        for (int i = 0; i < getChildCount(); i++) {
+            int left = bounds.width() * i / 4
+                    + bounds.left;
+            getChildAt(i).setDrawBounds(
+                    left, top, left + radius * 2, bottom
+            );
+        }
+    }
+
+    private class Bounce extends CircleSprite {
+
+        Bounce() {
+            setScale(1f);
+        }
+
+        @Override
+        public ValueAnimator onCreateAnimation() {
+                        float fractions[] = new float[]{0f, 0.4f, 0.8f, 1f};
+                        return new SpriteAnimatorBuilder(this).scale(fractions, 0f, 1f, 0f, 0f).
+                                duration(1400).
+                                easeInOut(fractions)
+                                .build();
+
+//            float fractions[] = new float[]{0f, 1f};
+            ////            return new SpriteAnimatorBuilder(this)
+            ////                    .scale(fractions, 0f, 1f)
+            ////                    .alpha(fractions, 80, 256)
+            ////                    .duration(1400)
+            ////                    .easeInOut(fractions)
+            ////                    .build();
+        }
+    }
+}

BIN
BaseLibrary/src/main/res/drawable-xxhdpi/ic_dash_line.png


BIN
BaseLibrary/src/main/res/drawable-xxhdpi/ic_network_error.png


BIN
BaseLibrary/src/main/res/drawable-xxhdpi/icon_testing_closea.png


BIN
BaseLibrary/src/main/res/drawable-xxhdpi/icon_testing_default.png


BIN
BaseLibrary/src/main/res/drawable-xxhdpi/icon_testing_success.png


BIN
BaseLibrary/src/main/res/drawable-xxhdpi/icon_testing_wait.png


+ 6 - 0
BaseLibrary/src/main/res/drawable/bg_white_default_shape.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <solid android:color="@color/white"/>
+    <corners android:radius="5dp"/>
+</shape>

+ 5 - 0
BaseLibrary/src/main/res/drawable/shape_corner.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#99000000" />
+    <corners android:radius="10dp" />
+</shape>

+ 132 - 0
BaseLibrary/src/main/res/layout/common_popu_stu.xml

@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout 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"
+    android:orientation="vertical">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/dp_32"
+        android:layout_marginEnd="@dimen/dp_32"
+        android:background="@drawable/bg_white_default_shape">
+
+
+        <ImageView
+            android:id="@+id/iv_icon"
+            android:layout_width="4dp"
+            android:layout_height="@dimen/dp_18"
+            android:layout_marginStart="@dimen/dp_20"
+            android:layout_marginTop="@dimen/dp_24"
+            android:background="@drawable/btn_green_stu_line_shape"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <TextView
+            android:id="@+id/tv_title"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/dp_16"
+            android:layout_marginEnd="@dimen/dp_16"
+            android:text="确定退课吗?"
+            android:textColor="@color/black_444"
+            android:textSize="@dimen/dp_18"
+            app:layout_constraintBottom_toBottomOf="@id/iv_icon"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toEndOf="@+id/iv_icon"
+            app:layout_constraintTop_toTopOf="@+id/iv_icon" />
+
+        <TextView
+            android:id="@+id/tv_content"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/dp_15"
+            android:text=""
+            android:textColor="@color/black_444"
+            android:textSize="@dimen/dp_16"
+            app:layout_constraintEnd_toEndOf="@+id/tv_title"
+            app:layout_constraintStart_toStartOf="@+id/iv_icon"
+            app:layout_constraintTop_toBottomOf="@+id/iv_icon" />
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/recyclerView"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_marginTop="@dimen/dp_15"
+            android:background="@color/white"
+            android:overScrollMode="never"
+            android:scrollbars="none"
+            android:visibility="gone"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/tv_content"
+            app:layout_goneMarginTop="@dimen/dp_15" />
+
+        <View
+            android:id="@+id/horizontal_line"
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:layout_marginTop="@dimen/dp_15"
+            android:background="@color/divide_color"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/recyclerView" />
+
+        <TextView
+            android:id="@+id/btn_cancel"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/dp_50"
+            android:gravity="center_vertical|left"
+            android:paddingStart="@dimen/dp_60"
+            android:text="取消"
+            android:textColor="@color/colorPrimaryStudent"
+            android:textSize="@dimen/dp_14"
+            app:layout_constraintEnd_toStartOf="@id/vertical_line"
+            app:layout_constraintHorizontal_chainStyle="spread_inside"
+            app:layout_constraintHorizontal_weight="1"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/horizontal_line"
+            app:layout_goneMarginTop="@dimen/dp_15" />
+
+        <View
+            android:id="@+id/vertical_line"
+            android:layout_width="@dimen/dp_1"
+            android:layout_height="@dimen/dp_50"
+            android:background="@color/divide_color"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toStartOf="@id/btn_commit"
+            app:layout_constraintStart_toEndOf="@id/btn_cancel"
+            app:layout_constraintTop_toTopOf="@id/btn_cancel" />
+
+        <TextView
+            android:id="@+id/btn_commit"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/dp_50"
+            android:gravity="center_vertical|end"
+            android:paddingEnd="@dimen/dp_60"
+            android:text="确定"
+            android:textColor="@color/colorPrimaryStudent"
+            android:textSize="@dimen/dp_14"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintHorizontal_weight="1"
+            app:layout_constraintStart_toEndOf="@id/vertical_line"
+            app:layout_constraintTop_toBottomOf="@+id/horizontal_line"
+            app:layout_goneMarginTop="@dimen/dp_15" />
+
+        <TextView
+            android:id="@+id/btn_cancel_match"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/dp_50"
+            android:background="@color/white"
+            android:gravity="center"
+            android:text="取消"
+            android:textColor="@color/colorPrimaryStudent"
+            android:textSize="@dimen/dp_14"
+            android:visibility="gone"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/horizontal_line"
+            app:layout_goneMarginTop="@dimen/dp_15" />
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</LinearLayout>

+ 34 - 0
BaseLibrary/src/main/res/layout/load.xml

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                xmlns:app="http://schemas.android.com/apk/res-auto"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="80dp"
+        android:layout_centerInParent="true"
+        android:background="@drawable/shape_corner"
+        android:gravity="center"
+        android:orientation="vertical">
+
+        <com.cooleshow.base.widgets.loading.SpinKitView
+            style="@style/SpinKitView.Small.FadingCircle"
+            android:layout_width="45dp"
+            android:layout_height="45dp"
+            app:SpinKit_Color="@color/white"
+            app:SpinKit_Style="FadingCircle"/>
+
+        <TextView
+            android:id="@+id/tv_loading"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/dp_15"
+            android:layout_marginTop="5dp"
+            android:layout_marginEnd="@dimen/dp_15"
+            android:text="加载中..."
+            android:textColor="@color/white"
+            android:textSize="14dp"/>
+    </LinearLayout>
+
+</RelativeLayout>

+ 3 - 0
BaseLibrary/src/main/res/values/colors.xml

@@ -92,4 +92,7 @@
     <color name="color_63ffe1">#63FFE1</color>
     <color name="color_fa6400">#FA6400</color>
     <color name="color_ff9300">#FF9300</color>
+    <color name="color_f97215">#F97215</color>
+    <color name="color_ff4444">#FF4444</color>
+    <color name="color_808080">#808080</color>
 </resources>

+ 1 - 0
BaseLibrary/src/main/res/values/strings.xml

@@ -15,4 +15,5 @@
     <string name="nav_bar_cart">聊天</string>
     <string name="nav_bar_msg">商城</string>
     <string name="nav_bar_user">我的</string>
+    <string name="equipment_testing_hint">设备检测需要麦克风、储存权限,去设置?</string>
 </resources>

+ 96 - 0
BaseLibrary/src/main/res/values/styles.xml

@@ -362,4 +362,100 @@
             <enum name="Full" value="1" />
         </attr>
     </declare-styleable>
+
+    <declare-styleable name="RoundProgressBar">
+        <attr name="max" format="integer"></attr>
+        <attr name="startAngle" format="integer"></attr>
+        <attr name="roundColor" format="color" />
+        <attr name="roundProgressColor" format="color" />
+        <attr name="roundWidth" format="dimension"></attr>
+        <attr name="backColor" format="color" />
+        <attr name="textColor" format="color" />
+        <attr name="textSize" format="dimension" />
+        <attr name="textIsDisplayable" format="boolean"></attr>
+        <attr name="style">
+            <enum name="STROKE" value="0"></enum>
+            <enum name="FILL" value="1"></enum>
+        </attr>
+    </declare-styleable>
+
+    <style name="SpinKitView">
+        <item name="android:indeterminateOnly">true</item>
+        <item name="android:minWidth">48dip</item>
+        <item name="android:maxWidth">48dip</item>
+        <item name="android:minHeight">48dip</item>
+        <item name="android:maxHeight">48dip</item>
+    </style>
+
+
+    <style name="SpinKitView.Circle">
+        <item name="SpinKit_Style">Circle</item>
+    </style>
+
+    <style name="SpinKitView.FadingCircle">
+        <item name="SpinKit_Style">FadingCircle</item>
+    </style>
+
+
+    <style name="SpinKitView.ThreeBounce">
+        <item name="SpinKit_Style">ThreeBounce</item>
+    </style>
+
+    <style name="SpinKitView.Large">
+        <item name="android:minWidth">76dip</item>
+        <item name="android:maxWidth">76dip</item>
+        <item name="android:minHeight">76dip</item>
+        <item name="android:maxHeight">76dip</item>
+    </style>
+
+
+    <style name="SpinKitView.Large.Circle">
+        <item name="SpinKit_Style">Circle</item>
+    </style>
+
+
+    <style name="SpinKitView.Large.FadingCircle">
+        <item name="SpinKit_Style">FadingCircle</item>
+    </style>
+
+
+    <style name="SpinKitView.Large.ThreeBounce">
+        <item name="SpinKit_Style">ThreeBounce</item>
+    </style>
+
+
+    <style name="SpinKitView.Small">
+        <item name="android:minWidth">16dip</item>
+        <item name="android:maxWidth">16dip</item>
+        <item name="android:minHeight">16dip</item>
+        <item name="android:maxHeight">16dip</item>
+    </style>
+
+
+    <style name="SpinKitView.Small.Circle">
+        <item name="SpinKit_Style">Circle</item>
+    </style>
+
+
+    <style name="SpinKitView.Small.FadingCircle">
+        <item name="SpinKit_Style">FadingCircle</item>
+    </style>
+
+
+    <style name="SpinKitView.Small.ThreeBounce">
+        <item name="SpinKit_Style">ThreeBounce</item>
+    </style>
+
+    <attr name="SpinKitViewStyle" format="reference" />
+
+    <declare-styleable name="SpinKitView">
+
+        <attr name="SpinKit_Style">
+            <enum name="Circle" value="0" />
+            <enum name="FadingCircle" value="1" />
+            <enum name="ThreeBounce" value="2" />
+
+        </attr>
+        <attr name="SpinKit_Color" format="color" />
+    </declare-styleable>
 </resources>

+ 12 - 1
student/src/main/AndroidManifest.xml

@@ -99,7 +99,7 @@
             <intent-filter>
                 <action android:name="android.intent.action.VIEW" />
                 <category android:name="android.intent.category.DEFAULT" />
-                <data android:scheme="wx149a928c415c137a" />
+                <data android:scheme="wx97408cd22c879ff7" />
             </intent-filter>
 
         </activity>
@@ -128,6 +128,17 @@
             android:name=".ui.course.EvaluateTeacherActivity"
             android:configChanges="orientation|screenSize|keyboardHidden"
             android:screenOrientation="portrait" />
+        <activity
+            android:name=".ui.mine.TeachableInstrumentActivity"
+            android:screenOrientation="portrait" />
+        <activity
+            android:name=".ui.mine.NetworkMonitoringActivity"
+            android:configChanges="orientation|screenSize|keyboardHidden"
+            android:screenOrientation="portrait" />
+        <activity
+            android:name=".ui.mine.EquipmentTestActivity"
+            android:configChanges="orientation|screenSize|keyboardHidden"
+            android:screenOrientation="portrait" />
 
     </application>
 

+ 68 - 0
student/src/main/java/com/cooleshow/student/adapter/TeachableInstrumentAdapter.java

@@ -0,0 +1,68 @@
+package com.cooleshow.student.adapter;
+
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.chad.library.adapter.base.BaseQuickAdapter;
+import com.chad.library.adapter.base.viewholder.BaseViewHolder;
+import com.cooleshow.student.R;
+import com.cooleshow.student.bean.TeachableInstrumentBean;
+
+import java.util.List;
+
+/**
+ * 创建日期:2022/5/13 17:31
+ *
+ * @author Ryan
+ * 类说明:
+ */
+public class TeachableInstrumentAdapter extends BaseQuickAdapter<TeachableInstrumentBean, BaseViewHolder> {
+
+    public TeachableInstrumentAdapter(List<TeachableInstrumentBean> data) {
+        super(R.layout.layout_teachable_instrument, data);
+    }
+
+
+    @Override
+    protected void convert(BaseViewHolder helper, TeachableInstrumentBean item) {
+        TextView tv_title = helper.getView(R.id.tv_title);
+        tv_title.setText(item.name);
+        RecyclerView rv_item=helper.getView(R.id.rv_item);
+        if (null!=item.subjects&&item.subjects.size()>0){
+            rv_item.setVisibility(View.VISIBLE);
+            GridLayoutManager manager = new GridLayoutManager(getContext(), 3);
+            rv_item.setHasFixedSize(true);
+            rv_item.setLayoutManager(manager);
+            TeachableInstrumentItemAdapter teachableInstrumentItemAdapter=new TeachableInstrumentItemAdapter(item.subjects);
+            rv_item.setNestedScrollingEnabled(false);
+            rv_item.setAdapter(teachableInstrumentItemAdapter);
+            teachableInstrumentItemAdapter.setItemSelectListener(new TeachableInstrumentItemAdapter.ItemSelectListener() {
+                @Override
+                public void select(long id) {
+                    setOtherUnSelect(id);
+                }
+            });
+        }else {
+            rv_item.setVisibility(View.GONE);
+        }
+
+    }
+    private void setOtherUnSelect(long id){
+        for (TeachableInstrumentBean teachableInstrumentBean : getData()) {
+            if (null != teachableInstrumentBean.subjects && teachableInstrumentBean.subjects.size() > 0) {
+                for (TeachableInstrumentBean subject : teachableInstrumentBean.subjects) {
+                    if (subject.id==id){
+                        subject.isSelect=true;
+                    }else {
+                        subject.isSelect=false;
+                    }
+                }
+            }
+        }
+        TeachableInstrumentAdapter.this.notifyDataSetChanged();
+    }
+
+}

+ 63 - 0
student/src/main/java/com/cooleshow/student/adapter/TeachableInstrumentItemAdapter.java

@@ -0,0 +1,63 @@
+package com.cooleshow.student.adapter;
+
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.chad.library.adapter.base.BaseQuickAdapter;
+import com.chad.library.adapter.base.viewholder.BaseViewHolder;
+import com.cooleshow.base.utils.GlideUtils;
+import com.cooleshow.base.utils.ToastUtils;
+import com.cooleshow.student.R;
+import com.cooleshow.student.bean.TeachableInstrumentBean;
+
+import java.util.List;
+
+/**
+ * 创建日期:2022/5/13 18:12
+ *
+ * @author Ryan
+ * 类说明:
+ */
+public class TeachableInstrumentItemAdapter extends BaseQuickAdapter<TeachableInstrumentBean, BaseViewHolder> {
+
+    public TeachableInstrumentItemAdapter(List<TeachableInstrumentBean> data) {
+        super(R.layout.layout_teachable_instrument_item, data);
+    }
+
+
+    @Override
+    protected void convert(BaseViewHolder helper, TeachableInstrumentBean item) {
+        if (item == null) {
+            return;
+        }
+        ImageView iv_pic = helper.getView(R.id.iv_pic);
+        ImageView im_check = helper.getView(R.id.im_check);
+        TextView tv_name = helper.getView(R.id.tv_name);
+        GlideUtils.INSTANCE.loadImage(getContext(), item.img, iv_pic);
+        if (item.isSelect) {
+            im_check.setBackgroundResource(R.drawable.icon_check_select);
+        } else {
+            im_check.setBackgroundResource(R.drawable.icon_check_normal);
+        }
+        tv_name.setText(item.name);
+        iv_pic.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+               if (!item.isSelect){
+                   if (null!=itemSelectListener){
+                       itemSelectListener.select(item.id);
+                   }
+               }
+            }
+        });
+    }
+
+    public  interface ItemSelectListener{
+        void select(long id);
+    }
+    private ItemSelectListener itemSelectListener;
+    public void setItemSelectListener(ItemSelectListener itemSelectListener){
+        this.itemSelectListener=itemSelectListener;
+    }
+}

+ 115 - 0
student/src/main/java/com/cooleshow/student/adapter/TestingListAdapter.java

@@ -0,0 +1,115 @@
+package com.cooleshow.student.adapter;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.cooleshow.base.bean.EquipmentTestingBean;
+import com.cooleshow.student.R;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * 创建日期:2022/6/1 17:11
+ *
+ * @author Ryan
+ * 类说明:
+ */
+public class TestingListAdapter extends RecyclerView.Adapter<TestingListAdapter.ViewHolder> {
+
+
+    private Context mContext;
+    private int cont = 0;
+    private List<EquipmentTestingBean> list = new LinkedList<>();
+
+    public TestingListAdapter(Context mContex, List<EquipmentTestingBean> list1) {
+        this.mContext = mContex;
+        list.addAll(list1);
+    }
+
+    @NonNull
+    @Override
+    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+        View inflater = LayoutInflater.from(mContext).inflate(R.layout.testing_list_item, parent, false);
+        return new ViewHolder(inflater);
+
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+        if (position == 5) {
+            holder.line.setVisibility(View.INVISIBLE);
+        } else {
+            holder.line.setVisibility(View.VISIBLE);
+
+        }
+        if (position != 0) {
+            holder.tvStartLine.setVisibility(View.VISIBLE);
+        } else {
+            holder.tvStartLine.setVisibility(View.INVISIBLE);
+        }
+
+        if (list.get(position).getState() == 1) {
+            holder.ivIcon.setBackgroundResource(com.cooleshow.base.R.drawable.icon_testing_success);
+        } else if (list.get(position).getState() == 2) {
+            holder.ivIcon.setBackgroundResource(com.cooleshow.base.R.drawable.icon_testing_closea);
+        } else if (list.get(position).getState() == 3) {
+            holder.ivIcon.setBackgroundResource(com.cooleshow.base.R.drawable.icon_testing_wait);
+        } else if (list.get(position).getState() == 4) {
+            holder.ivIcon.setBackgroundResource(com.cooleshow.base.R.drawable.icon_testing_default);
+        }
+
+        if (position < cont) {
+            if (position == cont - 1) {
+                holder.line.setBackgroundResource(com.cooleshow.base.R.drawable.ic_dash_line);
+            } else {
+                holder.line.setBackgroundResource(com.cooleshow.base.R.color.gray_AA);
+            }
+            holder.tvStartLine.setBackgroundResource(com.cooleshow.base.R.color.gray_AA);
+        } else {
+
+            holder.line.setBackgroundResource(com.cooleshow.base.R.drawable.ic_dash_line);
+            holder.tvStartLine.setBackgroundResource(com.cooleshow.base.R.drawable.ic_dash_line);
+
+        }
+
+    }
+
+    @Override
+    public int getItemCount() {
+        return 6;
+    }
+
+
+    public void setData(List<EquipmentTestingBean> list1, int cont) {
+        list.clear();
+        list.addAll(list1);
+        this.cont = cont;
+        notifyDataSetChanged();
+    }
+
+
+    public class ViewHolder extends RecyclerView.ViewHolder {
+
+
+        private ImageView ivIcon;
+        private View line;
+        private View tvStartLine;
+
+        public ViewHolder(View itemView) {
+            super(itemView);
+            ivIcon = itemView.findViewById(R.id.iv_icon);
+            line = itemView.findViewById(R.id.tv_line);
+            tvStartLine = itemView.findViewById(R.id.tv_start_line);
+        }
+
+
+    }
+
+}

+ 26 - 0
student/src/main/java/com/cooleshow/student/api/APIService.java

@@ -23,6 +23,7 @@ import com.cooleshow.student.bean.SparringCourseCommentBean;
 import com.cooleshow.student.bean.SparringCourseHomeworkBean;
 import com.cooleshow.student.bean.StudentUserInfo;
 import com.cooleshow.student.bean.SystemMessageBean;
+import com.cooleshow.student.bean.TeachableInstrumentBean;
 import com.cooleshow.student.bean.VideoCourseListBean;
 import com.cooleshow.usercenter.bean.SetDetailBean;
 import com.cooleshow.usercenter.bean.UserInfo;
@@ -335,4 +336,29 @@ public interface APIService {
      */
     @POST(TEACHER_GROUP + "homework/review")
     Observable<BaseResponse<Object>> submitSparringCourseHomeworkComment(@Body RequestBody body);
+
+
+    /**
+     * 乐器列表查询
+     *
+     * @return
+     */
+    @GET(STUDENT_GROUP + "subject/subjectSelect")
+    Observable<BaseResponse<List<TeachableInstrumentBean>>> subjectSelect();
+
+    /**
+     * 根据声部编号查询声部
+     * @param id
+     * @return
+     */
+    @GET(STUDENT_GROUP + "subject/get/{id}")
+    Observable<BaseResponse<TeachableInstrumentBean>> getSubjectFromId(@Path("id") String id);
+
+    /**
+     * 设置声部
+     * @param subjectIds
+     * @return
+     */
+    @GET(STUDENT_GROUP + "student/setSubject")
+    Observable<BaseResponse<Object>> setSubject(@Query("subjectIds") String subjectIds);
 }

+ 55 - 0
student/src/main/java/com/cooleshow/student/bean/TeachableInstrumentBean.java

@@ -0,0 +1,55 @@
+package com.cooleshow.student.bean;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 创建日期:2022/5/13 16:59
+ *
+ * @author Ryan
+ * 类说明:
+ */
+public class TeachableInstrumentBean implements Serializable {
+    /**
+     * "code": "",
+     * "createTime": "",
+     * "delFlag": true,
+     * "desc": "",
+     * "id": 0,
+     * "img": "",
+     * "name": "",
+     * "parentSubjectId": 0,
+     * "parentSubjectName": "",
+     * "subjects": [
+     * {
+     * "code": "",
+     * "createTime": "",
+     * "delFlag": true,
+     * "desc": "",
+     * "id": 0,
+     * "img": "",
+     * "name": "",
+     * "parentSubjectId": 0,
+     * "parentSubjectName": "",
+     * "subjects": [
+     * {}
+     * ],
+     * "updateTime": ""
+     * }
+     * ],
+     * "updateTime": ""
+     */
+    public String code;
+    public String createTime;
+    public boolean delFlag;
+    public String desc;
+    public long id;
+    public String img;
+    public String name;
+    public int parentSubjectId;
+    public String parentSubjectName;
+    public List<TeachableInstrumentBean> subjects;
+    public String updateTime;
+    public boolean isSelect;
+
+}

+ 3 - 3
student/src/main/java/com/cooleshow/student/bean/weixinpay/WeixinPayInfo.java

@@ -13,7 +13,7 @@ public class WeixinPayInfo {
     private String packageValue;
     private String partnerid;
     private String prepayid;
-    private String Sign;
+    private String sign;
     private String timestamp;
 
     public String getAppid() {
@@ -57,11 +57,11 @@ public class WeixinPayInfo {
     }
 
     public String getSign() {
-        return Sign;
+        return sign;
     }
 
     public void setSign(String sign) {
-        Sign = sign;
+        this.sign = sign;
     }
 
     public String getTimestamp() {

+ 17 - 0
student/src/main/java/com/cooleshow/student/contract/EquipmentTestContract.java

@@ -0,0 +1,17 @@
+package com.cooleshow.student.contract;
+
+import com.cooleshow.base.presenter.view.BaseView;
+
+/**
+ * 创建日期:2022/6/1 16:24
+ *
+ * @author Ryan
+ * 类说明:
+ */
+public interface EquipmentTestContract {
+    interface EquipmentTestView extends BaseView {
+
+    }
+    interface Presenter {
+    }
+}

+ 11 - 0
student/src/main/java/com/cooleshow/student/contract/HomeContract.java

@@ -2,9 +2,14 @@ package com.cooleshow.student.contract;
 
 import com.cooleshow.base.presenter.view.BaseView;
 import com.cooleshow.student.bean.AppHomeBean;
+import com.cooleshow.student.bean.CountOfUnreadBean;
 import com.cooleshow.student.bean.HomeLiveAndVideoBean;
 import com.cooleshow.student.bean.HomeStyleBean;
 import com.cooleshow.student.bean.HotAlbumBean;
+import com.cooleshow.student.bean.StudentUserInfo;
+import com.cooleshow.student.bean.TeachableInstrumentBean;
+
+import java.util.List;
 
 /**
  * 创建日期:2022/5/26 10:09
@@ -21,6 +26,12 @@ public interface HomeContract {
         void queryLiveAndVideoSuccess(HomeLiveAndVideoBean data);
 
         void getStylePageSuccess(HomeStyleBean data);
+
+        void queryUserInfoSuccess(StudentUserInfo data);
+
+        void getSubjectFromIdSuccess(TeachableInstrumentBean o);
+
+        void queryCountOfUnreadSuccess(List<CountOfUnreadBean> data);
     }
 
     interface Presenter {

+ 17 - 0
student/src/main/java/com/cooleshow/student/contract/NetworkMonitoringContract.java

@@ -0,0 +1,17 @@
+package com.cooleshow.student.contract;
+
+import com.cooleshow.base.presenter.view.BaseView;
+
+/**
+ * 创建日期:2022/6/1 15:06
+ *
+ * @author Ryan
+ * 类说明:
+ */
+public interface NetworkMonitoringContract {
+    interface NetworkMonitoringView extends BaseView {
+
+    }
+    interface Presenter {
+    }
+}

+ 23 - 0
student/src/main/java/com/cooleshow/student/contract/TeachableInstrumentContract.java

@@ -0,0 +1,23 @@
+package com.cooleshow.student.contract;
+
+import com.cooleshow.base.presenter.view.BaseView;
+import com.cooleshow.student.bean.TeachableInstrumentBean;
+
+import java.util.List;
+
+/**
+ * 创建日期:2022/5/13 16:33
+ *
+ * @author Ryan
+ * 类说明:
+ */
+public interface TeachableInstrumentContract {
+    interface TeachableInstrumentView extends BaseView {
+        void subjectSelectSuccess(List<TeachableInstrumentBean> styleInfoBean);
+        void setSubjectSuccess(Object o);
+    }
+
+    interface Presenter {
+        void subjectSelect();
+    }
+}

+ 51 - 0
student/src/main/java/com/cooleshow/student/presenter/main/HomePresenter.java

@@ -9,16 +9,21 @@ import com.cooleshow.base.utils.ToastUtils;
 import com.cooleshow.base.utils.helper.ErrorParse;
 import com.cooleshow.student.api.APIService;
 import com.cooleshow.student.bean.AppHomeBean;
+import com.cooleshow.student.bean.CountOfUnreadBean;
 import com.cooleshow.student.bean.HomeLiveAndVideoBean;
 import com.cooleshow.student.bean.HomeStyleBean;
 import com.cooleshow.student.bean.HotAlbumBean;
 import com.cooleshow.student.bean.PayTestBean;
+import com.cooleshow.student.bean.StudentUserInfo;
+import com.cooleshow.student.bean.TeachableInstrumentBean;
 import com.cooleshow.student.contract.HomeContract;
 import com.cooleshow.student.contract.MineContract;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 
+import java.util.List;
+
 /**
  * 创建日期:2022/5/26 10:09
  *
@@ -143,4 +148,50 @@ public class HomePresenter extends BasePresenter<HomeContract.HomeView> implemen
             }
         });
     }
+
+    public void queryUserInfo() {
+        addSubscribe(create(APIService.class).queryUserInfo(), new BaseObserver<StudentUserInfo>(getView()) {
+            @Override
+            protected void onSuccess(StudentUserInfo data) {
+                if (getView() != null) {
+                    getView().queryUserInfoSuccess(data);
+                }
+            }
+        });
+    }
+
+    public void getSubjectFromId(String subjectId) {
+        addSubscribe(create(APIService.class).getSubjectFromId(subjectId), new BaseObserver<TeachableInstrumentBean>(getView()) {
+            @Override
+            protected void onSuccess(TeachableInstrumentBean data) {
+                if (getView() != null) {
+                    getView().getSubjectFromIdSuccess(data);
+                }
+            }
+        });
+    }
+
+
+    public void queryCountOfUnread() {
+
+        addSubscribe(create(APIService.class).queryCountOfUnread(), new BaseObserver<List<CountOfUnreadBean>>(getView()) {
+            @Override
+            protected void onSuccess(List<CountOfUnreadBean> data) {
+                if (getView() != null) {
+                    getView().queryCountOfUnreadSuccess(data);
+                }
+            }
+
+            @Override
+            public void onComplete() {
+                super.onComplete();
+            }
+
+            @Override
+            public void onError(Throwable e) {
+                super.onError(e);
+
+            }
+        });
+    }
 }

+ 13 - 0
student/src/main/java/com/cooleshow/student/presenter/mine/EquipmentTestPresenter.java

@@ -0,0 +1,13 @@
+package com.cooleshow.student.presenter.mine;
+
+import com.cooleshow.base.presenter.BasePresenter;
+import com.cooleshow.student.contract.EquipmentTestContract;
+
+/**
+ * 创建日期:2022/6/1 16:23
+ *
+ * @author Ryan
+ * 类说明:
+ */
+public class EquipmentTestPresenter extends BasePresenter<EquipmentTestContract.EquipmentTestView> implements EquipmentTestContract.Presenter {
+}

+ 14 - 0
student/src/main/java/com/cooleshow/student/presenter/mine/NetworkMonitoringPresenter.java

@@ -0,0 +1,14 @@
+package com.cooleshow.student.presenter.mine;
+
+import com.cooleshow.base.presenter.BasePresenter;
+import com.cooleshow.student.contract.NetworkMonitoringContract;
+
+/**
+ * 创建日期:2022/6/1 15:06
+ *
+ * @author Ryan
+ * 类说明:
+ */
+public class NetworkMonitoringPresenter extends BasePresenter<NetworkMonitoringContract.NetworkMonitoringView> implements NetworkMonitoringContract.Presenter {
+
+}

+ 56 - 0
student/src/main/java/com/cooleshow/student/presenter/mine/TeachableInstrumentPresenter.java

@@ -0,0 +1,56 @@
+package com.cooleshow.student.presenter.mine;
+
+import com.cooleshow.base.presenter.BasePresenter;
+import com.cooleshow.base.rx.BaseObserver;
+import com.cooleshow.student.api.APIService;
+import com.cooleshow.student.bean.TeachableInstrumentBean;
+import com.cooleshow.student.contract.TeachableInstrumentContract;
+
+
+import java.util.List;
+
+/**
+ * 创建日期:2022/5/13 16:32
+ *
+ * @author Ryan
+ * 类说明:
+ */
+public class TeachableInstrumentPresenter extends BasePresenter<TeachableInstrumentContract.TeachableInstrumentView> implements TeachableInstrumentContract.Presenter {
+
+    @Override
+    public void subjectSelect() {
+        getView().showLoading();
+        addSubscribe(create(APIService.class).subjectSelect(), new BaseObserver<List<TeachableInstrumentBean>>(getView()) {
+            @Override
+            protected void onSuccess(List<TeachableInstrumentBean> data) {
+                if (getView() != null) {
+                    getView().subjectSelectSuccess(data);
+                }
+            }
+            @Override
+            public void onComplete() {
+                super.onComplete();
+                getView().hideLoading();
+            }
+
+        });
+    }
+
+    public void setSubject(String subjectId){
+        getView().showLoading();
+        addSubscribe(create(APIService.class).setSubject(subjectId), new BaseObserver<Object>(getView()) {
+            @Override
+            protected void onSuccess(Object data) {
+                if (getView() != null) {
+                    getView().setSubjectSuccess(data);
+                }
+            }
+            @Override
+            public void onComplete() {
+                super.onComplete();
+                getView().hideLoading();
+            }
+
+        });
+    }
+}

+ 84 - 8
student/src/main/java/com/cooleshow/student/ui/main/HomeFragment.java

@@ -2,8 +2,11 @@ package com.cooleshow.student.ui.main;
 
 import android.app.Activity;
 import android.app.Dialog;
+import android.content.Intent;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Bundle;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
@@ -11,6 +14,7 @@ import android.widget.ImageView;
 import android.widget.LinearLayout;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.core.widget.NestedScrollView;
 import androidx.fragment.app.Fragment;
 import androidx.recyclerview.widget.GridLayoutManager;
@@ -25,6 +29,7 @@ import com.cooleshow.base.common.BaseApplication;
 import com.cooleshow.base.common.WebConstants;
 import com.cooleshow.base.router.RouterPath;
 import com.cooleshow.base.ui.fragment.BaseMVPFragment;
+import com.cooleshow.base.utils.FileUtils;
 import com.cooleshow.base.utils.GlideUtils;
 import com.cooleshow.base.utils.helper.QMUIDisplayHelper;
 import com.cooleshow.student.R;
@@ -35,9 +40,12 @@ import com.cooleshow.student.adapter.HomeTeacherStyleAdapter;
 import com.cooleshow.student.adapter.HomeVideoCourseAdapter;
 import com.cooleshow.student.adapter.HomeWonderfulInfoAdapter;
 import com.cooleshow.student.bean.AppHomeBean;
+import com.cooleshow.student.bean.CountOfUnreadBean;
 import com.cooleshow.student.bean.HomeLiveAndVideoBean;
 import com.cooleshow.student.bean.HomeStyleBean;
 import com.cooleshow.student.bean.HotAlbumBean;
+import com.cooleshow.student.bean.StudentUserInfo;
+import com.cooleshow.student.bean.TeachableInstrumentBean;
 import com.cooleshow.student.contract.HomeContract;
 import com.cooleshow.student.databinding.FragmentHomeLayoutBinding;
 import com.cooleshow.student.presenter.main.HomePresenter;
@@ -50,6 +58,7 @@ import com.youth.banner.adapter.BannerImageAdapter;
 import com.youth.banner.holder.BannerImageHolder;
 import com.youth.banner.listener.OnBannerListener;
 
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -110,11 +119,25 @@ public class HomeFragment extends BaseMVPFragment<FragmentHomeLayoutBinding, Hom
                         .withString(WebConstants.WEB_URL, WebConstants.STUDENT_TEACHER_ELEGANT)
                         .navigation();
                 break;
+            case R.id.tv_title:
+            case R.id.im_title:
+                Bundle bundle = new Bundle();
+                bundle.putSerializable("selectTeachableInstrument", (Serializable) teachableInstrumentBean);
+                ARouter.getInstance().build(RouterPath.MineCenter.MINE_TEACHABLE_INSTRUMENT)
+                        .withBundle("bundle", bundle)
+                        .navigation(((MainActivity)getActivity()), MainActivity.SELECT_RESULT);
+                break;
 
         }
     }
 
     @Override
+    public void onResume() {
+        super.onResume();
+        presenter.queryCountOfUnread();
+    }
+
+    @Override
     protected FragmentHomeLayoutBinding getLayoutView() {
         return FragmentHomeLayoutBinding.inflate(getLayoutInflater());
     }
@@ -143,17 +166,19 @@ public class HomeFragment extends BaseMVPFragment<FragmentHomeLayoutBinding, Hom
         mViewBinding.tvGoLive.setOnClickListener(this);
         mViewBinding.tvTeacherStyleMore.setOnClickListener(this);
         mViewBinding.imTeacherStyleMore.setOnClickListener(this);
+        mViewBinding.tvTitle.setOnClickListener(this);
+        mViewBinding.imTitle.setOnClickListener(this);
         mViewBinding.scrollLayout.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
             @Override
             public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
                 boolean localVisibleRect = getLocalVisibleRect(getActivity(), banner, 10);
                 //banner可见的时候就自动循环,否则就停止,解决问题:在scrollview到最底部时候,由于banner自动到第一个时候就往上顶一段距离
-                if (localVisibleRect){
-                    if (null!=banner){
+                if (localVisibleRect) {
+                    if (null != banner) {
                         banner.isAutoLoop(true);
                     }
-                }else {
-                    if (null!=banner){
+                } else {
+                    if (null != banner) {
                         banner.isAutoLoop(false);
                     }
                 }
@@ -208,6 +233,7 @@ public class HomeFragment extends BaseMVPFragment<FragmentHomeLayoutBinding, Hom
         presenter.userAccountPage();
         presenter.queryLiveAndVideo();
         presenter.getStylePage();
+        presenter.queryUserInfo();
         mViewBinding.refreshLayout.setOnRefreshListener(new OnRefreshListener() {
             @Override
             public void onRefresh(@NonNull RefreshLayout refreshLayout) {
@@ -230,12 +256,13 @@ public class HomeFragment extends BaseMVPFragment<FragmentHomeLayoutBinding, Hom
         showDialog(appHomeBean.flashPage);
     }
 
-    private void showDialog(List<AppHomeBean.ItemBean> flashPage){
-        if (null==flashPage||flashPage.size()==0){
+    private void showDialog(List<AppHomeBean.ItemBean> flashPage) {
+        if (null == flashPage || flashPage.size() == 0) {
             return;
         }
-        DialogUtils.showHomeDialog(getContext(),flashPage.get(0));
+        DialogUtils.showHomeDialog(getContext(), flashPage.get(0));
     }
+
     @Override
     public void hotAlbumListSuccess(HotAlbumBean data) {
         if (null == data || null == data.rows || data.rows.size() == 0) {
@@ -293,6 +320,38 @@ public class HomeFragment extends BaseMVPFragment<FragmentHomeLayoutBinding, Hom
 
     }
 
+    @Override
+    public void queryUserInfoSuccess(StudentUserInfo data) {
+        String subjectId = data.subjectId;
+        String firstSubjectId = "";
+        if (!TextUtils.isEmpty(subjectId)) {
+            if (subjectId.contains(",")) {
+                String[] split = subjectId.split(",");
+                firstSubjectId = split[0];
+            } else {
+                firstSubjectId = subjectId;
+            }
+            presenter.getSubjectFromId(firstSubjectId);
+
+        } else {
+            mViewBinding.tvTitle.setText("请选择");
+        }
+    }
+
+    private TeachableInstrumentBean teachableInstrumentBean = null;
+
+    @Override
+    public void getSubjectFromIdSuccess(TeachableInstrumentBean data) {
+        setTeachableInstrumentBean(data);
+    }
+
+
+
+    public void setTeachableInstrumentBean(TeachableInstrumentBean data) {
+        mViewBinding.tvTitle.setText(data.name);
+        teachableInstrumentBean = data;
+    }
+
     private void initRecentLive(HomeLiveAndVideoBean.RecentCoursesBean recentCourses) {
         if (null == recentCourses) {
             mViewBinding.clLive.setVisibility(View.GONE);
@@ -460,7 +519,7 @@ public class HomeFragment extends BaseMVPFragment<FragmentHomeLayoutBinding, Hom
 
         int[] location = new int[2];
 
-        location[1] = location[1] + DisplayUtils.dip2px(BaseApplication.context,offsetY);
+        location[1] = location[1] + DisplayUtils.dip2px(BaseApplication.context, offsetY);
 
         view.getLocationInWindow(location);
 
@@ -477,4 +536,21 @@ public class HomeFragment extends BaseMVPFragment<FragmentHomeLayoutBinding, Hom
         }
 
     }
+
+
+    @Override
+    public void queryCountOfUnreadSuccess(List<CountOfUnreadBean> data) {
+        if (null==data||data.size()==0){
+            return;
+        }
+        int totalCount=0;
+        for (CountOfUnreadBean datum : data) {
+            totalCount+=datum.value;
+        }
+        if (totalCount>0){
+            mViewBinding.viewUnreadMessage.setVisibility(View.VISIBLE);
+        }else {
+            mViewBinding.viewUnreadMessage.setVisibility(View.GONE);
+        }
+    }
 }

+ 17 - 0
student/src/main/java/com/cooleshow/student/ui/main/MainActivity.java

@@ -1,5 +1,6 @@
 package com.cooleshow.student.ui.main;
 
+import android.content.Intent;
 import android.os.Bundle;
 import android.text.TextUtils;
 import android.view.MenuItem;
@@ -16,6 +17,7 @@ import com.cooleshow.base.utils.LogUtils;
 import com.cooleshow.base.utils.helper.QMUIStatusBarHelper;
 import com.cooleshow.student.R;
 import com.cooleshow.student.adapter.HomePageAdapter;
+import com.cooleshow.student.bean.TeachableInstrumentBean;
 import com.cooleshow.student.contract.MainContract;
 import com.cooleshow.student.databinding.ActivityMainBinding;
 import com.cooleshow.student.presenter.main.MainPresenter;
@@ -26,6 +28,7 @@ import com.daya.live_teaching.im.IMManager;
 import com.google.android.material.bottomnavigation.BottomNavigationView;
 
 import java.util.ArrayList;
+import java.util.List;
 
 import io.rong.imlib.RongIMClient;
 
@@ -37,6 +40,7 @@ import io.rong.imlib.RongIMClient;
  */
 @Route(path = RouterPath.APPCenter.PATH_HOME)
 public class MainActivity extends BaseMVPActivity<ActivityMainBinding, MainPresenter> implements MainContract.MainView {
+    public static final int SELECT_RESULT = 1001;
     private ArrayList<Fragment> mFragments = new ArrayList<>();
     private HomeFragment mHomeFragment;
     private MineFragment mMineFragment;
@@ -178,4 +182,17 @@ public class MainActivity extends BaseMVPActivity<ActivityMainBinding, MainPrese
     protected MainPresenter createPresenter() {
         return new MainPresenter();
     }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+        if (resultCode == RESULT_OK) {
+            if (requestCode == SELECT_RESULT) {
+                if (null!=mHomeFragment){
+                    TeachableInstrumentBean dataSerializableExtra = (TeachableInstrumentBean) data.getSerializableExtra("selectTeachableInstrument");
+                    mHomeFragment.setTeachableInstrumentBean(dataSerializableExtra);
+                }
+            }
+        }
+    }
 }

+ 38 - 2
student/src/main/java/com/cooleshow/student/ui/main/MineFragment.java

@@ -1,7 +1,9 @@
 package com.cooleshow.student.ui.main;
 
+import android.Manifest;
 import android.text.TextUtils;
 import android.view.View;
+import android.widget.TextView;
 
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
@@ -11,6 +13,8 @@ import com.cooleshow.base.common.WebConstants;
 import com.cooleshow.base.router.RouterPath;
 import com.cooleshow.base.ui.fragment.BaseMVPFragment;
 import com.cooleshow.base.utils.GlideUtils;
+import com.cooleshow.base.utils.PermissionUtils;
+import com.cooleshow.base.widgets.DialogUtil;
 import com.cooleshow.student.R;
 import com.cooleshow.student.adapter.ItemMarkAdapter;
 import com.cooleshow.student.bean.StudentUserInfo;
@@ -18,6 +22,7 @@ import com.cooleshow.student.contract.MineContract;
 import com.cooleshow.student.databinding.FragmentMineLayoutBinding;
 import com.cooleshow.student.presenter.main.MinePresenter;
 import com.cooleshow.student.ui.course.SparringCourseDetailActivity;
+import com.tbruyelle.rxpermissions3.RxPermissions;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -85,12 +90,15 @@ public class MineFragment extends BaseMVPFragment<FragmentMineLayoutBinding, Min
                 break;
             case R.id.tv_network_detection:
                 //网络检测
+                ARouter.getInstance().build(RouterPath.MineCenter.MINE_NETWORK_MONITORING)
+                        .navigation();
                 break;
             case R.id.tv_device_detection:
                 //设备检测
+                checkPermission();
                 //支付测试
-                ARouter.getInstance().build(RouterPath.MineCenter.MINE_PAY_TEST)
-                        .navigation();
+               /* ARouter.getInstance().build(RouterPath.MineCenter.MINE_PAY_TEST)
+                        .navigation();*/
                 break;
             case R.id.tv_help:
                 //帮助中心
@@ -116,6 +124,34 @@ public class MineFragment extends BaseMVPFragment<FragmentMineLayoutBinding, Min
         }
     }
 
+    private void checkPermission(){
+        new RxPermissions(this)
+                .request(Manifest.permission.RECORD_AUDIO,
+                        Manifest.permission.WRITE_EXTERNAL_STORAGE)
+                .subscribe(granted -> {
+                    if (granted) {
+                        ARouter.getInstance().build(RouterPath.MineCenter.MINE_EQUIPMENT_TEST)
+                                .navigation();
+                    } else {
+                        DialogUtil.showInCenter(getChildFragmentManager(), com.cooleshow.base.R.layout.common_popu_stu, (holder, dialog) -> {
+                            TextView tvTitle = holder.getView(com.cooleshow.base.R.id.tv_title);
+                            TextView tvContent = holder.getView(com.cooleshow.base.R.id.tv_content);
+                            TextView btncancel = holder.getView(com.cooleshow.base.R.id.btn_cancel);
+                            TextView btnCommit = holder.getView(com.cooleshow.base.R.id.btn_commit);
+                            tvTitle.setText("提示");
+                            tvContent.setText(getResources().getString(com.cooleshow.base.R.string.equipment_testing_hint));
+                            btncancel.setOnClickListener(view1 -> {
+                                dialog.dismiss();
+                            });
+                            btnCommit.setOnClickListener(view1 -> {
+                                PermissionUtils.toSelfSetting(getContext());
+                                dialog.dismiss();
+                            });
+                        });
+                    }
+                });
+    }
+
     @Override
     protected FragmentMineLayoutBinding getLayoutView() {
         return FragmentMineLayoutBinding.inflate(getLayoutInflater());

+ 394 - 0
student/src/main/java/com/cooleshow/student/ui/mine/EquipmentTestActivity.java

@@ -0,0 +1,394 @@
+package com.cooleshow.student.ui.mine;
+
+import android.content.Context;
+import android.content.Intent;
+import android.media.MediaPlayer;
+import android.media.MediaRecorder;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Handler;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.style.ForegroundColorSpan;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.core.app.NotificationManagerCompat;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.alibaba.android.arouter.facade.annotation.Route;
+import com.cooleshow.base.bean.EquipmentTestingBean;
+import com.cooleshow.base.recorder.AudioRecorder;
+import com.cooleshow.base.router.RouterPath;
+import com.cooleshow.base.ui.activity.BaseMVPActivity;
+import com.cooleshow.base.utils.FileUtils;
+import com.cooleshow.base.utils.NetworkUtil;
+import com.cooleshow.base.widgets.DialogUtil;
+import com.cooleshow.student.R;
+import com.cooleshow.student.adapter.TestingListAdapter;
+import com.cooleshow.student.contract.EquipmentTestContract;
+import com.cooleshow.student.databinding.ActivityEquipmentTestBinding;
+import com.cooleshow.student.presenter.mine.EquipmentTestPresenter;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Timer;
+
+/**
+ * 创建日期:2022/6/1 16:21
+ *
+ * @author Ryan
+ * 类说明:
+ */
+@Route(path = RouterPath.MineCenter.MINE_EQUIPMENT_TEST)
+public class EquipmentTestActivity extends BaseMVPActivity<ActivityEquipmentTestBinding, EquipmentTestPresenter> implements EquipmentTestContract.EquipmentTestView, View.OnClickListener {
+
+    private ImageView ivIcon;
+    private TextView tvTitle;
+    private TextView tvHint;
+    private RecyclerView recyclerView;
+    private Button btnCancel;
+    private Button btnConfirm;
+    private Button btnNext;
+    private List<EquipmentTestingBean> list = new LinkedList<>();
+    ;
+    private int cont = 1;
+    private AudioRecorder mAudioRecorder;
+    private Timer timer;
+    private boolean isRecording = false;
+    private int recorderSecondsElapsed;
+    private int playerSecondsElapsed;
+    private String mFileName = null;
+    private String mFilePath = null;
+    private File mAudioFile;
+    private boolean isPlaying = false;
+    private Handler mHandler = new Handler();
+
+    private MediaPlayer mMediaPlayer = null;
+    private String fileLength;
+    TestingListAdapter adapter;
+
+    @Override
+    protected void initView() {
+        ivIcon = viewBinding.imageView;
+        tvTitle = viewBinding.tvTitle;
+        tvHint = viewBinding.tvHint;
+        btnCancel = viewBinding.btnCancel;
+        btnConfirm = viewBinding.btnConfirm;
+        btnNext = viewBinding.btnNext;
+        recyclerView = viewBinding.recyclerView;
+        btnNext.setOnClickListener(this);
+
+    }
+
+    @Override
+    public void initData() {
+        super.initData();
+        list.clear();
+        for (int i = 0; i < 6; i++) {
+            EquipmentTestingBean bean = new EquipmentTestingBean();
+            if (0 == i) {
+                bean.setName("设备检测");
+                bean.setContent("为确保您能正常上课,现在进行声音测试");
+                bean.setIcon(R.drawable.icon_testing_phone);
+                bean.setState(3);
+            }
+            if (1 == i) {
+                bean.setName("手机话筒检测");
+                bean.setContent("请按录音并念出下方文字\n“我正在测试话筒与扬声器”");
+                bean.setIcon(R.drawable.icon_testing_recorder);
+                bean.setState(4);
+            }
+            if (2 == i) {
+                bean.setName("扬声器检测");
+                bean.setContent("录音内容播放中请听是否有声音");
+                bean.setIcon(R.drawable.icon_testing_play);
+                bean.setState(4);
+            }
+            if (3 == i) {
+                bean.setName("设备检测成功");
+                bean.setContent("恭喜您!话筒与扬声器测试已通过");
+                bean.setIcon(R.drawable.icon_recorder_success);
+                bean.setState(4);
+            }
+            if (4 == i) {
+                bean.setName("网络检测成功");
+                bean.setContent("您当前的网络状态良好");
+                bean.setIcon(R.drawable.icon_testing_network);
+                bean.setState(4);
+            }
+            if (5 == i) {
+                bean.setName("通知权限");
+                bean.setContent("通知权限未开启,可能错过上课提醒哦!快去开启通知权限吧~");
+                bean.setIcon(R.drawable.icon_testing_notice);
+                bean.setState(4);
+            }
+            list.add(bean);
+        }
+
+        GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 6);
+        recyclerView.setLayoutManager(gridLayoutManager);
+        adapter = new TestingListAdapter(this, list);
+        recyclerView.setAdapter(adapter);
+    }
+
+    @Override
+    public void onClick(View view) {
+        switch (view.getId()) {
+            case R.id.btn_next:
+                list.get(0).setState(1);
+                switch (cont) {
+                    case 1:
+                        cont = 2;
+                        tvTitle.setText(list.get(1).getName());
+                        SpannableString spannableString = new SpannableString(list.get(1).getContent());
+                        spannableString.setSpan(new ForegroundColorSpan(getResources().getColor(com.cooleshow.base.R.color.color_f97215)), 12, spannableString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                        tvHint.setText(spannableString);
+                        list.get(1).setState(3);
+                        btnNext.setText("开始录音");
+                        ivIcon.setImageResource(list.get(1).getIcon());
+                        break;
+                    case 2:
+                    case 3:
+                        if (!isRecording) {
+                            cont = 3;
+                            startRecorder();
+                            btnNext.setText("停止录音");
+                        } else {
+                            cont = 4;
+                            stopRecorder();
+                            startPlaying();
+                            btnNext.setText("下一步");
+                            btnConfirm.setVisibility(View.VISIBLE);
+                            btnCancel.setVisibility(View.VISIBLE);
+                            btnNext.setVisibility(View.GONE);
+                            tvTitle.setText(list.get(2).getName());
+                            tvHint.setText(list.get(2).getContent());
+                            ivIcon.setImageResource(list.get(2).getIcon());
+                            list.get(1).setState(1);
+                            list.get(2).setState(3);
+                            btnCancel.setOnClickListener(view1 -> {
+                                stopPlaying();
+                                list.get(1).setState(2);
+                                list.get(2).setState(2);
+                                list.get(3).setState(2);
+                                list.get(4).setState(3);
+                                tvTitle.setText("设备检测失败");
+                                tvHint.setText("话筒或者扬声器故障,请检查设备是否处于静音或者音量过低");
+                                btnNext.setVisibility(View.VISIBLE);
+                                btnConfirm.setVisibility(View.GONE);
+                                btnCancel.setVisibility(View.GONE);
+                                adapter.setData(list, cont);
+
+                            });
+                            btnConfirm.setOnClickListener(view1 -> {
+                                stopPlaying();
+                                list.get(2).setState(1);
+                                list.get(3).setState(1);
+                                list.get(4).setState(3);
+                                tvTitle.setText(list.get(3).getName());
+                                tvHint.setText(list.get(3).getContent());
+                                ivIcon.setImageResource(list.get(3).getIcon());
+                                btnNext.setVisibility(View.VISIBLE);
+                                btnConfirm.setVisibility(View.GONE);
+                                btnCancel.setVisibility(View.GONE);
+                                adapter.setData(list, cont);
+
+                            });
+                        }
+                        break;
+                    case 4:
+                        cont = 5;
+                        btnNext.setText("下一步");
+                        ivIcon.setImageResource(list.get(4).getIcon());
+                        list.get(5).setState(3);
+                        if (NetworkUtil.isNetworkAvailable(this)) {
+                            if (NetworkUtil.getNetWorkType(this) == NetworkUtil.NETWORKTYPE_3G || NetworkUtil.getNetWorkType(this) == NetworkUtil.NETWORKTYPE_WIFI) {
+                                list.get(4).setState(1);
+                                tvTitle.setText(list.get(4).getName());
+                                tvHint.setText(list.get(4).getContent());
+                            } else {
+                                list.get(4).setState(2);
+                                tvTitle.setText("网络检测失败");
+                                tvHint.setText("当前网络不畅,请检查网络状态");
+                            }
+
+                        } else {
+                            list.get(4).setState(2);
+                            tvTitle.setText("网络检测失败");
+                            tvHint.setText("当前无网络连接,请检查网络状态");
+                        }
+                        break;
+                    case 5:
+                        cont = 6;
+                        tvTitle.setText(list.get(5).getName());
+
+                        ivIcon.setImageResource(list.get(5).getIcon());
+                        btnNext.setText("完成检测");
+                        if (isNotificationEnabled(this)) {
+                            list.get(5).setState(1);
+                            tvHint.setText("通知权限已开启,再也不会错过上课提醒了");
+                        } else {
+                            list.get(5).setState(2);
+                            tvHint.setText(list.get(5).getContent());
+                            DialogUtil.showInCenter(getSupportFragmentManager(), com.cooleshow.base.R.layout.common_popu, (holder, dialog1) -> {
+                                TextView tvTitle = holder.getView(R.id.tv_title);
+                                TextView tvContent = holder.getView(R.id.tv_content);
+                                TextView btncancel = holder.getView(R.id.btn_cancel);
+                                TextView btnCommit = holder.getView(R.id.btn_commit);
+                                tvTitle.setText("是开启通知权限?");
+                                tvContent.setText("");
+                                btncancel.setOnClickListener(view1 -> {
+                                    dialog1.dismiss();
+                                });
+                                btnCommit.setOnClickListener(view1 -> {
+                                    finish();
+                                    dialog1.dismiss();
+                                    gotoSet();
+                                });
+                            });
+
+                        }
+                        break;
+                    case 6:
+                        finish();
+                        break;
+                }
+                adapter.setData(list, cont);
+        }
+    }
+
+    @Override
+    protected ActivityEquipmentTestBinding getLayoutView() {
+        return ActivityEquipmentTestBinding.inflate(getLayoutInflater());
+    }
+
+    @Override
+    protected EquipmentTestPresenter createPresenter() {
+        return new EquipmentTestPresenter();
+    }
+
+
+    private void startRecorder() {
+
+        isRecording = true;
+        stopPlaying();
+        mFileName = "/麦克风测试.aac";
+        mFilePath = FileUtils.getCacheDir(this);
+
+        //        File fileDirectory = new File(mFilePath);
+        //        if (!fileDirectory.exists()) {
+        //            fileDirectory.mkdirs();
+        //        }
+
+        File mAudioFile = new File(mFilePath + mFileName);
+        mAudioRecorder = AudioRecorder.getInstance();
+        mAudioRecorder.prepareRecord(MediaRecorder.AudioSource.MIC,
+                MediaRecorder.OutputFormat.AAC_ADTS, MediaRecorder.AudioEncoder.AAC,
+                mAudioFile);
+        mAudioRecorder.startRecord();
+    }
+
+    private void stopRecorder() {
+        isRecording = false;
+        if (null != mAudioRecorder) {
+            mAudioRecorder.stopRecord();
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        stopRecorder();
+        stopPlaying();
+        if (null != mAudioFile) {
+            FileUtils.deleteFile1(mAudioFile);
+
+        }
+    }
+
+    private void startPlaying() {
+        mMediaPlayer = new MediaPlayer();
+
+        try {
+            mMediaPlayer.setDataSource(mFilePath + mFileName);
+            mMediaPlayer.prepare();
+            mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
+                @Override
+                public void onPrepared(MediaPlayer mp) {
+                    mMediaPlayer.start();
+                }
+            });
+        } catch (IOException e) {
+        }
+
+        mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+            @Override
+            public void onCompletion(MediaPlayer mp) {
+                stopPlaying();
+            }
+        });
+    }
+
+
+    private void pausePlaying() {
+        mMediaPlayer.pause();
+    }
+
+    private void resumePlaying() {
+        mMediaPlayer.start();
+    }
+
+    private void stopPlaying() {
+        if (mMediaPlayer == null || mHandler == null) {
+            return;
+        }
+        mMediaPlayer.stop();
+        mMediaPlayer.reset();
+        mMediaPlayer.release();
+        mMediaPlayer = null;
+
+        isPlaying = !isPlaying;
+        //allow the screen to turn off again once audio is finished playing
+    }
+
+    private boolean isNotificationEnabled(Context context) {
+        boolean isOpened = false;
+        try {
+            isOpened = NotificationManagerCompat.from(context).areNotificationsEnabled();
+        } catch (Exception e) {
+            e.printStackTrace();
+            isOpened = false;
+        }
+        return isOpened;
+
+    }
+
+    private void gotoSet() {
+
+        Intent intent = new Intent();
+        if (Build.VERSION.SDK_INT >= 26) {
+            // android 8.0引导
+            intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
+            intent.putExtra("android.provider.extra.APP_PACKAGE", getPackageName());
+        } else if (Build.VERSION.SDK_INT >= 21) {
+            // android 5.0-7.0
+            intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
+            intent.putExtra("app_package", getPackageName());
+            intent.putExtra("app_uid", getApplicationInfo().uid);
+        } else {
+            // 其他
+            intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
+            intent.setData(Uri.fromParts("package", getPackageName(), null));
+        }
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        startActivity(intent);
+
+    }
+
+}

+ 359 - 0
student/src/main/java/com/cooleshow/student/ui/mine/NetworkMonitoringActivity.java

@@ -0,0 +1,359 @@
+package com.cooleshow.student.ui.mine;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+
+import com.alibaba.android.arouter.facade.annotation.Route;
+import com.cooleshow.base.router.RouterPath;
+import com.cooleshow.base.ui.activity.BaseMVPActivity;
+import com.cooleshow.base.utils.NetworkUtil;
+import com.cooleshow.base.widgets.BaseDialog;
+import com.cooleshow.base.widgets.DialogUtil;
+import com.cooleshow.base.widgets.RoundProgressBar;
+import com.cooleshow.base.widgets.ViewHolder;
+import com.cooleshow.base.widgets.loading.SpinKitView;
+import com.cooleshow.student.R;
+import com.cooleshow.student.contract.NetworkMonitoringContract;
+import com.cooleshow.student.databinding.ActivityNetworkMonitoringBinding;
+import com.cooleshow.student.presenter.mine.NetworkMonitoringPresenter;
+
+import java.util.Random;
+
+import io.rong.imkit.utils.StatusBarUtil;
+
+/**
+ * 创建日期:2022/6/1 14:50
+ *
+ * @author Ryan
+ * 类说明:
+ */
+@Route(path = RouterPath.MineCenter.MINE_NETWORK_MONITORING)
+public class NetworkMonitoringActivity extends BaseMVPActivity<ActivityNetworkMonitoringBinding, NetworkMonitoringPresenter> implements NetworkMonitoringContract.NetworkMonitoringView, View.OnClickListener {
+    RoundProgressBar progess;
+    ImageView ivOne;
+    SpinKitView skOne;
+    ImageView ivTwo;
+    SpinKitView skTwo;
+    ImageView ivThree;
+    SpinKitView skThree;
+    ImageView ivFour;
+    SpinKitView skFour;
+    boolean isSuccess = false;
+    Handler mHandler;
+    Runnable mRunnable;
+    int proges = 0;
+    int position = 0;
+    boolean isStart = true;
+    private int delayMillis;
+    private boolean isNetwork = false;
+    private boolean isStop = false;
+    private int normal = R.drawable.icon_network_normal;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        StatusBarUtil.setStatusBarDarkTheme(this, true);
+
+    }
+    @Override
+    public void onClick(View view) {
+
+    }
+
+    @Override
+    protected void initView() {
+        initMidTitleToolBar(viewBinding.toolbarInclude.toolbar, "网络检测");
+        progess=viewBinding.progess;
+        ivOne=viewBinding.ivOne;
+        skOne=viewBinding.skOne;
+        ivTwo=viewBinding.ivTwo;
+        skTwo=viewBinding.skTwo;
+        ivThree=viewBinding.ivThree;
+        skThree=viewBinding.skThree;
+        ivFour=viewBinding.ivFour;
+        skFour=viewBinding.skFour;
+
+
+
+        mHandler = new Handler();
+        progess.setOnProgressListener(position -> {
+            this.position = position;
+            try {
+                if (position == 5) {
+                    getNetWorkType(1);
+                }
+                if (position == 30) {
+                    if (!isNetwork) {
+                        isStop = true;
+                        new Handler().postDelayed(new Runnable() {
+                            @Override
+                            public void run() {
+                                if (isNetwork) {
+                                    mHandler.post(mRunnable);
+                                    getNetWorkType(2);
+                                } else {
+                                    initPopu("失败", "路由检测失败,请尝试一下措施:\n1.重启路由器,并靠近路由器重试\n2.切换4G网络重试");
+                                    ivTwo.setVisibility(View.VISIBLE);
+                                    skTwo.setVisibility(View.GONE);
+                                    ivTwo.setImageResource(com.cooleshow.base.R.drawable.ic_network_error);
+                                }
+                            }
+                        }, 2000);
+                    } else {
+                        getNetWorkType(2);
+                    }
+                }
+                if (position == 60) {
+                    getNetWorkType(3);
+                }
+                if (position == 100) {
+                    getNetWorkType(4);
+                }
+            } catch (Exception e) {
+            }
+        });
+    }
+    @Override
+    protected void onResume() {
+        super.onResume();
+        //        progess.setProgress(1);
+        //        getNetWorkType(0);
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                isNetwork = NetworkUtil.ping();
+            }
+        }).start();
+
+    }
+
+
+    @Override
+    protected ActivityNetworkMonitoringBinding getLayoutView() {
+        return ActivityNetworkMonitoringBinding.inflate(getLayoutInflater());
+    }
+
+    @Override
+    protected NetworkMonitoringPresenter createPresenter() {
+        return new NetworkMonitoringPresenter();
+    }
+
+
+    private void getNetWorkType(int i) {
+
+        if (NetworkUtil.getNetWorkType(getApplicationContext()) == NetworkUtil.NETWORKTYPE_WIFI) {
+            progess.setType("Wi-Fi");
+        } else if (NetworkUtil.getNetWorkType(getApplicationContext()) == NetworkUtil.NETWORKTYPE_3G) {
+            progess.setType("4G");
+        } else if (NetworkUtil.getNetWorkType(getApplicationContext()) == NetworkUtil.NETWORKTYPE_2G) {
+            progess.setType("2G");
+        } else if (NetworkUtil.getNetWorkType(getApplicationContext()) == NetworkUtil.NETWORKTYPE_WAP) {
+            progess.setType("WAP");
+        } else if (NetworkUtil.getNetWorkType(getApplicationContext()) == NetworkUtil.NETWORKTYPE_INVALID) {
+            progess.setType("无网络");
+        }
+
+        if (NetworkUtil.isNetworkAvailable(getApplicationContext())) {
+            if (i == 1) {
+                ivOne.setImageResource(normal);
+            }
+            if (i == 2) {
+                ivTwo.setImageResource(normal);
+            }
+            if (i == 3) {
+                ivThree.setImageResource(normal);
+            }
+            if (i == 4) {
+                ivFour.setImageResource(normal);
+            }
+        } else {
+            if (i == 1) {
+                ivOne.setImageResource(com.cooleshow.base.R.drawable.ic_network_error);
+                ivTwo.setImageResource(com.cooleshow.base.R.drawable.ic_network_error);
+                ivThree.setImageResource(com.cooleshow.base.R.drawable.ic_network_error);
+                ivFour.setImageResource(com.cooleshow.base.R.drawable.ic_network_error);
+            }
+            if (i == 2) {
+                ivTwo.setImageResource(com.cooleshow.base.R.drawable.ic_network_error);
+                ivThree.setImageResource(com.cooleshow.base.R.drawable.ic_network_error);
+                ivFour.setImageResource(com.cooleshow.base.R.drawable.ic_network_error);
+            }
+            if (i == 3) {
+                ivThree.setImageResource(com.cooleshow.base.R.drawable.ic_network_error);
+                ivFour.setImageResource(com.cooleshow.base.R.drawable.ic_network_error);
+            }
+            if (i == 4) {
+                ivFour.setImageResource(com.cooleshow.base.R.drawable.ic_network_error);
+            }
+        }
+        if (0 == i) {
+            ivOne.setVisibility(View.GONE);
+            skOne.setVisibility(View.VISIBLE);
+            ivTwo.setVisibility(View.GONE);
+            skTwo.setVisibility(View.GONE);
+            ivThree.setVisibility(View.GONE);
+            skThree.setVisibility(View.GONE);
+            ivFour.setVisibility(View.GONE);
+            skFour.setVisibility(View.GONE);
+        }
+        if (1 == i) {
+            ivOne.setVisibility(View.VISIBLE);
+            skOne.setVisibility(View.GONE);
+            ivTwo.setVisibility(View.GONE);
+            skTwo.setVisibility(View.VISIBLE);
+            ivThree.setVisibility(View.GONE);
+            skThree.setVisibility(View.GONE);
+            ivFour.setVisibility(View.GONE);
+            skFour.setVisibility(View.GONE);
+        }
+        if (2 == i) {
+            ivOne.setVisibility(View.VISIBLE);
+            skOne.setVisibility(View.GONE);
+            ivTwo.setVisibility(View.VISIBLE);
+            skTwo.setVisibility(View.GONE);
+            ivThree.setVisibility(View.GONE);
+            skThree.setVisibility(View.VISIBLE);
+            ivFour.setVisibility(View.GONE);
+            skFour.setVisibility(View.GONE);
+        }
+        if (3 == i) {
+            ivOne.setVisibility(View.VISIBLE);
+            skOne.setVisibility(View.GONE);
+            ivTwo.setVisibility(View.VISIBLE);
+            skTwo.setVisibility(View.GONE);
+            ivThree.setVisibility(View.VISIBLE);
+            skThree.setVisibility(View.GONE);
+            ivFour.setVisibility(View.GONE);
+            skFour.setVisibility(View.VISIBLE);
+        }
+        if (4 == i) {
+            ivOne.setVisibility(View.VISIBLE);
+            skOne.setVisibility(View.GONE);
+            ivTwo.setVisibility(View.VISIBLE);
+            skTwo.setVisibility(View.GONE);
+            ivThree.setVisibility(View.VISIBLE);
+            skThree.setVisibility(View.GONE);
+            ivFour.setVisibility(View.VISIBLE);
+            skFour.setVisibility(View.GONE);
+
+            if (NetworkUtil.getNetWorkType(getApplicationContext()) == NetworkUtil.NETWORKTYPE_3G
+                    || NetworkUtil.getNetWorkType(getApplicationContext()) == NetworkUtil.NETWORKTYPE_WIFI) {
+                initPopu("良好", "恭喜你!网络十分流畅");
+            } else if (NetworkUtil.isNetworkAvailable(getApplicationContext())) {
+                initPopu("不佳", "网络连接不佳,请尝试一下措施:\n1.重启路由器,并靠近路由器重试\n2.切换4G网络重试");
+            } else {
+                initPopu("无网络", "网络连接不佳,请尝试一下措施:\n1.重启路由器,并靠近路由器重试\n2.切换4G网络重试");
+            }
+        }
+
+
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+        new Handler().postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                if (hasFocus && isStart) {
+                    new Thread(new Runnable() {
+                        @Override
+                        public void run() {
+                            isNetwork = false;
+                            isNetwork = NetworkUtil.ping();
+                        }
+                    }).start();
+                    isStart = false;
+                    proges = 0;
+                    ivOne.setVisibility(View.GONE);
+                    skOne.setVisibility(View.VISIBLE);
+                    ivTwo.setVisibility(View.GONE);
+                    skTwo.setVisibility(View.GONE);
+                    ivThree.setVisibility(View.GONE);
+                    skThree.setVisibility(View.GONE);
+                    ivFour.setVisibility(View.GONE);
+                    skFour.setVisibility(View.GONE);
+                    ivTwo.setImageResource(com.cooleshow.base.R.drawable.ic_network_error);
+                    ivThree.setImageResource(com.cooleshow.base.R.drawable.ic_network_error);
+                    ivFour.setImageResource(com.cooleshow.base.R.drawable.ic_network_error);
+                    mRunnable = () -> {
+                        if (isStop) {
+                            isStop = false;
+                            mHandler.removeCallbacks(mRunnable);
+                        } else if (proges == 100) {
+                            mHandler.removeCallbacks(mRunnable);
+                        } else if (!NetworkUtil.isNetworkAvailable(getApplicationContext())) {
+                            progess.setProgress(100);
+                            mHandler.removeCallbacks(mRunnable);
+                        } else {
+                            progess.setProgress(proges += 1);
+                            Random rand = new Random();
+                            if (NetworkUtil.getNetWorkType(getApplicationContext()) == NetworkUtil.NETWORKTYPE_WIFI) {
+                                if (5 < position && position < 30) {
+                                    delayMillis = rand.nextInt(400);
+                                } else {
+                                    delayMillis = rand.nextInt(100);
+                                }
+                            } else if (NetworkUtil.getNetWorkType(getApplicationContext()) == NetworkUtil.NETWORKTYPE_3G) {
+                                if (5 < position && position < 30) {
+                                    delayMillis = rand.nextInt(400);
+                                } else {
+                                    delayMillis = rand.nextInt(100);
+                                }
+                            } else {
+                                delayMillis = rand.nextInt(500);
+                            }
+
+                            mHandler.postDelayed(mRunnable, delayMillis);
+                        }
+                    };
+                    mHandler.post(mRunnable);
+                }
+            }
+        }, 500);
+
+    }
+
+    private void initPopu(String title, String content) {
+        proges = 100;
+        DialogUtil.showInCenter(getSupportFragmentManager(), R.layout.network_popu, new DialogUtil.ShowListener() {
+            @Override
+            public void onShow(ViewHolder holder, BaseDialog dialog) {
+                TextView tvTitle = holder.getView(R.id.tv_title);
+                TextView tvContent = holder.getView(R.id.tv_content);
+                TextView btncancel = holder.getView(R.id.btn_cancel);
+                TextView btnCommit = holder.getView(R.id.btn_commit);
+
+                tvTitle.setText(title);
+                if (title.equals("良好")) {
+                    tvTitle.setTextColor(getResources().getColor(com.cooleshow.base.R.color.colorPrimary));
+                    tvContent.setGravity(Gravity.CENTER);
+                } else {
+                    tvTitle.setTextColor(getResources().getColor(com.cooleshow.base.R.color.color_f85043));
+                }
+                tvContent.setText(content);
+                btncancel.setOnClickListener(view1 -> {
+                    finish();
+                    dialog.dismiss();
+                });
+                btnCommit.setOnClickListener(view1 -> {
+                    proges = 0;
+                    isStart = true;
+                    dialog.dismiss();
+                });
+            }
+        });
+    }
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        mHandler.removeCallbacks(mRunnable);
+        mHandler.removeCallbacksAndMessages(mRunnable);
+    }
+}

+ 6 - 42
student/src/main/java/com/cooleshow/student/ui/mine/PayTestActivity.java

@@ -53,41 +53,13 @@ public class PayTestActivity extends BaseMVPActivity<ActivityPayTestBinding, Pay
         String orderNo = viewBinding.etId.getText().toString().trim();
         switch (view.getId()) {
             case R.id.tv_weixin:
-              /*  if (TextUtils.isEmpty(orderNo)) {
+                if (TextUtils.isEmpty(orderNo)) {
                     ToastUtils.showShort("输入订单号");
                     break;
                 }
-                doWeixinPay(orderNo);*/
-
-
-                //微信
-                PayReq req = new PayReq();
-                /*req.appId = weixinPayInfo.getAppid();
-                req.partnerId = weixinPayInfo.getPartnerid();
-                req.prepayId = weixinPayInfo.getPrepayid();
-                req.nonceStr = weixinPayInfo.getNoncestr();
-                req.timeStamp = weixinPayInfo.getTimestamp();
-                req.packageValue = weixinPayInfo.getPackageValue();
-                req.sign = weixinPayInfo.getSign();*/
-
-            /*
-            {\"packageValue\":\"Sign=WXPay\",\"appid\":\"wx149a928c415c137a\",\"sign\":\"",\"partnerid\":\"1625930034\",\"prepayid\":\"wx2714122960625249e527c060d8fdb50000\",\"noncestr\":\"abBAT62fVYDFooWwkk2W5C1a6p9y4PD6\",\"timestamp\":\"1653631949\"}"
-    },
-             */
-
-                     req.appId="wx149a928c415c137a";
-                req.partnerId="1625930034";
-                req.prepayId="wx2714122960625249e527c060d8fdb50000";
-                req.packageValue="Sign=WXPay";
-                req.nonceStr="abBAT62fVYDFooWwkk2W5C1a6p9y4PD6";
-                req.timeStamp="1653631949";
-                req.sign="RsDZRGgfNjL4FJqwPg1Mp/iLrbSZqaWVG6yX22Nh+EF2qJXkGAqGP1iDU/o7CSVctyg3xfdOzX1Q2vAvBJrf9rVG5H9+1cfPf5UMkn4VWLKn8JloD6XdSp2XRO+nxG16C8FZ13LXCH0O/xD5A48Rl7JduUr3/N8NIheB+Qz/kPWMwZTmZ0E/WVfh4NiJRK5BoBII4Eu0NAAxDMZV+fziXBmgSh5xkQxPcqSL9YWYBr5furqBnjlFXV5Xa7kAQgnxdCUib9FnBCGnSwba9UBQf1KAlsc4hYDV0kPEVTYxUKjASQsMDg9S3OLMpsMxBv+Do1DTAnisxvkT0Ubi5BbaDA==";
+                doWeixinPay(orderNo);
 
 
-//                    req.extData			= "app data"; // optional
-                //正在前往微信支付
-                // 在支付之前,如果应用没有注册到微信,应该先调用IWXMsg.registerApp将应用注册到微信
-                api.sendReq(req);
                 break;
             case R.id.tv_alipay:
                 if (TextUtils.isEmpty(orderNo)) {
@@ -106,7 +78,7 @@ public class PayTestActivity extends BaseMVPActivity<ActivityPayTestBinding, Pay
         //沙箱环境支付
         EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
         api = WXAPIFactory.createWXAPI(this, null);
-        api.registerApp("wx149a928c415c137a");
+        api.registerApp("wx97408cd22c879ff7");
     }
 
     @Override
@@ -175,22 +147,14 @@ public class PayTestActivity extends BaseMVPActivity<ActivityPayTestBinding, Pay
                 Gson gson=new Gson();
                 WeixinPayInfo weixinPayInfo = gson.fromJson(o.pay_info, WeixinPayInfo.class);
                 PayReq req = new PayReq();
-                /*req.appId = weixinPayInfo.getAppid();
+                req.appId = weixinPayInfo.getAppid();
+//                req.appId ="wx97408cd22c879ff7";
                 req.partnerId = weixinPayInfo.getPartnerid();
                 req.prepayId = weixinPayInfo.getPrepayid();
                 req.nonceStr = weixinPayInfo.getNoncestr();
                 req.timeStamp = weixinPayInfo.getTimestamp();
                 req.packageValue = weixinPayInfo.getPackageValue();
-                req.sign = weixinPayInfo.getSign();*/
-
-                req.appId="wx149a928c415c137a";
-                req.partnerId="1625930034";
-                req.prepayId="wx261155254861066e2f36eef49c8b970000";
-                req.packageValue="Sign=WXPay";
-                req.nonceStr="ZHAHmiQmqD7E4qKGqcceTHJ1j1vCtuYJ";
-                req.timeStamp="1653537327";
-                req.sign="7364A25C06D2C99774EEFA1D1625E4F4";
-
+                req.sign = weixinPayInfo.getSign();
 
 //                    req.extData			= "app data"; // optional
                 //正在前往微信支付

+ 150 - 0
student/src/main/java/com/cooleshow/student/ui/mine/TeachableInstrumentActivity.java

@@ -0,0 +1,150 @@
+package com.cooleshow.student.ui.mine;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.alibaba.android.arouter.facade.annotation.Autowired;
+import com.alibaba.android.arouter.facade.annotation.Route;
+import com.alibaba.android.arouter.launcher.ARouter;
+import com.cooleshow.base.router.RouterPath;
+import com.cooleshow.base.ui.activity.BaseMVPActivity;
+import com.cooleshow.student.R;
+import com.cooleshow.student.adapter.TeachableInstrumentAdapter;
+import com.cooleshow.student.bean.TeachableInstrumentBean;
+import com.cooleshow.student.contract.TeachableInstrumentContract;
+import com.cooleshow.student.databinding.ActivityTeachableInstrumentBinding;
+import com.cooleshow.student.presenter.mine.TeachableInstrumentPresenter;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import io.rong.imkit.utils.StatusBarUtil;
+
+/**
+ * 创建日期:2022/6/1 9:15
+ *
+ * @author Ryan
+ * 类说明:
+ */
+@Route(path = RouterPath.MineCenter.MINE_TEACHABLE_INSTRUMENT)
+public class TeachableInstrumentActivity extends BaseMVPActivity<ActivityTeachableInstrumentBinding, TeachableInstrumentPresenter> implements TeachableInstrumentContract.TeachableInstrumentView, View.OnClickListener {
+
+    private RecyclerView instrumentList;
+    private TeachableInstrumentAdapter teachableInstrumentAdapter;
+    @Autowired(name = "bundle")
+    Bundle myBundle;
+
+    @Override
+    public void onClick(View view) {
+        switch (view.getId()) {
+            case R.id.tv_confirm:
+                List<TeachableInstrumentBean> selectTeachableInstrument = new ArrayList<>();
+                for (TeachableInstrumentBean teachableInstrumentBean : dataList) {
+                    if (null != teachableInstrumentBean.subjects && teachableInstrumentBean.subjects.size() > 0) {
+                        for (TeachableInstrumentBean subject : teachableInstrumentBean.subjects) {
+                            if (subject.isSelect) {
+                                selectTeachableInstrument.add(subject);
+                            }
+                        }
+                    }
+                }
+                presenter.setSubject(selectTeachableInstrument.get(0).id+"");
+
+                break;
+        }
+    }
+
+
+    private List<TeachableInstrumentBean> dataList = new ArrayList<>();
+
+    @Override
+    protected void initView() {
+        ARouter.getInstance().inject(this);
+        initMidTitleToolBar(viewBinding.toolbarInclude.toolbar, "可教授乐器");
+        instrumentList = viewBinding.rvInstrument;
+        viewBinding.tvConfirm.setOnClickListener(this);
+        LinearLayoutManager manager = new LinearLayoutManager(this);
+        instrumentList.setLayoutManager(manager);
+        teachableInstrumentAdapter = new TeachableInstrumentAdapter(dataList);
+        instrumentList.setAdapter(teachableInstrumentAdapter);
+        initCarryData();
+    }
+
+    private TeachableInstrumentBean carryList = null;
+
+    private void initCarryData() {
+        if (null != myBundle) {
+            carryList = (TeachableInstrumentBean) myBundle.getSerializable("selectTeachableInstrument");
+        }
+
+    }
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        StatusBarUtil.setStatusBarDarkTheme(this, true);
+    }
+
+    @Override
+    protected ActivityTeachableInstrumentBinding getLayoutView() {
+        return ActivityTeachableInstrumentBinding.inflate(getLayoutInflater());
+    }
+
+    @Override
+    protected TeachableInstrumentPresenter createPresenter() {
+        return new TeachableInstrumentPresenter();
+    }
+
+    @Override
+    public void initData() {
+        super.initData();
+        presenter.subjectSelect();
+    }
+
+    @Override
+    public void subjectSelectSuccess(List<TeachableInstrumentBean> data) {
+        if (null != data && data.size() > 0) {
+            dataList.clear();
+            if (null != carryList) {
+                for (TeachableInstrumentBean datum : data) {
+                    if (null != datum.subjects && datum.subjects.size() > 0) {
+                        for (TeachableInstrumentBean subject : datum.subjects) {
+                            if (carryList.id == subject.id) {
+                                subject.isSelect = true;
+                            }
+                        }
+                    }
+                }
+            }
+
+            dataList.addAll(data);
+            if (null != teachableInstrumentAdapter) {
+                teachableInstrumentAdapter.notifyDataSetChanged();
+            }
+        }
+    }
+
+    @Override
+    public void setSubjectSuccess(Object o) {
+        List<TeachableInstrumentBean> selectTeachableInstrument = new ArrayList<>();
+        for (TeachableInstrumentBean teachableInstrumentBean : dataList) {
+            if (null != teachableInstrumentBean.subjects && teachableInstrumentBean.subjects.size() > 0) {
+                for (TeachableInstrumentBean subject : teachableInstrumentBean.subjects) {
+                    if (subject.isSelect) {
+                        selectTeachableInstrument.add(subject);
+                    }
+                }
+            }
+        }
+        Intent intent = new Intent();
+        intent.putExtra("selectTeachableInstrument", (Serializable) selectTeachableInstrument.get(0));
+        setResult(RESULT_OK, intent);
+        finish();
+    }
+}

+ 1 - 1
student/src/main/java/com/cooleshow/student/wxapi/WXPayEntryActivity.java

@@ -25,7 +25,7 @@ public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.pay_result);
 
-        api = WXAPIFactory.createWXAPI(this, "wx149a928c415c137a");
+        api = WXAPIFactory.createWXAPI(this, "wx97408cd22c879ff7");
         api.handleIntent(getIntent(), this);
     }
 

BIN
student/src/main/res/drawable-xhdpi/icon_check_normal.png


BIN
student/src/main/res/drawable-xhdpi/icon_check_select.png


BIN
student/src/main/res/drawable-xhdpi/icon_device_initialize.png


BIN
student/src/main/res/drawable-xhdpi/icon_line_initialize.png


BIN
student/src/main/res/drawable-xhdpi/icon_line_test_initialize.png


BIN
student/src/main/res/drawable-xhdpi/icon_network_normal.png


BIN
student/src/main/res/drawable-xhdpi/icon_recorder_success.png


BIN
student/src/main/res/drawable-xhdpi/icon_root_initialize.png


BIN
student/src/main/res/drawable-xhdpi/icon_testing_network.png


BIN
student/src/main/res/drawable-xhdpi/icon_testing_notice.png


BIN
student/src/main/res/drawable-xhdpi/icon_testing_phone.png


BIN
student/src/main/res/drawable-xhdpi/icon_testing_play.png


BIN
student/src/main/res/drawable-xhdpi/icon_testing_recorder.png


BIN
student/src/main/res/drawable-xxhdpi/icon_check_normal.png


BIN
student/src/main/res/drawable-xxhdpi/icon_check_select.png


BIN
student/src/main/res/drawable-xxhdpi/icon_device_initialize.png


BIN
student/src/main/res/drawable-xxhdpi/icon_line_initialize.png


BIN
student/src/main/res/drawable-xxhdpi/icon_line_test_initialize.png


BIN
student/src/main/res/drawable-xxhdpi/icon_network_normal.png


BIN
student/src/main/res/drawable-xxhdpi/icon_recorder_success.png


BIN
student/src/main/res/drawable-xxhdpi/icon_root_initialize.png


BIN
student/src/main/res/drawable-xxhdpi/icon_testing_network.png


BIN
student/src/main/res/drawable-xxhdpi/icon_testing_notice.png


BIN
student/src/main/res/drawable-xxhdpi/icon_testing_phone.png


BIN
student/src/main/res/drawable-xxhdpi/icon_testing_play.png


BIN
student/src/main/res/drawable-xxhdpi/icon_testing_recorder.png


+ 7 - 0
student/src/main/res/drawable/border_corner_2dc7aa.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/common_white" />
+    <stroke android:width="1dp" android:color="@color/color_2dc7aa" />
+    <corners android:radius="25dp" />
+</shape>

+ 8 - 0
student/src/main/res/drawable/mark_2dc7aa_3radius.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/color_2dc7aa" />
+    <size
+        android:width="@dimen/dp_3"
+        android:height="@dimen/dp_16" />
+    <corners android:radius="@dimen/dp_3" />
+</shape>

+ 135 - 0
student/src/main/res/layout/activity_equipment_test.xml

@@ -0,0 +1,135 @@
+<?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"
+    android:background="@color/white"
+    tools:ignore="MissingDefaultResource">
+
+    <include
+        android:id="@+id/toolbar_include"
+        layout="@layout/common_toolbar_layout" />
+
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/dp_28"
+        android:layout_marginEnd="@dimen/dp_28"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toTopOf="parent">
+
+
+        <ImageView
+            android:id="@+id/imageView"
+            android:layout_width="@dimen/dp_183"
+            android:layout_height="@dimen/dp_168"
+            android:layout_marginTop="@dimen/dp_30"
+            android:scaleType="centerInside"
+            android:src="@drawable/icon_testing_phone"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/recyclerView"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/dp_50"
+            android:overScrollMode="never"
+            android:scrollbars="none"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/imageView" />
+
+        <TextView
+            android:id="@+id/tv_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="设备检测"
+            android:textColor="@color/black_444"
+            android:textSize="@dimen/dp_18"
+            android:textStyle="bold"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@id/recyclerView" />
+
+        <TextView
+            android:id="@+id/tv_hint"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/dp_76"
+            android:layout_marginTop="@dimen/dp_10"
+            android:layout_marginEnd="@dimen/dp_74"
+            android:gravity="center"
+            android:lineSpacingExtra="@dimen/dp_5"
+            android:text="为确保您能正常上课,现在进行声音测试"
+            app:layout_goneMarginTop="@dimen/dp_12"
+            android:textColor="@color/gray_777"
+            android:textSize="@dimen/dp_14"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/tv_title" />
+
+        <Button
+            android:id="@+id/btn_cancel"
+            style="?android:attr/borderlessButtonStyle"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/dp_50"
+            android:layout_marginStart="@dimen/dp_28"
+            android:layout_marginTop="@dimen/dp_37"
+            android:layout_marginBottom="@dimen/dp_28"
+            android:background="@drawable/border_corner_2dc7aa"
+            android:text="无声音"
+            android:textColor="@color/colorPrimary"
+            android:textSize="@dimen/dp_16"
+            android:visibility="gone"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toStartOf="@+id/btn_confirm"
+            app:layout_constraintHorizontal_chainStyle="spread_inside"
+            app:layout_constraintHorizontal_weight="1"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/tv_hint" />
+
+        <Button
+            android:id="@+id/btn_confirm"
+            style="?android:attr/borderlessButtonStyle"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/dp_50"
+            android:layout_marginStart="@dimen/dp_24"
+            android:layout_marginTop="@dimen/dp_37"
+            android:layout_marginEnd="@dimen/dp_28"
+            android:layout_marginBottom="@dimen/dp_28"
+            android:background="@drawable/shape_course_status_ing"
+            android:text="有声音"
+            android:textColor="@color/white"
+            android:textSize="@dimen/dp_16"
+            android:visibility="gone"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintHorizontal_weight="1"
+            app:layout_constraintStart_toEndOf="@+id/btn_cancel"
+            app:layout_constraintTop_toBottomOf="@+id/tv_hint" />
+
+        <Button
+            android:id="@+id/btn_next"
+            style="?android:attr/borderlessButtonStyle"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/dp_50"
+            android:layout_marginStart="@dimen/dp_60"
+            android:layout_marginTop="@dimen/dp_37"
+            android:layout_marginEnd="@dimen/dp_60"
+            android:layout_marginBottom="@dimen/dp_28"
+            android:background="@drawable/shape_course_status_ing"
+            android:text="开始测试"
+            android:textColor="@color/white"
+            android:textSize="@dimen/dp_16"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toBottomOf="@+id/tv_hint" />
+
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 239 - 0
student/src/main/res/layout/activity_network_monitoring.xml

@@ -0,0 +1,239 @@
+<?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"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/color_f7f8f9">
+    <FrameLayout
+        android:id="@+id/fl_toolbar"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@color/white">
+        <include
+            android:id="@+id/toolbar_include"
+            layout="@layout/common_toolbar_layout" />
+    </FrameLayout>
+
+
+    <View
+        android:id="@+id/view_bg"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/dp_249"
+        android:background="@color/white"
+        app:layout_constraintTop_toBottomOf="@+id/fl_toolbar"/>
+
+    <com.cooleshow.base.widgets.RoundProgressBar
+        android:id="@+id/progess"
+        android:layout_width="@dimen/dp_188"
+        android:layout_height="@dimen/dp_188"
+        android:layout_marginTop="@dimen/dp_29"
+        app:backColor="#ffffff"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toBottomOf="@+id/fl_toolbar"
+        app:roundColor="@color/white"
+        app:roundProgressColor="@color/colorPrimaryStudent"
+        app:roundWidth="@dimen/dp_15"
+        app:startAngle="270"
+        app:textColor="@color/black"
+        app:textSize="@dimen/dp_38" />
+
+
+    <LinearLayout
+        android:id="@+id/ll_device"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="@dimen/dp_12"
+        android:layout_marginTop="@dimen/dp_10"
+        android:layout_marginRight="@dimen/dp_12"
+        android:background="@drawable/bg_white_10dp"
+        android:gravity="center_vertical"
+        android:orientation="horizontal"
+        app:layout_constraintTop_toBottomOf="@+id/view_bg">
+
+
+        <ImageView
+            android:layout_width="@dimen/dp_20"
+            android:layout_height="@dimen/dp_20"
+            android:layout_marginLeft="@dimen/dp_14"
+            android:background="@drawable/icon_device_initialize" />
+
+        <TextView
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:gravity="center_vertical"
+            android:paddingLeft="@dimen/dp_12"
+            android:paddingTop="@dimen/dp_13"
+            android:paddingBottom="@dimen/dp_12"
+            android:text="设备初始化"
+            android:textColor="@color/black_444"
+            android:textSize="@dimen/dp_16" />
+
+        <ImageView
+            android:id="@+id/iv_one"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="@dimen/dp_18"
+            android:src="@drawable/icon_network_normal"
+            android:visibility="gone" />
+
+        <com.cooleshow.base.widgets.loading.SpinKitView
+            android:id="@+id/sk_one"
+            style="@style/SpinKitView.Small.FadingCircle"
+            android:layout_width="@dimen/dp_30"
+            android:layout_height="@dimen/dp_30"
+            android:layout_marginRight="@dimen/dp_18"
+            app:SpinKit_Color="@color/color_999999"
+            app:SpinKit_Style="ThreeBounce" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/ll_root"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:layout_constraintTop_toBottomOf="@+id/ll_device"
+        android:layout_marginLeft="@dimen/dp_12"
+        android:layout_marginTop="@dimen/dp_10"
+        android:layout_marginRight="@dimen/dp_12"
+        android:background="@drawable/bg_white_10dp"
+        android:gravity="center_vertical"
+        android:orientation="horizontal">
+
+        <ImageView
+            android:layout_width="@dimen/dp_20"
+            android:layout_height="@dimen/dp_20"
+            android:layout_marginLeft="@dimen/dp_14"
+            android:background="@drawable/icon_root_initialize" />
+        <TextView
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:gravity="center_vertical"
+            android:paddingLeft="@dimen/dp_12"
+            android:paddingTop="@dimen/dp_13"
+            android:paddingBottom="@dimen/dp_12"
+            android:text="路由环境检测"
+            android:textColor="@color/black_444"
+            android:textSize="@dimen/dp_16" />
+
+        <ImageView
+            android:id="@+id/iv_two"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="@dimen/dp_18"
+            android:src="@drawable/ic_network_error"
+            android:visibility="gone" />
+
+        <com.cooleshow.base.widgets.loading.SpinKitView
+            android:id="@+id/sk_two"
+            style="@style/SpinKitView.Small.FadingCircle"
+            android:layout_width="@dimen/dp_30"
+            android:layout_height="@dimen/dp_30"
+            android:visibility="gone"
+            android:layout_marginRight="@dimen/dp_18"
+            app:SpinKit_Color="@color/color_999999"
+            app:SpinKit_Style="ThreeBounce" />
+    </LinearLayout>
+
+
+    <LinearLayout
+        android:id="@+id/ll_line"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center_vertical"
+        app:layout_constraintTop_toBottomOf="@+id/ll_root"
+        android:layout_marginLeft="@dimen/dp_12"
+        android:layout_marginTop="@dimen/dp_10"
+        android:layout_marginRight="@dimen/dp_12"
+        android:background="@drawable/bg_white_10dp"
+        android:orientation="horizontal">
+        <ImageView
+            android:layout_width="@dimen/dp_20"
+            android:layout_height="@dimen/dp_20"
+            android:layout_marginLeft="@dimen/dp_14"
+            android:background="@drawable/icon_line_initialize" />
+
+        <TextView
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:gravity="center_vertical"
+            android:paddingLeft="@dimen/dp_12"
+            android:paddingTop="@dimen/dp_13"
+            android:paddingBottom="@dimen/dp_12"
+            android:text="线路检测"
+            android:textColor="@color/black_444"
+            android:textSize="@dimen/dp_16" />
+
+        <ImageView
+            android:id="@+id/iv_three"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="@dimen/dp_18"
+            android:src="@drawable/ic_network_error"
+            android:visibility="gone" />
+
+        <com.cooleshow.base.widgets.loading.SpinKitView
+            android:id="@+id/sk_three"
+            style="@style/SpinKitView.Small.FadingCircle"
+            android:layout_width="@dimen/dp_30"
+            android:layout_height="@dimen/dp_30"
+            android:layout_marginRight="@dimen/dp_18"
+            android:visibility="gone"
+            app:SpinKit_Color="@color/color_999999"
+            app:SpinKit_Style="ThreeBounce" />
+    </LinearLayout>
+
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center_vertical"
+        app:layout_constraintTop_toBottomOf="@+id/ll_line"
+        android:layout_marginLeft="@dimen/dp_12"
+        android:layout_marginTop="@dimen/dp_10"
+        android:layout_marginRight="@dimen/dp_12"
+        android:background="@drawable/bg_white_10dp"
+        android:orientation="horizontal">
+        <ImageView
+            android:layout_width="@dimen/dp_20"
+            android:layout_height="@dimen/dp_20"
+            android:layout_marginLeft="@dimen/dp_14"
+            android:background="@drawable/icon_line_test_initialize" />
+
+        <TextView
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:gravity="center_vertical"
+            android:paddingLeft="@dimen/dp_12"
+            android:paddingTop="@dimen/dp_13"
+            android:paddingBottom="@dimen/dp_12"
+            android:text="模拟测试"
+            android:textColor="@color/black_444"
+            android:textSize="@dimen/dp_16" />
+
+        <ImageView
+            android:id="@+id/iv_four"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="@dimen/dp_18"
+            android:src="@drawable/ic_network_error"
+            android:visibility="gone" />
+
+        <com.cooleshow.base.widgets.loading.SpinKitView
+            android:id="@+id/sk_four"
+            style="@style/SpinKitView.Small.FadingCircle"
+            android:layout_width="@dimen/dp_30"
+            android:layout_height="@dimen/dp_30"
+            android:layout_marginRight="@dimen/dp_18"
+            android:visibility="gone"
+            app:SpinKit_Color="@color/color_999999"
+            app:SpinKit_Style="ThreeBounce" />
+    </LinearLayout>
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 44 - 0
student/src/main/res/layout/activity_teachable_instrument.xml

@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@color/color_f6f8f9"
+    android:orientation="vertical">
+
+    <include
+        android:id="@+id/toolbar_include"
+        layout="@layout/common_toolbar_layout" />
+
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/rv_instrument"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@+id/toolbar_include"
+        android:layout_marginLeft="10dp"
+        android:layout_marginTop="16dp"
+        android:overScrollMode="never"
+        android:layout_marginRight="10dp"
+        android:layout_marginBottom="119dp"
+        android:nestedScrollingEnabled="false"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+
+    <TextView
+        android:id="@+id/tv_confirm"
+        android:layout_width="match_parent"
+        android:layout_height="44dp"
+        android:layout_marginLeft="27dp"
+        android:layout_marginRight="27dp"
+        android:layout_marginBottom="48dp"
+        android:background="@drawable/shape_course_status_ing"
+        android:gravity="center"
+        android:text="确认"
+        android:textColor="@color/white"
+        android:textSize="@dimen/sp_14"
+        android:layout_alignParentBottom="true"
+       />
+
+</RelativeLayout>

Некоторые файлы не были показаны из-за большого количества измененных файлов