From e407dd1f335aa9c716b89b3152bf363b898d28fa Mon Sep 17 00:00:00 2001
From: Runt <qingingrunt2010@qq.com>
Date: Sun, 29 May 2022 11:29:56 +0000
Subject: [PATCH] 接口请求框架 注册接口

---
 app/src/main/java/com/auto/lyric/base/fragments/BaseLoadPageFragment.java                 |   33 -
 app/src/main/java/com/auto/lyric/retrofit/utils/RetrofitUtils.java                        |    3 
 app/src/main/java/com/auto/lyric/ui/collect/Collect.java                                  |    9 
 app/src/main/java/com/auto/lyric/base/activities/BaseLoadPageActivity.java                |   33 -
 app/src/main/java/com/auto/lyric/util/PreferencesUtils.java                               |  234 ++--------
 app/src/main/res/layout/activity_collect.xml                                              |   31 +
 app/src/main/java/com/auto/lyric/base/activities/BaseActivity.java                        |  125 ++++++
 app/src/main/java/com/auto/lyric/util/DeviceIdUtils.java                                  |  124 ++++++
 app/src/main/java/com/auto/lyric/base/model/BaseViewModel.java                            |    6 
 app/src/main/java/com/auto/lyric/data/ActiveResult.java                                   |    9 
 app/src/main/java/com/auto/lyric/ui/collect/CollectListResult.java                        |   14 
 app/src/main/java/com/auto/lyric/ui/collect/CollectActivity.java                          |   16 
 app/src/main/java/com/auto/lyric/data/ActiveBean.java                                     |    9 
 app/src/main/java/com/auto/lyric/retrofit/Interceptor/HttpLoggingInterceptor.java         |   57 +-
 app/src/main/res/layout/activity_main.xml                                                 |   44 +
 app/src/main/java/com/auto/lyric/ui/collect/CollectViewModel.java                         |   15 
 app/src/main/java/com/auto/lyric/base/fragments/BaseFragment.java                         |    5 
 app/src/main/res/mipmap-xhdpi/icon_white_back.png                                         |    0 
 app/src/main/res/drawable-v21/bg_white_divider.xml                                        |   38 +
 app/build.gradle                                                                          |    2 
 app/src/main/java/com/auto/lyric/retrofit/converter/DecryptGsonResponseBodyConverter.java |   15 
 app/src/main/java/com/auto/lyric/data/BaseApiResult.java                                  |   17 
 app/src/main/java/com/auto/lyric/util/SHA1UTIL.java                                       |   64 +++
 app/src/main/java/com/auto/lyric/vm/MainViewModel.java                                    |   43 ++
 app/src/main/res/mipmap-xxhdpi/icon_white_back.png                                        |    0 
 app/src/main/AndroidManifest.xml                                                          |    1 
 app/src/main/java/com/auto/lyric/retrofit/observable/HttpObserver.java                    |   64 ++-
 app/src/main/java/com/auto/lyric/data/BasePageResult.java                                 |    2 
 app/src/main/java/com/auto/lyric/service/FloatingWindowService.java                       |   12 
 app/src/main/java/com/auto/lyric/retrofit/observable/LoadingHttpObserver.java             |   36 +
 app/src/main/java/com/auto/lyric/MainActivity.java                                        |   52 ++
 app/src/main/res/mipmap-xxxhdpi/icon_white_back.png                                       |    0 
 app/src/main/java/com/auto/lyric/retrofit/api/CommonApiCenter.java                        |    2 
 app/src/main/java/com/auto/lyric/base/fragments/BaseTabFragment.java                      |    4 
 app/src/main/java/com/auto/lyric/data/ApkUpGradeResult.java                               |    2 
 app/src/main/java/com/auto/lyric/retrofit/api/CollectApiCenter.java                       |   79 +++
 36 files changed, 881 insertions(+), 319 deletions(-)

diff --git a/app/build.gradle b/app/build.gradle
index 73137dd..947103f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -18,11 +18,13 @@
     buildTypes {
         debug {
             minifyEnabled false
+            buildConfigField 'String','HOST_IP_ADDR','"https://test1.mydetao.cn/"'
             resValue "string", "app_name", "歌词工具测试"
             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
         }
         release {
             minifyEnabled false
+            buildConfigField 'String','HOST_IP_ADDR','"https://test1.mydetao.cn/"'
             resValue "string", "app_name", "歌词工具"
             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
         }
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3d7d703..611afe8 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -33,6 +33,7 @@
         android:label="@string/app_name"
         android:roundIcon="@mipmap/ic_launcher_round"
         android:supportsRtl="true"
+        android:networkSecurityConfig="@xml/network_security_config"
         android:theme="@style/Theme.AutoLyric">
         <activity
             android:name=".MainActivity"
diff --git a/app/src/main/java/com/auto/lyric/MainActivity.java b/app/src/main/java/com/auto/lyric/MainActivity.java
index e0ac153..fa1f3cf 100644
--- a/app/src/main/java/com/auto/lyric/MainActivity.java
+++ b/app/src/main/java/com/auto/lyric/MainActivity.java
@@ -6,27 +6,79 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.LinearLayout;
 import android.widget.Toast;
 
+import androidx.appcompat.app.AlertDialog;
+
 import com.auto.lyric.base.activities.BaseActivity;
+import com.auto.lyric.data.ActiveResult;
 import com.auto.lyric.data.LyricServer;
 import com.auto.lyric.data.TextBean;
 import com.auto.lyric.databinding.ActivityMainBinding;
+import com.auto.lyric.retrofit.observable.LoadingHttpObserver;
 import com.auto.lyric.service.AutoInputService;
 import com.auto.lyric.service.FloatingWindowService;
+import com.auto.lyric.util.DeviceUtil;
 import com.auto.lyric.vm.MainViewModel;
+import com.google.gson.Gson;
 
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Date;
 import java.util.regex.Pattern;
 
 public class MainActivity extends BaseActivity<ActivityMainBinding, MainViewModel> {
+    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
 
     @Override
     public void initViews() {
         Intent floatService  = new Intent(getApplicationContext(), FloatingWindowService.class);
+        String key = getStringProjectPrefrence("activeKey");
+        ActiveResult result = new Gson().fromJson(key,ActiveResult.class);
+        try {
+            if(TextUtils.isEmpty(key) || TextUtils.isEmpty(result.validDate)||
+                    new Date().getTime() > dateFormat.parse(result.validDate).getTime()){
+                AlertDialog.Builder builder = new AlertDialog.Builder(this);
+                builder.setTitle("软件尚未激活或已过期");
+                EditText editText = new EditText(this);
+                editText.setHint("请输入激活码");
+                ViewGroup.MarginLayoutParams params = new ViewGroup.MarginLayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+                params.setMargins(DeviceUtil.convertDpToPixel(30,this),DeviceUtil.convertDpToPixel(20,this),DeviceUtil.convertDpToPixel(30,this),0);
+                editText.setLayoutParams(params);
+                LinearLayout lin = new LinearLayout(this);
+                lin.addView(editText);
+                builder.setView(lin);
+                builder.setCancelable(false);
+                AlertDialog dialg = builder.create();
+                dialg.setButton(AlertDialog.BUTTON_NEGATIVE,"激活", (dialog, which) -> {
+                    viewModel.checkActive(editText.getText().toString().trim(),new LoadingHttpObserver<ActiveResult>(this) {
+
+                        @Override
+                        public void onError(ActiveResult error) {
+                            super.onError(error);
+                            dialg.show();
+                        }
+
+                        @Override
+                        public void onComplete(ActiveResult result) {
+
+                        }
+                    });
+                });
+                dialg.setButton(AlertDialog.BUTTON_POSITIVE,"退出程序",(dialog,which) ->{
+                    System.exit(0);
+                });
+                dialg.show();
+            }
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+
         binding.button.setOnClickListener(v -> {
 
             if(binding.edit.getText().toString().trim().length() == 0){
diff --git a/app/src/main/java/com/auto/lyric/base/activities/BaseActivity.java b/app/src/main/java/com/auto/lyric/base/activities/BaseActivity.java
index df0058d..23a5cac 100644
--- a/app/src/main/java/com/auto/lyric/base/activities/BaseActivity.java
+++ b/app/src/main/java/com/auto/lyric/base/activities/BaseActivity.java
@@ -25,10 +25,12 @@
 import com.auto.lyric.R;
 import com.auto.lyric.base.model.BaseViewModel;
 import com.auto.lyric.base.model.ViewModelFactory;
+import com.auto.lyric.util.PreferencesUtils;
 
 import java.io.File;
 import java.lang.reflect.Method;
 import java.lang.reflect.ParameterizedType;
+import java.util.Set;
 
 import dmax.dialog.SpotsDialog;
 
@@ -93,6 +95,7 @@
         }
         Class<VM> vmClass = (Class<VM>) type.getActualTypeArguments()[1];
         viewModel = new ViewModelProvider(this,getViewModelFactory()).get(vmClass);
+        viewModel.onCreate(this);
         setContentView(binding.getRoot());
         mContext = this;
         try {
@@ -288,4 +291,126 @@
         return false;
     }
 
+    public boolean getBooleanUserPrefrence(String key){
+        return PreferencesUtils.getBoolean(this,key,false,PreferencesUtils.USER);
+    }
+
+    public boolean getBooleanProjectPrefrence(String key){
+        return PreferencesUtils.getBoolean(this,key,false,PreferencesUtils.PROJECT);
+    }
+
+    public String getStringUserPrefrence(String key){
+        return PreferencesUtils.getString(this,key,"",PreferencesUtils.USER);
+    }
+
+    public String getStringProjectPrefrence(String key){
+        return PreferencesUtils.getString(this,key,"",PreferencesUtils.PROJECT);
+    }
+
+    public Integer getIntProjectPrefrence(String key){
+        return PreferencesUtils.getInt(this,key,0,PreferencesUtils.PROJECT);
+    }
+
+    public Long getLongProjectPrefrence(String key){
+        return PreferencesUtils.getLong(this,key,0,PreferencesUtils.PROJECT);
+    }
+
+    public float getFloatProjectPrefrence(String key){
+        return PreferencesUtils.getFloat(this,key,0,PreferencesUtils.PROJECT);
+    }
+
+    public Set getStringSetProjectPrefrence(String key){
+        return PreferencesUtils.getStringSet(this,key,PreferencesUtils.PROJECT);
+    }
+
+    public Integer getIntUserPrefrence(String key){
+        return PreferencesUtils.getInt(this,key,0,PreferencesUtils.USER);
+    }
+
+    public Long getLongUserPrefrence(String key){
+        return PreferencesUtils.getLong(this,key,0,PreferencesUtils.USER);
+    }
+
+    public float getFloatUserPrefrence(String key){
+        return PreferencesUtils.getFloat(this,key,0,PreferencesUtils.USER);
+    }
+
+    public Set getStringSetUserPrefrence(String key){
+        return PreferencesUtils.getStringSet(this,key,PreferencesUtils.USER);
+    }
+
+
+    public void putBooleanUserPrefrence(String key ,Boolean value){
+        PreferencesUtils.putBoolean(this,key,value,PreferencesUtils.USER);
+    }
+
+    public void putBooleanProjectPrefrence(String key,Boolean value){
+        PreferencesUtils.putBoolean(this,key,value,PreferencesUtils.PROJECT);
+    }
+
+    public void putStringUserPrefrence(String key,String value){
+        PreferencesUtils.putString(this,key,value,PreferencesUtils.USER);
+    }
+
+    public void putStringProjectPrefrence(String key,String value){
+        PreferencesUtils.putString(this,key,value,PreferencesUtils.PROJECT);
+    }
+
+    public void putIntProjectPrefrence(String key,int value){
+        PreferencesUtils.putInt(this,key,value,PreferencesUtils.PROJECT);
+    }
+
+    public void putLongProjectPrefrence(String key,long value){
+        PreferencesUtils.putLong(this,key,value,PreferencesUtils.PROJECT);
+    }
+
+    public void putFloatProjectPrefrence(String key,float value){
+        PreferencesUtils.putFloat(this,key,value,PreferencesUtils.PROJECT);
+    }
+
+    public void putStringSetProjectPrefrence(String key, Set value){
+        PreferencesUtils.putStringSet(this,key,value,PreferencesUtils.PROJECT);
+    }
+
+    public void putIntUserPrefrence(String key,int value){
+        PreferencesUtils.putInt(this,key,value,PreferencesUtils.USER);
+    }
+
+    public void putLongUserPrefrence(String key,long value){
+        PreferencesUtils.putLong(this,key,value,PreferencesUtils.USER);
+    }
+
+    public void putFloatUserPrefrence(String key,float value){
+        PreferencesUtils.putFloat(this,key,value,PreferencesUtils.USER);
+    }
+
+    public void putStringSetUserPrefrence(String key, Set value){
+        PreferencesUtils.putStringSet(this,key,value,PreferencesUtils.USER);
+    }
+
+
+    public void removeUserKey(String key){
+        PreferencesUtils.removeKey(this,key,PreferencesUtils.USER);
+    }
+
+    public void removeProjectKey(String key){
+        PreferencesUtils.removeKey(this,key,PreferencesUtils.PROJECT);
+    }
+
+    public void removeUserValue(String Value){
+        PreferencesUtils.removeValue(this,Value,PreferencesUtils.USER);
+    }
+
+    public void removeProjectValue(String Value){
+        PreferencesUtils.removeValue(this,Value,PreferencesUtils.PROJECT);
+    }
+
+
+    public void clearProjectData(){
+        PreferencesUtils.clearData(this,PreferencesUtils.PROJECT);
+    }
+    public void clearUserData(){
+        PreferencesUtils.clearData(this,PreferencesUtils.USER);
+    }
+
 }
diff --git a/app/src/main/java/com/auto/lyric/base/activities/BaseLoadPageActivity.java b/app/src/main/java/com/auto/lyric/base/activities/BaseLoadPageActivity.java
index 5fa07b2..528ef38 100644
--- a/app/src/main/java/com/auto/lyric/base/activities/BaseLoadPageActivity.java
+++ b/app/src/main/java/com/auto/lyric/base/activities/BaseLoadPageActivity.java
@@ -65,27 +65,20 @@
     }
 
     private void finishFreshLoadmore(D result){
-        if(result.code == 200){
-
-            smartRefresh.setEnableRefresh(true);
-            smartRefresh.finishRefresh();
-            if(page == 1){
-                adapter.getData().clear();
-                adapter.setData(result.rows);
-            }else{
-                adapter.getData().addAll(result.rows);
-                adapter.notifyDataSetChanged();
-            }
-            if(result.total <= adapter.getData().size()// 总数是否已经加载完
-                    || result.rows.size() < SIZE // 最后一页数据的数量一般不满size
-            ){//判断是否没有数据了
-                smartRefresh.finishLoadMoreWithNoMoreData();
-            }else {
-                smartRefresh.finishLoadMore();
-            }
+        smartRefresh.setEnableRefresh(true);
+        smartRefresh.finishRefresh();
+        if(page == 1){
+            adapter.getData().clear();
+            adapter.setData(result.rows);
         }else{
-            smartRefresh.setEnableRefresh(true);
-            smartRefresh.finishRefresh();
+            adapter.getData().addAll(result.rows);
+            adapter.notifyDataSetChanged();
+        }
+        if(result.total <= adapter.getData().size()// 总数是否已经加载完
+                || result.rows.size() < SIZE // 最后一页数据的数量一般不满size
+        ){//判断是否没有数据了
+            smartRefresh.finishLoadMoreWithNoMoreData();
+        }else {
             smartRefresh.finishLoadMore();
         }
     }
diff --git a/app/src/main/java/com/auto/lyric/base/fragments/BaseFragment.java b/app/src/main/java/com/auto/lyric/base/fragments/BaseFragment.java
index 9825d55..629490d 100644
--- a/app/src/main/java/com/auto/lyric/base/fragments/BaseFragment.java
+++ b/app/src/main/java/com/auto/lyric/base/fragments/BaseFragment.java
@@ -7,11 +7,11 @@
 
 import androidx.annotation.Nullable;
 import androidx.fragment.app.Fragment;
-import androidx.lifecycle.ViewModel;
 import androidx.lifecycle.ViewModelProvider;
 import androidx.viewbinding.ViewBinding;
 
 import com.auto.lyric.base.activities.BaseActivity;
+import com.auto.lyric.base.model.BaseViewModel;
 import com.auto.lyric.base.model.ViewModelFactory;
 
 import java.lang.reflect.Method;
@@ -21,7 +21,7 @@
  * fragment 封装
  * Created by Administrator on 2021/10/28 0028.
  */
-public abstract class BaseFragment<B extends ViewBinding,VM extends ViewModel> extends Fragment {
+public abstract class BaseFragment<B extends ViewBinding,VM extends BaseViewModel> extends Fragment {
 
     protected BaseActivity activity;
     protected  B binding;
@@ -52,6 +52,7 @@
     public void onActivityCreated(@Nullable Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
         activity = (BaseActivity) getActivity();
+        viewModel.onCreate(activity);
         initViews();
     }
 
diff --git a/app/src/main/java/com/auto/lyric/base/fragments/BaseLoadPageFragment.java b/app/src/main/java/com/auto/lyric/base/fragments/BaseLoadPageFragment.java
index 82093f3..23d28bd 100644
--- a/app/src/main/java/com/auto/lyric/base/fragments/BaseLoadPageFragment.java
+++ b/app/src/main/java/com/auto/lyric/base/fragments/BaseLoadPageFragment.java
@@ -77,27 +77,20 @@
     }
 
     private void finishFreshLoadmore(D result){
-        if(result.code == 200){
-
-            smartRefresh.setEnableRefresh(true);
-            smartRefresh.finishRefresh();
-            if(page == 1){
-                adapter.getData().clear();
-                adapter.setData(result.rows);
-            }else{
-                adapter.getData().addAll(result.rows);
-                adapter.notifyDataSetChanged();
-            }
-            if(result.total <= adapter.getData().size()// 总数是否已经加载完
-                    || result.rows.size() < SIZE // 最后一页数据的数量一般不满size
-            ){//判断是否没有数据了
-                smartRefresh.finishLoadMoreWithNoMoreData();
-            }else {
-                smartRefresh.finishLoadMore();
-            }
+        smartRefresh.setEnableRefresh(true);
+        smartRefresh.finishRefresh();
+        if(page == 1){
+            adapter.getData().clear();
+            adapter.setData(result.rows);
         }else{
-            smartRefresh.setEnableRefresh(true);
-            smartRefresh.finishRefresh();
+            adapter.getData().addAll(result.rows);
+            adapter.notifyDataSetChanged();
+        }
+        if(result.total <= adapter.getData().size()// 总数是否已经加载完
+                || result.rows.size() < SIZE // 最后一页数据的数量一般不满size
+        ){//判断是否没有数据了
+            smartRefresh.finishLoadMoreWithNoMoreData();
+        }else {
             smartRefresh.finishLoadMore();
         }
     }
diff --git a/app/src/main/java/com/auto/lyric/base/fragments/BaseTabFragment.java b/app/src/main/java/com/auto/lyric/base/fragments/BaseTabFragment.java
index 23485de..3c21308 100644
--- a/app/src/main/java/com/auto/lyric/base/fragments/BaseTabFragment.java
+++ b/app/src/main/java/com/auto/lyric/base/fragments/BaseTabFragment.java
@@ -1,10 +1,10 @@
 package com.auto.lyric.base.fragments;
 
-import androidx.lifecycle.ViewModel;
 import androidx.viewbinding.ViewBinding;
 import androidx.viewpager2.widget.ViewPager2;
 
 import com.auto.lyric.base.adapter.FragmentAdapter;
+import com.auto.lyric.base.model.BaseViewModel;
 import com.google.android.material.tabs.TabLayout;
 import com.google.android.material.tabs.TabLayoutMediator;
 
@@ -16,7 +16,7 @@
  * 带有tablayout fragment封装
  * Created by Administrator on 2021/11/3 0003.
  */
-public abstract class BaseTabFragment<B extends ViewBinding,VM extends ViewModel> extends BaseFragment<B,VM> {
+public abstract class BaseTabFragment<B extends ViewBinding,VM extends BaseViewModel> extends BaseFragment<B,VM> {
 
     TabLayout tabLayout;
     FragmentAdapter fragmentAdapter;
diff --git a/app/src/main/java/com/auto/lyric/base/model/BaseViewModel.java b/app/src/main/java/com/auto/lyric/base/model/BaseViewModel.java
index bbc4039..83badfd 100644
--- a/app/src/main/java/com/auto/lyric/base/model/BaseViewModel.java
+++ b/app/src/main/java/com/auto/lyric/base/model/BaseViewModel.java
@@ -2,6 +2,7 @@
 
 import androidx.lifecycle.ViewModel;
 
+import com.auto.lyric.base.activities.BaseActivity;
 import com.auto.lyric.retrofit.AndroidScheduler;
 import com.auto.lyric.retrofit.observable.HttpObserver;
 
@@ -13,6 +14,11 @@
  */
 public class BaseViewModel extends ViewModel {
 
+    protected BaseActivity activity;
+
+    public void onCreate(BaseActivity activity){
+        this.activity = activity;
+    }
 
     /**
      * 网络请求观察
diff --git a/app/src/main/java/com/auto/lyric/data/ActiveBean.java b/app/src/main/java/com/auto/lyric/data/ActiveBean.java
new file mode 100644
index 0000000..a40382c
--- /dev/null
+++ b/app/src/main/java/com/auto/lyric/data/ActiveBean.java
@@ -0,0 +1,9 @@
+package com.auto.lyric.data;
+
+/**
+ * Created by Runt (qingingrunt2010@qq.com) on 2022/5/29.
+ */
+public class ActiveBean {
+    public String activeKey, ip, phoneID, random,sign;
+    public long timeStamp ; public int userId;
+}
diff --git a/app/src/main/java/com/auto/lyric/data/ActiveResult.java b/app/src/main/java/com/auto/lyric/data/ActiveResult.java
new file mode 100644
index 0000000..5311e27
--- /dev/null
+++ b/app/src/main/java/com/auto/lyric/data/ActiveResult.java
@@ -0,0 +1,9 @@
+package com.auto.lyric.data;
+
+/**
+ * Created by Runt (qingingrunt2010@qq.com) on 2022/5/29.
+ */
+public class ActiveResult extends BaseApiResult{
+    public String userID,userClassName,validDate,permission;
+    public int userClass;
+}
diff --git a/app/src/main/java/com/auto/lyric/data/ApkUpGradeResult.java b/app/src/main/java/com/auto/lyric/data/ApkUpGradeResult.java
index 2e1e710..708adb2 100644
--- a/app/src/main/java/com/auto/lyric/data/ApkUpGradeResult.java
+++ b/app/src/main/java/com/auto/lyric/data/ApkUpGradeResult.java
@@ -3,7 +3,7 @@
 /**
  * Created by Administrator on 2021/11/15 0015.
  */
-public class ApkUpGradeResult extends BaseApiResult<ApkUpGradeResult.AppInfo>{
+public class ApkUpGradeResult extends BaseApiResult{
 
     public class AppInfo {
         //以下为声明的参数
diff --git a/app/src/main/java/com/auto/lyric/data/BaseApiResult.java b/app/src/main/java/com/auto/lyric/data/BaseApiResult.java
index 7156b95..424f901 100644
--- a/app/src/main/java/com/auto/lyric/data/BaseApiResult.java
+++ b/app/src/main/java/com/auto/lyric/data/BaseApiResult.java
@@ -5,19 +5,6 @@
 /**
  * Created by Administrator on 2021/10/28 0028.
  */
-public class BaseApiResult<D extends Object> implements Serializable {
-    public String msg;
-    public int code = 200;
-    public D data;
-
-
-    @Override
-    public String toString() {
-        return "BaseApiData{" +
-                "msg='" + msg + '\'' +
-                ", code=" + code +
-                ", data=" + data +
-                '}';
-    }
-
+public class BaseApiResult implements Serializable {
+    public String result,reason,errorInfo;
 }
diff --git a/app/src/main/java/com/auto/lyric/data/BasePageResult.java b/app/src/main/java/com/auto/lyric/data/BasePageResult.java
index e5af862..f091fb7 100644
--- a/app/src/main/java/com/auto/lyric/data/BasePageResult.java
+++ b/app/src/main/java/com/auto/lyric/data/BasePageResult.java
@@ -5,7 +5,7 @@
 /**
  * Created by Administrator on 2021/10/28 0028.
  */
-public class BasePageResult<T> extends BaseApiResult<String>{
+public class BasePageResult<T> extends BaseApiResult{
     public int pages;
     public int total;
     public int pageNum;
diff --git a/app/src/main/java/com/auto/lyric/retrofit/Interceptor/HttpLoggingInterceptor.java b/app/src/main/java/com/auto/lyric/retrofit/Interceptor/HttpLoggingInterceptor.java
index d75056a..c567957 100644
--- a/app/src/main/java/com/auto/lyric/retrofit/Interceptor/HttpLoggingInterceptor.java
+++ b/app/src/main/java/com/auto/lyric/retrofit/Interceptor/HttpLoggingInterceptor.java
@@ -5,7 +5,6 @@
 import com.auto.lyric.retrofit.net.NetWorkCost;
 import com.auto.lyric.retrofit.net.NetWorkListenear;
 import com.auto.lyric.retrofit.utils.HttpPrintUtils;
-import com.auto.lyric.util.GsonUtils;
 
 import org.json.JSONObject;
 
@@ -111,33 +110,37 @@
                 charset = contentType.charset(UTF8);
             }
             HashMap param = new HashMap();
-            if(requestBody instanceof MultipartBody){
-                logArrays.add("---------->REQUEST BODY[MultipartBody]<----------");
-                MultipartBody body = (MultipartBody) requestBody;
-                for(MultipartBody.Part part:body.parts()){
-                    Buffer buffer1 = new Buffer();
-                    part.body().writeTo(buffer1);
-                    String str=buffer1.readString(charset).replaceAll("%(?![0-9a-fA-F]{2})","%25");
-                    param.put(part.headers().get(part.headers().name(0)),URLDecoder.decode(str, "UTF-8"));
+            try {
+                if(requestBody instanceof MultipartBody){
+                    logArrays.add("---------->REQUEST BODY[MultipartBody]<----------");
+                    MultipartBody body = (MultipartBody) requestBody;
+                    for(MultipartBody.Part part:body.parts()){
+                        Buffer buffer1 = new Buffer();
+                        part.body().writeTo(buffer1);
+                        String str=buffer1.readString(charset).replaceAll("%(?![0-9a-fA-F]{2})","%25");
+                        param.put(part.headers().get(part.headers().name(0)),URLDecoder.decode(str, "UTF-8"));
+                    }
+                    logArrays.add(new JSONObject(param).toString(4));
+                }else if(requestBody instanceof FormBody){
+                    logArrays.add("---------->REQUEST BODY[FormBody]<----------");
+                    FormBody body = (FormBody) requestBody;
+                    for(int i = 0 ; i < body.size() ; i ++ ){
+                        param.put(body.name(i),body.value(i));
+                    }
+                    logArrays.add(new JSONObject(param).toString(4));
+                }else{
+                    Buffer buffer = new Buffer();
+                    requestBody.writeTo(buffer);
+                    logArrays.add("---------->REQUEST BODY<----------");
+                    String str = buffer.readString(charset);
+                    if(str.indexOf("{") == 0 ){
+                        logArrays.add(new JSONObject(URLDecoder.decode(str, "UTF-8")).toString(4));
+                    }else{
+                        logArrays.add(str);
+                    }
                 }
-                logArrays.add(GsonUtils.retractJson(new JSONObject(param).toString()));
-            }else if(requestBody instanceof FormBody){
-                logArrays.add("---------->REQUEST BODY[FormBody]<----------");
-                FormBody body = (FormBody) requestBody;
-                for(int i = 0 ; i < body.size() ; i ++ ){
-                    param.put(body.name(i),body.value(i));
-                }
-                logArrays.add(GsonUtils.retractJson(new JSONObject(param).toString()));
-            }else{
-                Buffer buffer = new Buffer();
-                requestBody.writeTo(buffer);
-                logArrays.add("---------->REQUEST BODY<----------");
-                String str = buffer.readString(charset);
-                try{
-                    logArrays.add(GsonUtils.retractJson(URLDecoder.decode(str, "UTF-8")));
-                }catch (Exception e){
-                    logArrays.add(str);
-                }
+            } catch (Exception e) {
+                e.printStackTrace();
             }
             logArrays.add("--> END " + request.method() + " " + contentType + " ( "
                     + requestBody.contentLength() + "-byte body )");
diff --git a/app/src/main/java/com/auto/lyric/retrofit/api/CollectApiCenter.java b/app/src/main/java/com/auto/lyric/retrofit/api/CollectApiCenter.java
new file mode 100644
index 0000000..8b5e706
--- /dev/null
+++ b/app/src/main/java/com/auto/lyric/retrofit/api/CollectApiCenter.java
@@ -0,0 +1,79 @@
+package com.auto.lyric.retrofit.api;
+
+import com.auto.lyric.data.ActiveResult;
+import com.auto.lyric.ui.collect.CollectListResult;
+
+import io.reactivex.Observable;
+import retrofit2.http.Field;
+import retrofit2.http.FormUrlEncoded;
+import retrofit2.http.POST;
+
+/**
+ * Created by Runt (qingingrunt2010@qq.com) on 2022/5/29.
+ */
+public interface CollectApiCenter {
+
+
+    /**
+     * 收藏夹列表
+     * @return
+     */
+    @FormUrlEncoded
+    @POST("index.php?route=lrc/favorites/getFavoritesList")
+    Observable<CollectListResult> getCollectList();
+
+    /**
+     * 歌词详情
+     * @return
+     */
+    @FormUrlEncoded
+    @POST("index.php?route=lrc/favorites/getLrc")
+    Observable<CollectListResult> getLrcDetail(@Field("lrc_id") int lrc_id);
+
+    /**
+     * 删除歌词
+     * @return
+     */
+    @FormUrlEncoded
+    @POST("index.php?route=lrc/favorites/delLrc")
+    Observable<CollectListResult> removeLrc(@Field("lrc_id") int lrc_id);
+
+    /**
+     * 添加歌词歌词
+     * @return
+     */
+    @FormUrlEncoded
+    @POST("index.php?route=lrc/favorites/delLrc")
+    Observable<CollectListResult> addLrc(@Field("lrc_title") String lrc_title,@Field("lrc_text") String lrc_text);
+
+    /**
+     * 激活软件
+     * @param activeKey
+     * @param ip
+     * @param random
+     * @param time
+     * @param userId
+     * @param sign
+     * @return
+     */
+    @FormUrlEncoded
+    @POST("index.php?route=lrc/login_check")
+    Observable<ActiveResult> loginCheck(@Field("activeKey") String activeKey, @Field("ip") String ip, @Field("random") String random,
+                                        @Field("timeStamp") long time, @Field("userId") int userId, @Field("sign") String sign);
+
+    /**
+     * 激活软件
+     * @param activeKey
+     * @param ip
+     * @param random
+     * @param time
+     * @param userId
+     * @param sign
+     * @return
+     */
+    @FormUrlEncoded
+    @POST("index.php?route=lrc/register")
+    Observable<ActiveResult> register(@Field("activeKey") String activeKey, @Field("ip") String ip,@Field("phoneID") String phoneID, @Field("random") String random,
+                                      @Field("timeStamp") long time, @Field("userID") int userId, @Field("sign") String sign);
+
+}
diff --git a/app/src/main/java/com/auto/lyric/retrofit/api/CommonApiCenter.java b/app/src/main/java/com/auto/lyric/retrofit/api/CommonApiCenter.java
index 3e673e2..84bed84 100644
--- a/app/src/main/java/com/auto/lyric/retrofit/api/CommonApiCenter.java
+++ b/app/src/main/java/com/auto/lyric/retrofit/api/CommonApiCenter.java
@@ -2,6 +2,7 @@
 
 
 
+import com.auto.lyric.data.ActiveResult;
 import com.auto.lyric.data.ApkUpGradeResult;
 
 import java.util.Map;
@@ -63,4 +64,5 @@
     Observable<ApkUpGradeResult> getAppUpdate();
 
 
+
 }
diff --git a/app/src/main/java/com/auto/lyric/retrofit/converter/DecryptGsonResponseBodyConverter.java b/app/src/main/java/com/auto/lyric/retrofit/converter/DecryptGsonResponseBodyConverter.java
index a86ecf0..8acd35a 100644
--- a/app/src/main/java/com/auto/lyric/retrofit/converter/DecryptGsonResponseBodyConverter.java
+++ b/app/src/main/java/com/auto/lyric/retrofit/converter/DecryptGsonResponseBodyConverter.java
@@ -1,5 +1,6 @@
 package com.auto.lyric.retrofit.converter;
 
+import android.text.TextUtils;
 import android.util.Log;
 
 import com.auto.lyric.data.BaseApiResult;
@@ -51,15 +52,15 @@
             response = decryptJsonStr(val);//解密
         } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
             e.printStackTrace();
-            BaseApiResult apiResult = new BaseApiResult<>();
-            apiResult.code = 412;
-            apiResult.msg = "解密数据出错"+e.getMessage();
+            BaseApiResult apiResult = new BaseApiResult();
+            apiResult.result = "412";
+            apiResult.reason = "解密数据出错"+e.getMessage();
             response = new Gson().toJson(apiResult);
         } catch (JSONException e) {
             e.printStackTrace();
-            BaseApiResult apiResult = new BaseApiResult<>();
-            apiResult.code = 414;
-            apiResult.msg = "非标准json";
+            BaseApiResult apiResult = new BaseApiResult();
+            apiResult.result = "414";
+            apiResult.reason = "非标准json";
             response = new Gson().toJson(apiResult);
         }catch (Exception e){
             JsonReader jsonReader = gson.newJsonReader(value.charStream());
@@ -88,6 +89,8 @@
             JSONObject json = new JSONObject(body);
             body = json.toString();
             //body = RSAUtils.decrypt(json.getString(ENCRYPT), RSAUtils.getPublicKey(RSAUtils.PUBLIC_KEY));//
+        }else if(TextUtils.isEmpty(body)){
+            return body;
         }
         return transHump? GsonUtils.toHumpJson(body):body;
     }
diff --git a/app/src/main/java/com/auto/lyric/retrofit/observable/HttpObserver.java b/app/src/main/java/com/auto/lyric/retrofit/observable/HttpObserver.java
index 4bf4ece..91f4f7b 100644
--- a/app/src/main/java/com/auto/lyric/retrofit/observable/HttpObserver.java
+++ b/app/src/main/java/com/auto/lyric/retrofit/observable/HttpObserver.java
@@ -2,10 +2,9 @@
 
 import android.util.Log;
 
-import androidx.lifecycle.MutableLiveData;
-
 import com.auto.lyric.data.BaseApiResult;
 
+import java.io.EOFException;
 import java.lang.reflect.ParameterizedType;
 import java.net.SocketTimeoutException;
 
@@ -19,50 +18,67 @@
 
     final String TAG = "HttpObserver";
 
-    MutableLiveData<T> resultLive;
-
-    public HttpObserver(MutableLiveData<T> resultLive) {
-        this.resultLive = resultLive;
-    }
-
+    protected T value;
 
     @Override
     public void onNext(T value) {
-        resultLive.setValue(value);
+        this.value = value;
     }
 
+    /**
+     * 错误处理
+     * @param throwable
+     */
     @Override
     public void onError(Throwable throwable) {
-        Log.i("subscribe","onError");
-
+        Log.e("subscribe","onError "+throwable);
+        T t = null;
         try {
             Log.e(TAG,this.getClass().getSimpleName()+" "+throwable.getMessage());
             Class<T> entityClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
-            T t = entityClass.newInstance();//实例化一个泛型
-            t.code = 410;
+            t = entityClass.newInstance();//实例化一个泛型
+            t.result = "410";
             if( throwable instanceof SocketTimeoutException){
-                t.msg = "服务请求超时,请稍候再试";//设置错误信息
+                t.reason = "服务请求超时,请稍候再试";//设置错误信息
+            }else if(throwable instanceof EOFException){
+                t.reason = "服务未反馈任何内容";//设置错误信息
             }else{
-                t.msg = "网络连接不畅,请检查您的网络设置";//设置错误信息
+                t.reason = "网络连接不畅,请检查您的网络设置";//设置错误信息
             }
-            resultLive.setValue(t);
         } catch (ClassCastException e) {
             e.printStackTrace();
-            T t = (T) new BaseApiResult<String>();
-            t.code = 409;
-            t.msg = "实例化对象未指定泛型实体类";
-            resultLive.setValue(t);
+            t = (T) new BaseApiResult();
+            t.result = "409";
+            t.reason = "实例化对象未指定泛型实体类";
         } catch (Exception e) {
             e.printStackTrace();
-            T t = (T) new BaseApiResult<String>();
-            t.code = 409;
-            t.msg = e.getMessage();
-            resultLive.setValue(t);
+            t.result = "409";
+            t.reason = e.getMessage();
         }
+        onError(t);
     }
 
     @Override
     public void onComplete() {
+        if(value.result.equals("success")){
+            //返回成功
+            onComplete(value);
+        }else{
+            //返回失败
+            onError(value);
+        }
         Log.i("subscribe","onComplete");
     }
+
+    /**
+     * 接口返回成功
+     * @param result
+     */
+    public abstract void onError(T result) ;
+
+    /**
+     * 接口返回失败
+     * @param error
+     */
+    public abstract void onComplete(T error) ;
 }
diff --git a/app/src/main/java/com/auto/lyric/retrofit/observable/LoadingHttpObserver.java b/app/src/main/java/com/auto/lyric/retrofit/observable/LoadingHttpObserver.java
new file mode 100644
index 0000000..a9c783e
--- /dev/null
+++ b/app/src/main/java/com/auto/lyric/retrofit/observable/LoadingHttpObserver.java
@@ -0,0 +1,36 @@
+package com.auto.lyric.retrofit.observable;
+
+import android.text.TextUtils;
+
+import com.auto.lyric.base.activities.BaseActivity;
+import com.auto.lyric.data.BaseApiResult;
+
+/**
+ * Created by Runt (qingingrunt2010@qq.com) on 2022/5/29.
+ */
+public abstract class LoadingHttpObserver<T extends BaseApiResult> extends HttpObserver<T> {
+
+    final String TAG = "HttpObserver";
+    BaseActivity activity;
+
+    public LoadingHttpObserver(BaseActivity activity) {
+        this.activity = activity;
+    }
+
+    @Override
+    protected void onStart() {
+        activity.showLoadingDialog("正在请求中...");
+    }
+
+    @Override
+    public void onComplete() {
+        activity.dissmissLoadingDialog();
+        super.onComplete();
+    }
+
+    @Override
+    public void onError(T error) {
+        activity.dissmissLoadingDialog();
+        activity.showToast(error == null?"未知错误": TextUtils.isEmpty(error.reason)?error.errorInfo: error.reason);
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/auto/lyric/retrofit/utils/RetrofitUtils.java b/app/src/main/java/com/auto/lyric/retrofit/utils/RetrofitUtils.java
index ca63fbf..ef00975 100644
--- a/app/src/main/java/com/auto/lyric/retrofit/utils/RetrofitUtils.java
+++ b/app/src/main/java/com/auto/lyric/retrofit/utils/RetrofitUtils.java
@@ -23,7 +23,6 @@
  */
 
 public class RetrofitUtils {
-    public static String HOST_IP_ADDR;
     static RetrofitUtils instance;
     Retrofit retrofit/*log输出,驼峰转换*/,unHumpRetrofit/*log输出,不强制驼峰转换*/,
             unLogRetrofit/*log不输出,驼峰转换*/,unLogHumpRetorfit/*log不输出,不强制驼峰转换*/;
@@ -108,7 +107,7 @@
                 //设置OKHttpClient
                 .client(client)
                 //设置baseUrl,注意,baseUrl必须后缀"/"
-                //.baseUrl(BuildConfig.ENVIRONMENT.equals("develop")?HOST_IP_ADDR:BuildConfig.HOST_IP_ADDR)
+                .baseUrl(BuildConfig.HOST_IP_ADDR)
                 .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                 .build();
     }
diff --git a/app/src/main/java/com/auto/lyric/service/FloatingWindowService.java b/app/src/main/java/com/auto/lyric/service/FloatingWindowService.java
index b194d21..f6056fd 100644
--- a/app/src/main/java/com/auto/lyric/service/FloatingWindowService.java
+++ b/app/src/main/java/com/auto/lyric/service/FloatingWindowService.java
@@ -17,7 +17,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.WindowManager;
-import android.widget.Toast;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -28,9 +27,7 @@
 import com.auto.lyric.databinding.FloatViewBinding;
 import com.auto.lyric.util.DeviceUtil;
 
-import java.text.ParseException;
 import java.text.SimpleDateFormat;
-import java.util.Date;
 import java.util.Timer;
 import java.util.TimerTask;
 
@@ -45,7 +42,6 @@
     FloatViewBinding binding;
     final String TAG = "FloatingWindowService";
     final int THREAD_STOP = 0, KEYBOARD_SEND = 100;
-    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
     SimpleDateFormat msFormat = new SimpleDateFormat("mm:ss.SSS");
     boolean pause;//是否暂停
     int progress;//时间进度
@@ -136,14 +132,6 @@
         binding.btnFast.setOnClickListener(v -> progress+=700);
         binding.btnBack.setOnClickListener(v -> progress-=700);
         binding.btnStart.setOnClickListener(v -> {
-            try {
-                if(new Date().getTime() > dateFormat.parse("2022-09-30 04:00:00").getTime()){
-                    Toast.makeText(getApplicationContext(),"软件使用时间已过期", Toast.LENGTH_SHORT).show();
-                    return;
-                }
-            } catch (ParseException e) {
-                e.printStackTrace();
-            }
             if(binding.btnStart.getText().equals("开启")){
                 start();
             }else{
diff --git a/app/src/main/java/com/auto/lyric/ui/collect/Collect.java b/app/src/main/java/com/auto/lyric/ui/collect/Collect.java
new file mode 100644
index 0000000..add7e21
--- /dev/null
+++ b/app/src/main/java/com/auto/lyric/ui/collect/Collect.java
@@ -0,0 +1,9 @@
+package com.auto.lyric.ui.collect;
+
+/**
+ * Created by Runt (qingingrunt2010@qq.com) on 2022/5/29.
+ */
+public class Collect {
+    public int lrdId;
+    public String lrcTitle, lrdText;
+}
diff --git a/app/src/main/java/com/auto/lyric/ui/collect/CollectActivity.java b/app/src/main/java/com/auto/lyric/ui/collect/CollectActivity.java
new file mode 100644
index 0000000..fb255a7
--- /dev/null
+++ b/app/src/main/java/com/auto/lyric/ui/collect/CollectActivity.java
@@ -0,0 +1,16 @@
+package com.auto.lyric.ui.collect;
+
+import com.auto.lyric.base.activities.BaseTitleBarActivity;
+import com.auto.lyric.databinding.ActivityCollectBinding;
+
+/**
+ * Created by Runt (qingingrunt2010@qq.com) on 2022/5/29.
+ */
+public class CollectActivity extends BaseTitleBarActivity<ActivityCollectBinding,CollectViewModel> {
+
+
+    @Override
+    public void initViews() {
+
+    }
+}
diff --git a/app/src/main/java/com/auto/lyric/ui/collect/CollectListResult.java b/app/src/main/java/com/auto/lyric/ui/collect/CollectListResult.java
new file mode 100644
index 0000000..ac646d0
--- /dev/null
+++ b/app/src/main/java/com/auto/lyric/ui/collect/CollectListResult.java
@@ -0,0 +1,14 @@
+package com.auto.lyric.ui.collect;
+
+import com.auto.lyric.data.BaseApiResult;
+
+import java.util.List;
+
+/**
+ * Created by Runt (qingingrunt2010@qq.com) on 2022/5/29.
+ */
+public class CollectListResult extends BaseApiResult {
+
+    public List<Collect> list;
+
+}
diff --git a/app/src/main/java/com/auto/lyric/ui/collect/CollectViewModel.java b/app/src/main/java/com/auto/lyric/ui/collect/CollectViewModel.java
new file mode 100644
index 0000000..40d2382
--- /dev/null
+++ b/app/src/main/java/com/auto/lyric/ui/collect/CollectViewModel.java
@@ -0,0 +1,15 @@
+package com.auto.lyric.ui.collect;
+
+import com.auto.lyric.base.model.BaseViewModel;
+import com.auto.lyric.retrofit.observable.LoadingHttpObserver;
+
+/**
+ * Created by Runt (qingingrunt2010@qq.com) on 2022/5/29.
+ */
+public class CollectViewModel extends BaseViewModel {
+
+    public void getLrcList(LoadingHttpObserver<CollectListResult> observer){
+
+    }
+
+}
diff --git a/app/src/main/java/com/auto/lyric/util/DeviceIdUtils.java b/app/src/main/java/com/auto/lyric/util/DeviceIdUtils.java
new file mode 100644
index 0000000..cd10cdf
--- /dev/null
+++ b/app/src/main/java/com/auto/lyric/util/DeviceIdUtils.java
@@ -0,0 +1,124 @@
+package com.auto.lyric.util;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+
+import org.json.JSONObject;
+
+import java.lang.reflect.Method;
+import java.util.HashSet;
+
+/**
+ * copy from: http://docs.aiduoyou.com/web/#/100/1495
+ */
+public class DeviceIdUtils {
+
+
+    public static String getDeviceId(Context context, int slotId) {
+        try {
+            //实例化TelephonyManager对象
+            TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+            Method method = telephonyManager.getClass().getMethod("getDeviceId", int.class);
+            return (String) method.invoke(telephonyManager, slotId);
+        } catch (Exception e) {
+            //e.printStackTrace();
+        }
+        return "";
+    }
+
+    public static String getImei(Context context, int slotId) {
+        try {
+            //实例化TelephonyManager对象
+            TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+            Method method = telephonyManager.getClass().getMethod("getImei", int.class);
+            return (String) method.invoke(telephonyManager, slotId);
+        } catch (Exception e) {
+            //e.printStackTrace();
+        }
+        return "";
+    }
+
+    @SuppressLint("MissingPermission")
+    public static String getDeviceId(Context context) {
+        try {
+            TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+            return tm.getDeviceId();
+        } catch (Exception e) {
+            //e.printStackTrace();
+        }
+        return "";
+    }
+    public static String getImei(Context context) {
+        try {
+            //实例化TelephonyManager对象
+            TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+            Method method = telephonyManager.getClass().getMethod("getImei");
+            return (String) method.invoke(telephonyManager);
+        } catch (Exception e) {
+            //e.printStackTrace();
+        }
+        return "";
+    }
+
+    public static String getAndroidId(Context context) {
+        try {
+            return Settings.System.getString(context.getContentResolver(), Settings.System.ANDROID_ID);
+        } catch (Exception e) {
+            //e.printStackTrace();
+        }
+        return "";
+    }
+
+
+    public static JSONObject getDeviceIds(Context context) {
+        try {
+            String imei1 = getDeviceId(context, 0);
+            String imei2 = getDeviceId(context, 1);
+            String imei3 = getImei(context, 0);
+            String imei4 = getImei(context, 1);
+            String imei5 = getDeviceId(context);
+            String imei6 = getImei(context);
+            HashSet<String> hashSet = new HashSet();
+            if (!TextUtils.isEmpty(imei1)) {
+                hashSet.add(imei1);
+            }
+            if (!TextUtils.isEmpty(imei2)) {
+                hashSet.add(imei2);
+            }
+            if (!TextUtils.isEmpty(imei3)) {
+                hashSet.add(imei3);
+            }
+            if (!TextUtils.isEmpty(imei4)) {
+                hashSet.add(imei4);
+            }
+            if (!TextUtils.isEmpty(imei5)) {
+                hashSet.add(imei5);
+            }
+            if (!TextUtils.isEmpty(imei6)) {
+                hashSet.add(imei6);
+            }
+            JSONObject jsonObject = new JSONObject();
+            int i = 0;
+            for (String value : hashSet) {
+                i ++;
+                jsonObject.put(String.valueOf(i), value);
+            }
+
+            String androidId = getAndroidId(context);
+            if (!TextUtils.isEmpty(androidId)) {
+                jsonObject.put("6", androidId);
+            }
+
+            return jsonObject;
+        } catch (Exception e) {
+            //e.printStackTrace();
+        }
+        return null;
+    }
+
+
+
+}
diff --git a/app/src/main/java/com/auto/lyric/util/SpUtils.java b/app/src/main/java/com/auto/lyric/util/PreferencesUtils.java
similarity index 64%
rename from app/src/main/java/com/auto/lyric/util/SpUtils.java
rename to app/src/main/java/com/auto/lyric/util/PreferencesUtils.java
index 21cd1b3..79b06a6 100644
--- a/app/src/main/java/com/auto/lyric/util/SpUtils.java
+++ b/app/src/main/java/com/auto/lyric/util/PreferencesUtils.java
@@ -8,36 +8,35 @@
 import java.util.Set;
 
 /**
- * Created by Administrator on 2021/10/28 0028.
+ * PreferencesUtils, easy to get or put data
+ * <ul>
+ * <strong>Preference Name</strong>
+ * <li>you can change preference name by {@link #PREFERENCE_NAME}</li>
+ * </ul>
+ * <ul>
+ * <strong>Put Value</strong>
+ * </ul>
+ * 
+ * @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-3-6
  */
-public class SpUtils {
+public class PreferencesUtils {
 
-    static SpUtils instance;
-    
-    /**
-     * 获取SP实例
-     *
-     * @return {@link SpUtils}
-     */
-    public static SpUtils getInstance() {
-        if(instance == null){
-            instance = new SpUtils();
-        }
-        return instance;
+    public static final String PREFERENCE_NAME="zipper";
+    public static final String PROJECT = "project";
+    public static final String USER = "user";
+    public static final String VISITOR = "visitor";
+
+    private PreferencesUtils() {
+        throw new AssertionError();
     }
 
-    
-    public final static String PROJECT = "project";
-    public final static String USER = "user";
-
-
-    public boolean clearData(Context context, String keyShared){
+    public static boolean clearData(Context context, String keyShared){
         SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE);
         return settings.edit().clear().commit();
     }
 
 
-    public boolean clearData(Context context, String key, String keyShared){
+    public static boolean clearData(Context context, String key, String keyShared){
         putString(context,key,null,keyShared);
         return true;
     }
@@ -51,7 +50,7 @@
      * @param key The name of the preference to modify
      * @return True if the new values were successfully written to persistent storage.
      */
-    public void  removeKey(Context context, String key, String keyShared){
+    public static void  removeKey(Context context, String key, String keyShared){
 
         SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE);
         SharedPreferences.Editor editor = settings.edit();
@@ -65,7 +64,7 @@
      * @param value The name of the preference to modify
      * @return True if the new values were successfully written to persistent storage.
      */
-    public void  removeValue(Context context, String value, String keyShared){
+    public static void  removeValue(Context context, String value, String keyShared){
         SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE);
         SharedPreferences.Editor editor = settings.edit();
         editor.remove(value);
@@ -74,13 +73,13 @@
 
     /**
      * put string preferences
-     *
+     * 
      * @param context
      * @param key The name of the preference to modify
      * @param value The new value for the preference
      * @return True if the new values were successfully written to persistent storage.
      */
-    public boolean putString(Context context, String key, String value, String keyShared) {
+    public static boolean putString(Context context, String key, String value, String keyShared) {
         SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE);
         SharedPreferences.Editor editor = settings.edit();
         editor.putString(key, value);
@@ -89,40 +88,40 @@
 
     /**
      * get string preferences
-     *
+     * 
      * @param context
      * @param key The name of the preference to retrieve
      * @return The preference value if it exists, or null. Throws ClassCastException if there is a preference with this
      *         name that is not a string
      * @see #getString(Context, String, String)
      */
-    public String getString(Context context, String key, String keyShared) {
+    public static String getString(Context context, String key, String keyShared) {
         return getString(context, key, null,keyShared);
     }
 
     /**
      * get string preferences
-     *
+     * 
      * @param context
      * @param key The name of the preference to retrieve
      * @param defaultValue Value to return if this preference does not exist
      * @return The preference value if it exists, or defValue. Throws ClassCastException if there is a preference with
      *         this name that is not a string
      */
-    public String getString(Context context, String key, String defaultValue, String keyShared) {
+    public static String getString(Context context, String key, String defaultValue, String keyShared) {
         SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE);
         return settings.getString(key, defaultValue);
     }
 
     /**
      * put int preferences
-     *
+     * 
      * @param context
      * @param key The name of the preference to modify
      * @param value The new value for the preference
      * @return True if the new values were successfully written to persistent storage.
      */
-    public boolean putInt(Context context, String key, int value, String keyShared) {
+    public static boolean putInt(Context context, String key, int value, String keyShared) {
         SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE);
         SharedPreferences.Editor editor = settings.edit();
         editor.putInt(key, value);
@@ -131,26 +130,26 @@
 
     /**
      * get int preferences
-     *
+     * 
      * @param context
      * @param key The name of the preference to retrieve
      * @return The preference value if it exists, or -1. Throws ClassCastException if there is a preference with this
      *         name that is not a int
      */
-    public int getInt(Context context, String key, String keyShared) {
+    public static int getInt(Context context, String key, String keyShared) {
         return getInt(context, key, -1,keyShared);
     }
 
     /**
      * get int preferences
-     *
+     * 
      * @param context
      * @param key The name of the preference to retrieve
      * @param defaultValue Value to return if this preference does not exist
      * @return The preference value if it exists, or defValue. Throws ClassCastException if there is a preference with
      *         this name that is not a int
      */
-    public int getInt(Context context, String key, int defaultValue, String keyShared) {
+    public static int getInt(Context context, String key, int defaultValue, String keyShared) {
         SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE);
         try {
             return settings.getInt(key, defaultValue);
@@ -165,13 +164,13 @@
 
     /**
      * put long preferences
-     *
+     * 
      * @param context
      * @param key The name of the preference to modify
      * @param value The new value for the preference
      * @return True if the new values were successfully written to persistent storage.
      */
-    public boolean putLong(Context context, String key, long value, String keyShared) {
+    public static boolean putLong(Context context, String key, long value, String keyShared) {
         SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE);
         SharedPreferences.Editor editor = settings.edit();
         editor.putLong(key, value);
@@ -180,26 +179,26 @@
 
     /**
      * get long preferences
-     *
+     * 
      * @param context
      * @param key The name of the preference to retrieve
      * @return The preference value if it exists, or -1. Throws ClassCastException if there is a preference with this
      *         name that is not a long
      */
-    public long getLong(Context context, String key, String keyShared) {
+    public static long getLong(Context context, String key, String keyShared) {
         return getLong(context, key, -1,keyShared);
     }
 
     /**
      * get long preferences
-     *
+     * 
      * @param context
      * @param key The name of the preference to retrieve
      * @param defaultValue Value to return if this preference does not exist
      * @return The preference value if it exists, or defValue. Throws ClassCastException if there is a preference with
      *         this name that is not a long
      */
-    public long getLong(Context context, String key, long defaultValue, String keyShared) {
+    public static long getLong(Context context, String key, long defaultValue, String keyShared) {
         SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE);
         try {
             return settings.getLong(key, defaultValue);
@@ -214,13 +213,13 @@
 
     /**
      * put float preferences
-     *
+     * 
      * @param context
      * @param key The name of the preference to modify
      * @param value The new value for the preference
      * @return True if the new values were successfully written to persistent storage.
      */
-    public boolean putFloat(Context context, String key, float value, String keyShared) {
+    public static boolean putFloat(Context context, String key, float value, String keyShared) {
         SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE);
         SharedPreferences.Editor editor = settings.edit();
         editor.putFloat(key, value);
@@ -229,26 +228,26 @@
 
     /**
      * get float preferences
-     *
+     * 
      * @param context
      * @param key The name of the preference to retrieve
      * @return The preference value if it exists, or -1. Throws ClassCastException if there is a preference with this
      *         name that is not a float
      */
-    public float getFloat(Context context, String key, String keyShared) {
+    public static float getFloat(Context context, String key, String keyShared) {
         return getFloat(context, key, -1,keyShared);
     }
 
     /**
      * get float preferences
-     *
+     * 
      * @param context
      * @param key The name of the preference to retrieve
      * @param defaultValue Value to return if this preference does not exist
      * @return The preference value if it exists, or defValue. Throws ClassCastException if there is a preference with
      *         this name that is not a float
      */
-    public float getFloat(Context context, String key, float defaultValue, String keyShared) {
+    public static float getFloat(Context context, String key, float defaultValue, String keyShared) {
         SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE);
         try {
             return settings.getFloat(key, defaultValue);
@@ -263,13 +262,13 @@
 
     /**
      * put boolean preferences
-     *
+     * 
      * @param context
      * @param key The name of the preference to modify
      * @param value The new value for the preference
      * @return True if the new values were successfully written to persistent storage.
      */
-    public boolean putBoolean(Context context, String key, boolean value, String keyShared) {
+    public static boolean putBoolean(Context context, String key, boolean value, String keyShared) {
         SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE);
         SharedPreferences.Editor editor = settings.edit();
         editor.putBoolean(key, value);
@@ -278,26 +277,26 @@
 
     /**
      * get boolean preferences, default is false
-     *
+     * 
      * @param context
      * @param key The name of the preference to retrieve
      * @return The preference value if it exists, or false. Throws ClassCastException if there is a preference with this
      *         name that is not a boolean
      */
-    public boolean getBoolean(Context context, String key, String keyShared) {
+    public static boolean getBoolean(Context context, String key, String keyShared) {
         return getBoolean(context, key, false,keyShared);
     }
 
     /**
      * get boolean preferences
-     *
+     * 
      * @param context
      * @param key The name of the preference to retrieve
      * @param defaultValue Value to return if this preference does not exist
      * @return The preference value if it exists, or defValue. Throws ClassCastException if there is a preference with
      *         this name that is not a boolean
      */
-    public boolean getBoolean(Context context, String key, boolean defaultValue, String keyShared) {
+    public static boolean getBoolean(Context context, String key, boolean defaultValue, String keyShared) {
         SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE);
         try {
             return settings.getBoolean(key, defaultValue);
@@ -318,7 +317,7 @@
      * @param value The new value for the preference ,  the value of set ,canot be the other class out of java collection
      * @return True if the new values were successfully written to persistent storage.
      */
-    public boolean putStringSet(Context context, String key, Set value, String keyShared) {
+    public static boolean putStringSet(Context context, String key, Set value, String keyShared) {
         SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE);
         SharedPreferences.Editor editor = settings.edit();
         editor.putStringSet(key, value);
@@ -333,7 +332,7 @@
      * @return The preference value if it exists, or false. Throws ClassCastException if there is a preference with this
      *         name that is not a boolean 获取出来的值最终被转换为hashset类型
      */
-    public Set getStringSet(Context context, String key, String keyShared) {
+    public static Set getStringSet(Context context, String key, String keyShared) {
         return getStringSet(context, key,new ArraySet(),keyShared);
     }
 
@@ -346,131 +345,8 @@
      * @return The preference value if it exists, or defValue. Throws ClassCastException if there is a preference with
      *         this name that is not a boolean 获取出来的值最终被转换为hashset类型
      */
-    public Set getStringSet(Context context, String key, Set defaultValue, String keyShared) {
+    public static Set getStringSet(Context context, String key, Set defaultValue, String keyShared) {
         SharedPreferences settings = context.getSharedPreferences(keyShared, Context.MODE_PRIVATE);
         return settings.getStringSet(key, defaultValue);
     }
-
-    public boolean getBooleanValOfUser(Context context, String key){
-        return getBoolean(context,key,false,USER);
-    }
-
-    public boolean getBooleanValOfProject(Context context, String key){
-        return getBoolean(context,key,false,PROJECT);
-    }
-
-    public String getStringValOfUser(Context context, String key){
-        return getString(context,key,"",USER);
-    }
-
-    public String getStringValOfProject(Context context, String key){
-        return getString(context,key,"",PROJECT);
-    }
-
-    public int getIntValOfProject(Context context, String key){
-        return getInt(context,key,0,PROJECT);
-    }
-
-    public Long getLongValOfProject(Context context, String key){
-        return getLong(context,key,0,PROJECT);
-    }
-
-    public float getFloatValOfProject(Context context, String key){
-        return getFloat(context,key,0,PROJECT);
-    }
-
-    public Set getStringSetValOfProject(Context context, String key){
-        return getStringSet(context,key,PROJECT);
-    }
-
-    public int getIntValOfUser(Context context, String key){
-        return getInt(context,key,0,USER);
-    }
-
-    public Long getLongValOfUser(Context context, String key){
-        return getLong(context,key,0,USER);
-    }
-
-    public float getFloatValOfUser(Context context, String key){
-        return getFloat(context,key,0,USER);
-    }
-
-    public Set getStringSetValOfUser(Context context, String key){
-        return getStringSet(context,key,USER);
-    }
-
-
-    public void putBooleanValOfUser(Context context, String key ,Boolean value){
-        putBoolean(context,key,value,USER);
-    }
-
-    public void putBooleanValOfProject(Context context, String key,Boolean value){
-        putBoolean(context,key,value,PROJECT);
-    }
-
-    public void putStringValOfUser(Context context,String key,String value){
-        putString(context,key,value,USER);
-    }
-
-    public void putStringValOfProject(Context context,String key,String value){
-        putString(context,key,value,PROJECT);
-    }
-
-    public void putIntValOfProject(Context context,String key,int value){
-        putInt(context,key,value,PROJECT);
-    }
-
-    public void putLongValOfProject(Context context,String key,long value){
-        putLong(context,key,value,PROJECT);
-    }
-
-    public void putFloatValOfProject(Context context,String key,float value){
-        putFloat(context,key,value,PROJECT);
-    }
-
-    public void putStringSetValOfProject(Context context,String key,Set value){
-        putStringSet(context,key,value,PROJECT);
-    }
-
-    public void putIntValOfUser(Context context,String key,int value){
-        putInt(context,key,value,USER);
-    }
-
-    public void putLongValOfUser(Context context,String key,long value){
-        putLong(context,key,value,USER);
-    }
-
-    public void putFloatValOfUser(Context context,String key,float value){
-        putFloat(context,key,value,USER);
-    }
-
-    public void putStringSetValOfUser(Context context,String key, Set value){
-        putStringSet(context,key,value,USER);
-    }
-
-
-    public void removeUserKey(Context context, String key){
-        removeKey(context,key,USER);
-    }
-
-    public void removeProjectKey(Context context, String key){
-        removeKey(context,key,PROJECT);
-    }
-
-    public void removeUserValue(Context context, String Value){
-        removeValue(context,Value,USER);
-    }
-
-    public void removeProjectValue(Context context, String Value){
-        removeValue(context,Value,PROJECT);
-    }
-
-
-    public void clearProjectData(Context context){
-        clearData(context,PROJECT);
-    }
-    public void clearUserData(Context context){
-        clearData(context,USER);
-    }
-
 }
diff --git a/app/src/main/java/com/auto/lyric/util/SHA1UTIL.java b/app/src/main/java/com/auto/lyric/util/SHA1UTIL.java
new file mode 100644
index 0000000..2f9c5d7
--- /dev/null
+++ b/app/src/main/java/com/auto/lyric/util/SHA1UTIL.java
@@ -0,0 +1,64 @@
+package com.auto.lyric.util;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * Created by Runt (qingingrunt2010@qq.com) on 2022/5/29.
+ */
+public class SHA1UTIL {
+
+    public static String getSHA(String info) {
+        byte[] bytesSHA = null;
+        try {
+
+            MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
+
+            messageDigest.update(info.getBytes());
+
+            bytesSHA = messageDigest.digest();
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+        String strSHA = byteToHex(bytesSHA);
+        return strSHA;
+    }
+
+
+    private static String byteToHex(byte[] bytes) {
+        String hs = "";
+        String temp;
+        for (byte b : bytes) {
+            temp = (Integer.toHexString(b & 0XFF));
+            if (temp.length() == 1) {
+                hs = hs + "0" + temp;
+            } else {
+                hs = hs + temp;
+            }
+        }
+        return hs;
+    }
+
+    /**
+     * MD5加密之方法二
+     * @explain java实现
+     * @param str
+     *            待加密字符串
+     * @return 16进制加密字符串
+     */
+    public static String MD5(String str) {
+        // 加密后的16进制字符串
+        String hexStr = "";
+        try {
+            // 此 MessageDigest 类为应用程序提供信息摘要算法的功能
+            MessageDigest md5 = MessageDigest.getInstance("MD5");
+            // 转换为MD5码
+            byte[] digest = md5.digest(str.getBytes("utf-8"));
+            hexStr = byteToHex(digest);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return hexStr;
+    }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/auto/lyric/vm/MainViewModel.java b/app/src/main/java/com/auto/lyric/vm/MainViewModel.java
index 395a607..ad1aad3 100644
--- a/app/src/main/java/com/auto/lyric/vm/MainViewModel.java
+++ b/app/src/main/java/com/auto/lyric/vm/MainViewModel.java
@@ -1,9 +1,52 @@
 package com.auto.lyric.vm;
 
 import com.auto.lyric.base.model.BaseViewModel;
+import com.auto.lyric.data.ActiveResult;
+import com.auto.lyric.retrofit.api.CollectApiCenter;
+import com.auto.lyric.retrofit.observable.LoadingHttpObserver;
+import com.auto.lyric.retrofit.utils.RetrofitUtils;
+import com.auto.lyric.util.DeviceIdUtils;
+import com.auto.lyric.util.NetWorkUtils;
+import com.auto.lyric.util.SHA1UTIL;
+
+import java.util.Date;
+import java.util.UUID;
+
+import io.reactivex.Observable;
 
 /**
  * Created by Runt (qingingrunt2010@qq.com) on 2022/3/20.
  */
 public class MainViewModel extends BaseViewModel {
+
+    CollectApiCenter apiCenter;
+
+    public MainViewModel(){
+        apiCenter = RetrofitUtils.getInstance().getRetrofit(CollectApiCenter.class);
+    }
+
+    public void checkActive(String activeKey,LoadingHttpObserver<ActiveResult> observer){
+        String ip = NetWorkUtils.getNetIp();
+        String random = UUID.randomUUID().toString();
+        long time = new Date().getTime()/1000;
+        int userId = 0;
+        String deviceId = DeviceIdUtils.getAndroidId(activity);
+        String sign = String.format("%s%s%s%s%s%s",activeKey,ip,deviceId ,random,time,userId);
+
+        Observable<ActiveResult> observable = apiCenter.register(activeKey, ip,deviceId, random, time, userId, SHA1UTIL.MD5(SHA1UTIL.getSHA(sign)));
+        httpObserverOn(observable,observer);
+    }
+
+    public void register(String activeKey,LoadingHttpObserver<ActiveResult> observer){
+        String ip = NetWorkUtils.getNetIp();
+        String random = UUID.randomUUID().toString();
+        long time = new Date().getTime()/1000;
+        int userId = 0;
+        String deviceId = DeviceIdUtils.getAndroidId(activity);
+        String sign = String.format("%s%s%s%s%s%s",activeKey,ip,deviceId ,random,time,userId);
+
+        Observable<ActiveResult> observable = apiCenter.register(activeKey, ip,deviceId, random, time, userId, SHA1UTIL.MD5(SHA1UTIL.getSHA(sign)));
+        httpObserverOn(observable,observer);
+    }
+
 }
diff --git a/app/src/main/res/drawable-v21/bg_white_divider.xml b/app/src/main/res/drawable-v21/bg_white_divider.xml
new file mode 100644
index 0000000..8c3f482
--- /dev/null
+++ b/app/src/main/res/drawable-v21/bg_white_divider.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="@color/color_gray">
+    <item>
+        <selector>
+            <item android:state_pressed="true">
+                <shape android:shape="rectangle">
+                    <solid android:color="@color/gray_pressed" />
+                </shape>
+            </item>
+
+            <item android:state_enabled="false">
+                <shape android:shape="rectangle">
+                    <solid android:color="@color/cut_off_line" />
+                </shape>
+            </item>
+
+            <item>
+                <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+                    <!-- 主体背景颜色值 -->
+                    <item >
+                        <shape>
+                            <solid android:color="@color/white"/>
+                        </shape>
+                    </item>
+                    <!-- 连框颜色值 -->
+                    <item android:height="1dp" android:gravity="bottom">
+                        <shape>
+                            <solid android:color="@color/black"/>
+                        </shape>
+                    </item>
+                </layer-list>
+            </item>
+
+        </selector>
+    </item>
+
+</ripple>
diff --git a/app/src/main/res/layout/activity_collect.xml b/app/src/main/res/layout/activity_collect.xml
new file mode 100644
index 0000000..d1772ef
--- /dev/null
+++ b/app/src/main/res/layout/activity_collect.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <com.auto.lyric.widgets.TitleBarView
+        android:id="@+id/titlebar"
+        android:layout_width="match_parent"
+        android:layout_height="50dp"
+        android:background="@color/black"
+        app:titleTextColor="@color/white"
+        app:titleText="标题"
+        app:leftDrawable="@mipmap/icon_white_back"
+        android:paddingLeft="20dp"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintRight_toRightOf="parent" />
+
+    <include layout="@layout/refresh_recycler"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        app:layout_constraintTop_toBottomOf="@id/titlebar"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"/>
+
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 5fb776e..0362135 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -27,30 +27,58 @@
         android:layout_height="wrap_content"
         android:text="确认"
         android:layout_margin="10dp"
-        app:layout_constraintBottom_toBottomOf="@id/edit"
+        app:layout_constraintTop_toBottomOf="@id/edit"
         app:layout_constraintRight_toRightOf="@id/edit"/>
+
+    <androidx.appcompat.widget.AppCompatButton
+        android:id="@+id/clear"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="清空"
+        android:layout_margin="10dp"
+        app:layout_constraintRight_toLeftOf="@id/button"
+        app:layout_constraintTop_toBottomOf="@id/edit" />
+
+    <androidx.appcompat.widget.AppCompatButton
+        android:id="@+id/collect"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="收藏"
+        android:layout_margin="10dp"
+        app:layout_constraintRight_toLeftOf="@id/clear"
+        app:layout_constraintTop_toBottomOf="@id/edit" />
+
+    <androidx.appcompat.widget.AppCompatButton
+        android:id="@+id/save"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="保存"
+        android:layout_margin="10dp"
+        app:layout_constraintRight_toLeftOf="@id/collect"
+        app:layout_constraintLeft_toLeftOf="@id/edit"
+        app:layout_constraintTop_toBottomOf="@id/edit" />
 
     <TextView
         android:id="@+id/txt_local"
         android:layout_width="match_parent"
-        android:layout_height="40dp"
+        android:layout_height="50dp"
         android:text="本地歌词"
         android:gravity="center_vertical"
         android:paddingLeft="16dp"
         android:textSize="16sp"
-        android:background="@drawable/bg_white"
-        app:layout_constraintTop_toBottomOf="@id/edit"
+        android:background="@drawable/bg_white_divider"
+        app:layout_constraintTop_toBottomOf="@id/save"
         app:layout_constraintRight_toRightOf="parent"
         app:layout_constraintLeft_toLeftOf="parent"/>
     <TextView
         android:id="@+id/txt_favorite"
         android:layout_width="match_parent"
-        android:layout_height="40dp"
+        android:layout_height="50dp"
         android:text="我的收藏"
         android:gravity="center_vertical"
         android:paddingLeft="16dp"
         android:textSize="16sp"
-        android:background="@drawable/bg_white"
+        android:background="@drawable/bg_white_divider"
         app:layout_constraintTop_toBottomOf="@id/txt_local"
         app:layout_constraintRight_toRightOf="parent"
         app:layout_constraintLeft_toLeftOf="parent"/>
@@ -59,12 +87,12 @@
     <TextView
         android:id="@+id/txt_setting"
         android:layout_width="match_parent"
-        android:layout_height="40dp"
+        android:layout_height="50dp"
         android:text="设置"
         android:gravity="center_vertical"
         android:paddingLeft="16dp"
         android:textSize="16sp"
-        android:background="@drawable/bg_white"
+        android:background="@drawable/bg_white_divider"
         app:layout_constraintTop_toBottomOf="@id/txt_favorite"
         app:layout_constraintRight_toRightOf="parent"
         app:layout_constraintLeft_toLeftOf="parent"/>
diff --git a/app/src/main/res/mipmap-xhdpi/icon_white_back.png b/app/src/main/res/mipmap-xhdpi/icon_white_back.png
new file mode 100644
index 0000000..8f3faab
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/icon_white_back.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxhdpi/icon_white_back.png b/app/src/main/res/mipmap-xxhdpi/icon_white_back.png
new file mode 100644
index 0000000..7d82e4c
--- /dev/null
+++ b/app/src/main/res/mipmap-xxhdpi/icon_white_back.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/icon_white_back.png b/app/src/main/res/mipmap-xxxhdpi/icon_white_back.png
new file mode 100644
index 0000000..f982292
--- /dev/null
+++ b/app/src/main/res/mipmap-xxxhdpi/icon_white_back.png
Binary files differ

--
Gitblit v1.9.1