Linjiajia
2023-03-28 bf4e40cdf60c2a2fd8a486051a1ddac2daefef62
家大事记完善
34个文件已修改
65个文件已添加
2 文件已重命名
28个文件已删除
15828 ■■■■ 已修改文件
.idea/dbnavigator.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/deploymentTargetDropDown.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/AndroidManifest.xml 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/application/zhangshi_app_android/MyApplication.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/application/zhangshi_app_android/adapter/FamilyMemorabiliaRvAdapter.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/application/zhangshi_app_android/bean/CaptchaImageBean.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/application/zhangshi_app_android/bean/FamilyMemorabiliaBean.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/application/zhangshi_app_android/bean/FamilyMemorabiliaRequestBean.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/application/zhangshi_app_android/bean/FamilyMemorabiliaResponseBean.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/application/zhangshi_app_android/bean/LoginRequestBean.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/application/zhangshi_app_android/bean/LoginResponseBean.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/application/zhangshi_app_android/config/BaseConfig.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/application/zhangshi_app_android/data/DataRepository.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/application/zhangshi_app_android/data/source/HttpDataSource.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/application/zhangshi_app_android/data/source/http/ApiService.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/application/zhangshi_app_android/data/source/http/HttpDataSourceImpl.java 60 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/application/zhangshi_app_android/ui/function/FamilyMemorabiliaActivity.java 192 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/application/zhangshi_app_android/ui/function/FamilyMemorabiliaActivityViewModel.java 209 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/application/zhangshi_app_android/ui/login/LoginActivity.java 51 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/application/zhangshi_app_android/ui/login/LoginActivityViewModel.java 205 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xhdpi/bg_login_home.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xhdpi/function_family_root_net.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xhdpi/ic_add.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xhdpi/ic_checked.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xhdpi/ic_delete_white.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xhdpi/ic_operate_add.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xhdpi/ic_operate_finish.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xhdpi/ic_operate_order.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xhdpi/ic_operate_select.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xhdpi/ic_password_invisible.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xhdpi/ic_password_visible.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xhdpi/ic_search_by.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xhdpi/ic_search_gray.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xhdpi/ic_vector_gray.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xhdpi/ic_vector_pink.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xhdpi/ic_wx_login.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xxhdpi/bg_login_home.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xxhdpi/function_family_root_net.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xxhdpi/ic_add.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xxhdpi/ic_checked.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xxhdpi/ic_delete_white.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xxhdpi/ic_operate_add.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xxhdpi/ic_operate_finish.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xxhdpi/ic_operate_order.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xxhdpi/ic_operate_select.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xxhdpi/ic_password_invisible.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xxhdpi/ic_password_visible.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xxhdpi/ic_search_by.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xxhdpi/ic_search_gray.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xxhdpi/ic_vector_gray.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xxhdpi/ic_vector_pink.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable-xxhdpi/ic_wx_login.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable/selector_checkbox.xml 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/activity_family_memorabilia.xml 787 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/activity_login.xml 263 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/fragment_function.xml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/item_family_memorabilia.xml 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/item_menu_family_root_net.xml 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/pop_operate.xml 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/pop_search.xml 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/values/colors.xml 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/values/strings.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/values/themes.xml 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/build.gradle 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/base/BaseApplication.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/base/BaseConfig.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/base/action/ActivityAction.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/base/action/AnimAction.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/base/action/ClickAction.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/base/action/HandlerAction.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/base/adapter/EditTextAdapter.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/base/adapter/ImageViewAdapter.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/base/dialog/BaseDialog.java 1345 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/base/dialog/UIDialog.java 145 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/base/view/BaseActivity.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/base/viewmodel/BaseViewModel.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/http/OkHttpHelper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/http/ResultData.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/http/interceptor/LogInterceptor.java 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/manager/AppManager.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/manager/UserManager.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/utils/RxUtils.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/utils/ScreenSizeUtils.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/java/com/android/app_base/widget/CustomScrollView.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/anim/bottom_in_window.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/anim/bottom_out_window.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/anim/ios_in_window.xml 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/anim/ios_out_window.xml 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/anim/left_in_window.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/anim/left_out_window.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/anim/pop_add_hide.xml 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/anim/pop_add_show.xml 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/anim/popup_down.xml 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/anim/popup_up.xml 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/anim/right_in_window.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/anim/right_out_window.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/anim/scale_in_window.xml 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/anim/scale_out_window.xml 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/anim/top_in_window.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/anim/top_out_window.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/layout/dialog_ui.xml 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw1024dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw1280dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw1365dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw1440dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw240dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw320dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw360dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw384dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw392dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw400dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw410dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw411dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw432dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw480dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw533dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw592dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw600dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw640dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw662dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw720dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw768dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw800dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw811dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw820dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw960dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values-sw961dp/dimens.xml 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values/arrts.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app_base/src/main/res/values/styles.xml 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.idea/dbnavigator.xml
@@ -17,6 +17,12 @@
  <component name="DBNavigator.Project.DatabaseFileManager">
    <open-files />
  </component>
  <component name="DBNavigator.Project.ExecutionManager">
    <retain-sticky-names value="false" />
  </component>
  <component name="DBNavigator.Project.ParserDiagnosticsManager">
    <diagnostics-history />
  </component>
  <component name="DBNavigator.Project.Settings">
    <connections />
    <browser-settings>
.idea/deploymentTargetDropDown.xml
@@ -7,11 +7,11 @@
        <deviceKey>
          <Key>
            <type value="VIRTUAL_DEVICE_PATH" />
            <value value="C:\Users\86175\.android\avd\Pixel_5_API_30.avd" />
            <value value="D:\software\Android\.android\avd\Pixel_API_30.avd" />
          </Key>
        </deviceKey>
      </Target>
    </targetSelectedWithDropDown>
    <timeTargetWasSelectedWithDropDown value="2023-03-21T13:34:06.068432400Z" />
    <timeTargetWasSelectedWithDropDown value="2023-03-27T13:20:06.320581100Z" />
  </component>
</project>
app/src/main/AndroidManifest.xml
@@ -3,7 +3,10 @@
    xmlns:tools="http://schemas.android.com/tools">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <application
        android:name=".MyApplication"
        android:allowBackup="true"
@@ -15,7 +18,7 @@
        android:networkSecurityConfig="@xml/network_security_config"
        android:resizeableActivity="true"
        android:supportsRtl="true"
        android:theme="@style/Theme.Zhangshi_app_android"
        android:theme="@style/Theme.app"
        android:usesCleartextTraffic="true"
        tools:targetApi="31">
        <!-- 沉浸式状态栏全面屏 -->
@@ -28,6 +31,13 @@
        <meta-data
            android:name="notch.config"
            android:value="portrait|landscape" />
        <!-- 屏幕适配 (默认以宽度适配)-->
        <meta-data
            android:name="design_width_in_dp"
            android:value="360"/>
        <meta-data
            android:name="design_height_in_dp"
            android:value="640"/>
        <activity
            android:name=".ui.main.MainActivity"
app/src/main/java/com/application/zhangshi_app_android/MyApplication.java
@@ -4,6 +4,8 @@
import com.hjq.bar.TitleBar;
import com.hjq.bar.style.TransparentBarStyle;
//import me.jessyan.autosize.AutoSizeConfig;
/**
 * @author Ljj
 * @date 2023.03.02. 17:51
app/src/main/java/com/application/zhangshi_app_android/adapter/FamilyMemorabiliaRvAdapter.java
@@ -4,12 +4,23 @@
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.CompoundButton;
import android.widget.FrameLayout;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.android.app_base.base.adapter.BaseRVAdapter;
import com.application.zhangshi_app_android.R;
import com.application.zhangshi_app_android.bean.FamilyMemorabiliaBean;
import com.application.zhangshi_app_android.databinding.ItemFamilyMemorabiliaBinding;
import com.application.zhangshi_app_android.ui.function.FamilyMemorabiliaActivity;
import com.application.zhangshi_app_android.ui.function.FamilyMemorabiliaActivityViewModel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
/**
 * @author Ljj
@@ -17,8 +28,18 @@
 * @desc 家大事记 recyclerView 的 adapter
 */
public class FamilyMemorabiliaRvAdapter extends BaseRVAdapter<FamilyMemorabiliaBean, ItemFamilyMemorabiliaBinding, FamilyMemorabiliaRvAdapter.MyViewHolder> {
    private FamilyMemorabiliaActivityViewModel viewModel;
    private boolean isCheckable;
    public FamilyMemorabiliaRvAdapter(Context context) {
        super(context);
    }
    public FamilyMemorabiliaRvAdapter(Context context, FamilyMemorabiliaActivityViewModel viewModel) {
        super(context);
        this.viewModel = viewModel;
    }
    @Override
@@ -33,10 +54,29 @@
    @Override
    protected void onBind(MyViewHolder holder, int position) {
        holder.getBinding().setBean(mDataList.get(position));
        if (position % 2 != 0){
            holder.getBinding().cardView.setCardBackgroundColor(mContext.getColor(R.color.color_card_blue));
        }else {
            holder.getBinding().cardView.setCardBackgroundColor(mContext.getColor(R.color.color_card_pink));
        }
        if (isCheckable){
            holder.getBinding().checkbox.setVisibility(View.VISIBLE);
            holder.getBinding().checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    List<FamilyMemorabiliaBean> list = new ArrayList<>(Objects.requireNonNull(viewModel.getCheckListLiveData().getValue()));
                    if (isChecked){
                        list.add(mDataList.get(position));
                    }else{
                        list.remove(mDataList.get(position));
                    }
                    viewModel.getCheckListLiveData().postValue(list);
                }
            });
            holder.getBinding().checkbox.setChecked(viewModel.getCheckListLiveData().getValue().contains(mDataList.get(position)));
        }else{
            holder.getBinding().checkbox.setVisibility(View.GONE);
        }
        holder.getBinding().layoutTitle.setOnClickListener(new View.OnClickListener() {
            @Override
@@ -90,6 +130,11 @@
        });
    }
    public void setCheckable(boolean b) {
        isCheckable = b;
        notifyItemRangeChanged(0,getItemCount());
    }
    public static class MyViewHolder extends BaseViewHolder<ItemFamilyMemorabiliaBinding>{
        private boolean isExpended;
@@ -98,5 +143,6 @@
            super(binding);
        }
    }
}
app/src/main/java/com/application/zhangshi_app_android/bean/CaptchaImageBean.java
New file
@@ -0,0 +1,60 @@
package com.application.zhangshi_app_android.bean;
/**
 * @author Ljj
 * @date 2023.03.24. 15:29
 * @desc 登录/注册的验证码图片类
 */
public class CaptchaImageBean {
    /**
     * 图片的base64编码
     */
    private String img;
    /**
     * 验证码的 uuid
     */
    private String uuid;
    /**
     * 验证码图片的值(方便开发阶段使用)
     */
    private String value;
    public CaptchaImageBean(String img, String uuid, String value) {
        this.img = img;
        this.uuid = uuid;
        this.value = value;
    }
    public String getImg() {
        return img;
    }
    public void setImg(String img) {
        this.img = img;
    }
    public String getUuid() {
        return uuid;
    }
    public void setUuid(String uuid) {
        this.uuid = uuid;
    }
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
    @Override
    public String toString() {
        return "CaptchaImageBean{" +
                "img='" + img + '\'' +
                ", uuid='" + uuid + '\'' +
                ", value='" + value + '\'' +
                '}';
    }
}
app/src/main/java/com/application/zhangshi_app_android/bean/FamilyMemorabiliaBean.java
@@ -6,4 +6,32 @@
 * @desc 家大事记 bean 类
 */
public class FamilyMemorabiliaBean {
    private long id;
    private String address;
    private String createTime;
    private String people;
    private String remark;
    private String title;
    private String url;
    public String getAddress() { return address; }
    public void setAddress(String value) { this.address = value; }
    public String getCreateTime() { return createTime; }
    public void setCreateTime(String value) { this.createTime = value; }
    public long getId() { return id; }
    public void setId(long value) { this.id = value; }
    public String getPeople() { return people; }
    public void setPeople(String value) { this.people = value; }
    public String getRemark() { return remark; }
    public void setRemark(String value) { this.remark = value; }
    public String getTitle() { return title; }
    public void setTitle(String value) { this.title = value; }
    public String getUrl() { return url; }
    public void setUrl(String value) { this.url = value; }
}
app/src/main/java/com/application/zhangshi_app_android/bean/FamilyMemorabiliaRequestBean.java
New file
@@ -0,0 +1,73 @@
package com.application.zhangshi_app_android.bean;
/**
 * @author Ljj
 * @date 2023.03.28. 15:57
 * @desc
 */
public class FamilyMemorabiliaRequestBean {
    private String people;
    private String address;
    private String remark;
    private String title;
    private String createTime;
    private int pageNum;
    private int pageSize;
    public String getPeople() {
        return people;
    }
    public void setPeople(String people) {
        this.people = people;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public String getRemark() {
        return remark;
    }
    public void setRemark(String remark) {
        this.remark = remark;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public int getPageNum() {
        return pageNum;
    }
    public void setPageNum(int pageNum) {
        this.pageNum = pageNum;
    }
    public int getPageSize() {
        return pageSize;
    }
    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }
    public String getCreateTime() {
        return createTime;
    }
    public void setCreateTime(String createTime) {
        this.createTime = createTime;
    }
}
app/src/main/java/com/application/zhangshi_app_android/bean/FamilyMemorabiliaResponseBean.java
New file
@@ -0,0 +1,27 @@
package com.application.zhangshi_app_android.bean;
import java.util.List;
/**
 * @author Ljj
 * @date 2023.03.28. 13:52
 * @desc 获取家大事记的返回类
 */
public class FamilyMemorabiliaResponseBean {
    private List<FamilyMemorabiliaBean> data;
    private long pageNum;
    private long pageSize;
    private long total;
    public List<FamilyMemorabiliaBean> getData() { return data; }
    public void setData(List<FamilyMemorabiliaBean> value) { this.data = value; }
    public long getPageNum() { return pageNum; }
    public void setPageNum(long value) { this.pageNum = value; }
    public long getPageSize() { return pageSize; }
    public void setPageSize(long value) { this.pageSize = value; }
    public long getTotal() { return total; }
    public void setTotal(long value) { this.total = value; }
}
app/src/main/java/com/application/zhangshi_app_android/bean/LoginRequestBean.java
New file
@@ -0,0 +1,45 @@
package com.application.zhangshi_app_android.bean;
/**
 * @author Ljj
 * @date 2023.03.25. 19:07
 * @desc 登录参数类
 */
public class LoginRequestBean {
    private String code;
    private String password;
    private String username;
    private String uuid;
    public LoginRequestBean(String username,String password,String code,  String uuid) {
        this.code = code;
        this.password = password;
        this.username = username;
        this.uuid = uuid;
    }
    /**
     * 验证码的值
     */
    public String getCode() { return code; }
    public void setCode(String value) { this.code = value; }
    /**
     * 注册提交的密码
     */
    public String getPassword() { return password; }
    public void setPassword(String value) { this.password = value; }
    /**
     * 注册提交的用户名
     */
    public String getUsername() { return username; }
    public void setUsername(String value) { this.username = value; }
    /**
     * 验证码的UUID,请求后端获取验证码接口后返回
     */
    public String getUuid() { return uuid; }
    public void setUuid(String value) { this.uuid = value; }
}
app/src/main/java/com/application/zhangshi_app_android/bean/LoginResponseBean.java
New file
@@ -0,0 +1,18 @@
package com.application.zhangshi_app_android.bean;
/**
 * @author Ljj
 * @date 2023.03.25. 19:20
 * @desc 获取家大事记的参数类
 */
public class LoginResponseBean {
    private String token;
    public String getToken() {
        return token;
    }
    public void setToken(String token) {
        this.token = token;
    }
}
app/src/main/java/com/application/zhangshi_app_android/config/BaseConfig.java
File was deleted
app/src/main/java/com/application/zhangshi_app_android/data/DataRepository.java
@@ -3,10 +3,20 @@
import androidx.annotation.NonNull;
import com.android.app_base.base.model.BaseModel;
import com.android.app_base.http.ResultData;
import com.application.zhangshi_app_android.bean.CaptchaImageBean;
import com.application.zhangshi_app_android.bean.FamilyMemorabiliaBean;
import com.application.zhangshi_app_android.bean.FamilyMemorabiliaRequestBean;
import com.application.zhangshi_app_android.bean.FamilyMemorabiliaResponseBean;
import com.application.zhangshi_app_android.bean.LoginRequestBean;
import com.application.zhangshi_app_android.bean.LoginResponseBean;
import com.application.zhangshi_app_android.data.source.HttpDataSource;
import com.application.zhangshi_app_android.data.source.LocalDataSource;
import com.application.zhangshi_app_android.data.source.http.HttpDataSourceImpl;
import com.application.zhangshi_app_android.data.source.local.LocalDataSourceImpl;
import java.util.List;
import java.util.Map;
import io.reactivex.Observable;
import io.reactivex.Observer;
@@ -50,7 +60,46 @@
    /**
     * @see HttpDataSourceImpl
     */
    /**
     * 获取验证码图片
     */
    public Observable<ResultData<CaptchaImageBean>> getCaptchaImage(){
        return mHttpDataSource.getCaptchaImage();
    }
    /**
     * 登录
     */
    public Observable<ResultData<LoginResponseBean>> login(LoginRequestBean loginRequestBean){
        return mHttpDataSource.login(loginRequestBean);
    }
    /**
     * 注册
     */
    public Observable<ResultData<String>> register(LoginRequestBean loginRequestBean){
        return mHttpDataSource.register(loginRequestBean);
    }
    /**
     * 获取家大事记
     */
    @Override
    public Observable<ResultData<FamilyMemorabiliaResponseBean>> getFamilyMemorabilia(Map<String, Object> queryMap) {
        return mHttpDataSource.getFamilyMemorabilia(queryMap);
    }
    /**
     * 增加家大事记
     */
    @Override
    public Observable<ResultData<String>> addFamilyMemorabilia(FamilyMemorabiliaBean familyMemorabiliaBean) {
        return mHttpDataSource.addFamilyMemorabilia(familyMemorabiliaBean);
    }
    /**
     * 删除家大事记
     */
    @Override
    public Observable<ResultData<String>> deleteFamilyMemorabilia(String ids) {
        return mHttpDataSource.deleteFamilyMemorabilia(ids);
    }
    /**
     * @see LocalDataSourceImpl
app/src/main/java/com/application/zhangshi_app_android/data/source/HttpDataSource.java
@@ -1,5 +1,16 @@
package com.application.zhangshi_app_android.data.source;
import com.android.app_base.http.ResultData;
import com.application.zhangshi_app_android.bean.CaptchaImageBean;
import com.application.zhangshi_app_android.bean.FamilyMemorabiliaBean;
import com.application.zhangshi_app_android.bean.FamilyMemorabiliaRequestBean;
import com.application.zhangshi_app_android.bean.FamilyMemorabiliaResponseBean;
import com.application.zhangshi_app_android.bean.LoginRequestBean;
import com.application.zhangshi_app_android.bean.LoginResponseBean;
import java.util.List;
import java.util.Map;
import io.reactivex.Observable;
import io.reactivex.Observer;
@@ -9,5 +20,31 @@
 * @desc 网络请求数据源 接口
 */
public interface HttpDataSource {
    /**
     * 获取验证码图片
     */
    Observable<ResultData<CaptchaImageBean>> getCaptchaImage();
    /**
     * 登录
     */
    Observable<ResultData<LoginResponseBean>> login(LoginRequestBean loginRequestBean);
    /**
     * 注册
     */
    Observable<ResultData<String>> register(LoginRequestBean loginRequestBean);
    /**
     * 获取家大事记
     */
    Observable<ResultData<FamilyMemorabiliaResponseBean>> getFamilyMemorabilia(Map<String, Object> queryMap);
    /**
     * 增加家大事记
     */
    Observable<ResultData<String>> addFamilyMemorabilia(FamilyMemorabiliaBean familyMemorabiliaBean);
    /**
     * 删除家大事记
     */
    Observable<ResultData<String>> deleteFamilyMemorabilia(String ids);
}
app/src/main/java/com/application/zhangshi_app_android/data/source/http/ApiService.java
@@ -1,13 +1,24 @@
package com.application.zhangshi_app_android.data.source.http;
import com.android.app_base.http.ResultData;
import com.application.zhangshi_app_android.bean.CaptchaImageBean;
import com.application.zhangshi_app_android.bean.FamilyMemorabiliaBean;
import com.application.zhangshi_app_android.bean.FamilyMemorabiliaRequestBean;
import com.application.zhangshi_app_android.bean.FamilyMemorabiliaResponseBean;
import com.application.zhangshi_app_android.bean.LoginRequestBean;
import com.application.zhangshi_app_android.bean.LoginResponseBean;
import java.util.List;
import java.util.Map;
import io.reactivex.Observable;
import retrofit2.http.FieldMap;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.Body;
import retrofit2.http.DELETE;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Url;
import retrofit2.http.Path;
import retrofit2.http.Query;
import retrofit2.http.QueryMap;
/**
 * @author Ljj
@@ -15,6 +26,38 @@
 * @desc 网络请求 service
 */
public interface ApiService {
    @GET()
    Observable<String> getData(@Url String url);
    /**
     * 获取验证码图片
     */
    @GET("/captchaImage")
    Observable<ResultData<CaptchaImageBean>> getCaptchaImage();
    /**
     * 登录
     */
    @POST("/login")
    Observable<ResultData<LoginResponseBean>> login(@Body LoginRequestBean loginRequestBean);
    /**
     * 注册
     */
    @POST("/register")
    Observable<ResultData<String>> register(@Body LoginRequestBean loginRequestBean);
    /**
     * 获取家大事件
     */
    @GET("family/zfEvent/all")
    Observable<ResultData<FamilyMemorabiliaResponseBean>> getFamilyMemorabilia(@QueryMap Map<String,Object> queryMap);
    /**
     * 增加家大事记
     */
    @POST("/family/zfEvent")
    Observable<ResultData<String>> addFamilyMemorabilia(@Body FamilyMemorabiliaBean familyMemorabiliaBean);
    /**
     * 删除家大事记
     */
    @DELETE("/family/zfEvent/{ids}")
    Observable<ResultData<String>> deleteFamilyMemorabilia(@Path("ids") String ids);
}
app/src/main/java/com/application/zhangshi_app_android/data/source/http/HttpDataSourceImpl.java
@@ -1,17 +1,18 @@
package com.application.zhangshi_app_android.data.source.http;
import androidx.annotation.NonNull;
import com.android.app_base.http.OkHttpHelper;
import com.android.app_base.http.ResultData;
import com.android.app_base.http.RetrofitManager;
import com.application.zhangshi_app_android.config.BaseConfig;
import com.application.zhangshi_app_android.bean.CaptchaImageBean;
import com.application.zhangshi_app_android.bean.FamilyMemorabiliaBean;
import com.application.zhangshi_app_android.bean.FamilyMemorabiliaResponseBean;
import com.application.zhangshi_app_android.bean.LoginRequestBean;
import com.application.zhangshi_app_android.bean.LoginResponseBean;
import com.android.app_base.base.BaseConfig;
import com.application.zhangshi_app_android.data.source.HttpDataSource;
import java.io.IOException;
import java.util.Map;
import io.reactivex.Observable;
import okhttp3.Interceptor;
import okhttp3.Response;
/**
 * @author Ljj
@@ -42,4 +43,49 @@
        INSTANCE = null;
    }
    /**
     * 获取验证码图片
     */
    @Override
    public Observable<ResultData<CaptchaImageBean>> getCaptchaImage() {
        return apiService.getCaptchaImage();
    }
    /**
     * 登录
     * @param loginRequestBean 登录参数
     */
    @Override
    public Observable<ResultData<LoginResponseBean>> login(LoginRequestBean loginRequestBean) {
        return apiService.login(loginRequestBean);
    }
    /**
     * 注册
     */
    @Override
    public Observable<ResultData<String>> register(LoginRequestBean loginRequestBean) {
        return apiService.register(loginRequestBean);
    }
    /**
     * 获取家大事记
     */
    @Override
    public Observable<ResultData<FamilyMemorabiliaResponseBean>> getFamilyMemorabilia(Map<String, Object> queryMap) {
        return apiService.getFamilyMemorabilia(queryMap);
    }
    /**
     * 增加家大事记
     */
    @Override
    public Observable<ResultData<String>> addFamilyMemorabilia(FamilyMemorabiliaBean familyMemorabiliaBean) {
        return apiService.addFamilyMemorabilia(familyMemorabiliaBean);
    }
    /**
     * 删除家大事记
     */
    @Override
    public Observable<ResultData<String>> deleteFamilyMemorabilia(String ids) {
        return apiService.deleteFamilyMemorabilia(ids);
    }
}
app/src/main/java/com/application/zhangshi_app_android/ui/function/FamilyMemorabiliaActivity.java
@@ -1,12 +1,35 @@
package com.application.zhangshi_app_android.ui.function;
import android.content.DialogInterface;
import android.graphics.drawable.ColorDrawable;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.PopupWindow;
import android.widget.TextView;
import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
import androidx.appcompat.app.AlertDialog;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.lifecycle.Observer;
import com.android.app_base.base.dialog.BaseDialog;
import com.android.app_base.base.dialog.UIDialog;
import com.android.app_base.base.view.BaseActivity;
import com.android.app_base.utils.ScreenSizeUtils;
import com.android.app_base.widget.LinearItemDecoration;
import com.application.zhangshi_app_android.BR;
import com.application.zhangshi_app_android.R;
import com.application.zhangshi_app_android.adapter.FamilyMemorabiliaRvAdapter;
import com.application.zhangshi_app_android.bean.FamilyMemorabiliaBean;
import com.application.zhangshi_app_android.databinding.ActivityFamilyMemorabiliaBinding;
import java.util.List;
/**
 * @author Ljj
 * @date 2023.03.18. 10:00
@@ -15,6 +38,10 @@
public class FamilyMemorabiliaActivity extends BaseActivity<ActivityFamilyMemorabiliaBinding,FamilyMemorabiliaActivityViewModel> {
    FamilyMemorabiliaRvAdapter adapter;
    private PopupWindow mOperatePopupWindow;
    private PopupWindow mSearchPopupWindow;
    private int operateType = 0;
    private int searchType = 0;
    @Override
    public int getLayoutId() {
@@ -33,26 +60,179 @@
    @Override
    public void initView() {
        adapter = new FamilyMemorabiliaRvAdapter(this);
        adapter = new FamilyMemorabiliaRvAdapter(this,viewModel);
        LinearItemDecoration itemDecoration = new LinearItemDecoration();
        itemDecoration.setBottomSpace((int) getResources().getDimension(com.android.app_base.R.dimen.dp_12));
        itemDecoration.setHorizontalSpace((int) getResources().getDimension(com.android.app_base.R.dimen.dp_20));
        itemDecoration.setFirstTop((int) getResources().getDimension(com.android.app_base.R.dimen.dp_20));
        binding.recyclerView.addItemDecoration(itemDecoration);
        binding.recyclerView.setAdapter(adapter);
        mOperatePopupWindow = initPopUpWindow(R.layout.pop_operate);
        mOperatePopupWindow.getContentView().findViewById(R.id.tv_add).setOnClickListener(v -> {
            //TODO 跳转 新建
        });
        mOperatePopupWindow.getContentView().findViewById(R.id.tv_select).setOnClickListener(v -> {
            binding.ivOperate.setBackgroundResource(R.drawable.ic_operate_finish);
            operateType = 1;
            adapter.setCheckable(true);
            mOperatePopupWindow.dismiss();
        });
        mOperatePopupWindow.getContentView().findViewById(R.id.tv_from_new_to_old).setOnClickListener(v -> {
            viewModel.changeOrder(true);
            mOperatePopupWindow.dismiss();
        });
        mOperatePopupWindow.getContentView().findViewById(R.id.tv_from_old_to_new).setOnClickListener(v -> {
            viewModel.changeOrder(false);
            mOperatePopupWindow.dismiss();
        });
        binding.ivOperate.setOnClickListener(v -> {
            if (operateType == 0){
                mOperatePopupWindow.showAsDropDown(binding.ivOperate,-ScreenSizeUtils.dip2px(this,85) +binding.ivOperate.getWidth(),0);
            } else if (operateType == 1) {
                binding.ivOperate.setBackgroundResource(R.drawable.ic_operate);
                operateType = 0;
                adapter.setCheckable(false);
            } else {
                new UIDialog.Builder(this)
                        .setTitle("您确定要删除项目吗")
                        .setContent("项目删除后将无法恢复")
                        .setConfirm("确定")
                        .setCancel("取消")
                        .setListener(new UIDialog.OnListener() {
                            @Override
                            public void onConfirm(BaseDialog dialog) {
                                viewModel.delete();
                            }
                        })
                        .show();
            }
        });
        mSearchPopupWindow = initPopUpWindow(R.layout.pop_search);
        binding.ivSearchType.setOnClickListener(v -> {
            mSearchPopupWindow.showAsDropDown(binding.etSearch,0,0);
        });
        binding.ivSearchDefault.setOnClickListener(v -> {
            binding.layoutSearch.setVisibility(View.VISIBLE);
            binding.layoutDefault.setVisibility(View.GONE);
        });
        binding.fabAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            }
        });
        setOnClickListener(
                mSearchPopupWindow.getContentView().findViewById(R.id.tv_global_search),
                mSearchPopupWindow.getContentView().findViewById(R.id.tv_search_in_family_memorabilia),
                mSearchPopupWindow.getContentView().findViewById(R.id.tv_search_by_title),
                mSearchPopupWindow.getContentView().findViewById(R.id.tv_search_by_people),
                mSearchPopupWindow.getContentView().findViewById(R.id.tv_search_by_time),
                mSearchPopupWindow.getContentView().findViewById(R.id.tv_search_by_place));
        binding.etSearch.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if ((actionId == EditorInfo.IME_ACTION_UNSPECIFIED || actionId == EditorInfo.IME_ACTION_SEARCH)
                        && event != null) {
                    viewModel.getFamilyMemorabilia(searchType);
                    hideSoftKeyboard();
                    return true;
                }
                return false;
            }
        });
        binding.drawerLayout.setScrimColor(getResources().getColor(R.color.color_shadow));
    }
    @Override
    public void initData() {
        adapter.addItem(new FamilyMemorabiliaBean());
        adapter.addItem(new FamilyMemorabiliaBean());
        adapter.addItem(new FamilyMemorabiliaBean());
        adapter.addItem(new FamilyMemorabiliaBean());
        adapter.addItem(new FamilyMemorabiliaBean());
        viewModel.getFamilyMemorabilia(0);
    }
    @Override
    public void initLiveDataObserve() {
        viewModel.getCheckListLiveData().observe(this, new Observer<List<FamilyMemorabiliaBean>>() {
            @Override
            public void onChanged(List<FamilyMemorabiliaBean> familyMemorabiliaBeans) {
                if (operateType == 0){
                    return;
                }
                if (familyMemorabiliaBeans.isEmpty()){
                    binding.ivOperate.setBackgroundResource(R.drawable.ic_operate_finish);
                    operateType = 1;
                }else{
                    binding.ivOperate.setBackgroundResource(R.drawable.ic_delete_white);
                    operateType = 2;
                }
            }
        });
        viewModel.getDataListLiveData().observe(this, new Observer<List<FamilyMemorabiliaBean>>() {
            @Override
            public void onChanged(List<FamilyMemorabiliaBean> familyMemorabiliaBeans) {
                adapter.setData(familyMemorabiliaBeans);
            }
        });
    }
    private PopupWindow initPopUpWindow(@LayoutRes int layoutId){
        PopupWindow popupWindow = new PopupWindow(this);
        // 设置布局文件
        popupWindow.setContentView(LayoutInflater.from(this).inflate(layoutId, null));
        // 为了避免部分机型不显示,需要重新设置一下宽高
        popupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
        popupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
        // 设置pop透明效果
        popupWindow.setBackgroundDrawable(new ColorDrawable(0x0000));
        // 设置pop出入动画
        popupWindow.setAnimationStyle(com.android.app_base.R.style.pop_add);
        // 设置pop获取焦点,如果为false点击返回按钮会退出当前Activity,如果pop中有Editor的话,focusable必须要为true
        popupWindow.setFocusable(true);
        // 设置pop可点击,为false点击事件无效,默认为true
        popupWindow.setTouchable(true);
        // 设置点击pop外侧消失,默认为false;在focusable为true时点击外侧始终消失
        popupWindow.setOutsideTouchable(true);
        return popupWindow;
    }
    @Override
    protected void dataNull() {
        super.dataNull();
    }
    @Override
    public void onClick(View v) {
        int id = v.getId();
        if (id == R.id.tv_global_search){
            searchType = 0;
            binding.etSearch.setHint("全局搜索");
            mSearchPopupWindow.dismiss();
        }else if (id == R.id.tv_search_in_family_memorabilia) {
            searchType = 1;
            mSearchPopupWindow.dismiss();
            binding.etSearch.setHint("在“家大事记”内搜索");
        }else if (id == R.id.tv_search_by_title) {
            searchType = 2;
            mSearchPopupWindow.dismiss();
            binding.etSearch.setHint("按“大事记标题”搜索");
        }else if (id == R.id.tv_search_by_people) {
            searchType = 3;
            mSearchPopupWindow.dismiss();
            binding.etSearch.setHint("按“人物”搜索");
        }else if (id == R.id.tv_search_by_time) {
            searchType = 4;
            mSearchPopupWindow.dismiss();
            binding.etSearch.setHint("按“时间”搜索");
        }else if (id == R.id.tv_search_by_place) {
            searchType = 5;
            mSearchPopupWindow.dismiss();
            binding.etSearch.setHint("按“地点”搜索");
        }
    }
}
app/src/main/java/com/application/zhangshi_app_android/ui/function/FamilyMemorabiliaActivityViewModel.java
@@ -1,11 +1,29 @@
package com.application.zhangshi_app_android.ui.function;
import static com.android.app_base.base.BaseConfig.CODE_SUCCESS;
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.MutableLiveData;
import com.android.app_base.base.StateViewEnum;
import com.android.app_base.base.viewmodel.BaseViewModel;
import com.android.app_base.http.ResultData;
import com.android.app_base.utils.RxUtils;
import com.application.zhangshi_app_android.bean.FamilyMemorabiliaBean;
import com.application.zhangshi_app_android.bean.FamilyMemorabiliaResponseBean;
import com.application.zhangshi_app_android.data.DataRepository;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
/**
 * @author Ljj
@@ -14,6 +32,9 @@
 */
public class FamilyMemorabiliaActivityViewModel extends BaseViewModel<DataRepository> {
    private MutableLiveData<List<FamilyMemorabiliaBean>> checkListLiveData;
    private MutableLiveData<List<FamilyMemorabiliaBean>> dataListLiveData;
    private MutableLiveData<String> stringMutableLiveData;
    public FamilyMemorabiliaActivityViewModel(@NonNull Application application) {
        super(application);
    }
@@ -22,4 +43,192 @@
    protected DataRepository initModel() {
        return DataRepository.getInstance();
    }
    /**
     * 获取家大事记
     */
    public void getFamilyMemorabilia(int searchType) {
        Map<String, Object> queryMap = new HashMap<>();
        queryMap.put("pageNum",1);
        queryMap.put("pageSize",20);
        if (searchType == 1){
            queryMap.put("remark",stringMutableLiveData.getValue());
        } else if (searchType == 2) {
            queryMap.put("title",stringMutableLiveData.getValue());
        }else if (searchType == 3) {
            queryMap.put("people",stringMutableLiveData.getValue());
        }
        else if (searchType == 4) {
            queryMap.put("createTime",stringMutableLiveData.getValue());
        }
        else if (searchType == 5) {
            queryMap.put("address",stringMutableLiveData.getValue());
        }
        model.getFamilyMemorabilia(queryMap)
                .compose(RxUtils.schedulersTransformer())
                .subscribe(new Observer<ResultData<FamilyMemorabiliaResponseBean>>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        addSubscribe(d);
                    }
                    @Override
                    public void onNext(ResultData<FamilyMemorabiliaResponseBean> data) {
                        if (data.getCode() == CODE_SUCCESS){
                            if (data.getData().getData().isEmpty()){
                                changeStateView(StateViewEnum.DATA_NULL);
                            }else {
                                dataListLiveData.postValue(data.getData().getData());
                            }
                        }else {
                            messageLiveData.postValue(data.getMsg());
                        }
                    }
                    @Override
                    public void onError(Throwable e) {
                        messageLiveData.postValue(e.getMessage());
                    }
                    @Override
                    public void onComplete() {
                    }
                });
    }
    /**
     * 增加家大事记
     */
    public void add(FamilyMemorabiliaBean bean) {
        model.addFamilyMemorabilia(bean)
                .compose(RxUtils.schedulersTransformer())
                .subscribe(new Observer<ResultData<String>>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        addSubscribe(d);
                    }
                    @Override
                    public void onNext(ResultData<String> stringResultData) {
                        if (stringResultData.getCode() == CODE_SUCCESS){
                            messageLiveData.postValue("添加成功");
                        }else {
                            messageLiveData.postValue(stringResultData.getMsg());
                        }
                    }
                    @Override
                    public void onError(Throwable e) {
                        messageLiveData.postValue(e.getMessage());
                    }
                    @Override
                    public void onComplete() {
                    }
                });
    }
    /**
     * 删除家大事记
     */
    public void delete() {
        List<FamilyMemorabiliaBean> deleteList = getCheckListLiveData().getValue();
        if (deleteList == null){
            return;
        }
        StringBuffer sb = new StringBuffer();
        deleteList.forEach(familyMemorabiliaBean -> sb.append(familyMemorabiliaBean.getId()).append(","));
        sb.deleteCharAt(sb.length()-1);
        System.out.println();
        model.deleteFamilyMemorabilia(sb.toString())
                .compose(RxUtils.schedulersTransformer())
                .subscribe(new Observer<ResultData<String>>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        addSubscribe(d);
                    }
                    @Override
                    public void onNext(ResultData<String> stringResultData) {
                        if (stringResultData.getCode() == CODE_SUCCESS){
                            List<FamilyMemorabiliaBean> list = getDataListLiveData().getValue();
                            if (list != null) {
                                list.removeAll(getCheckListLiveData().getValue());
                            }
                            getDataListLiveData().postValue(list);
                            messageLiveData.postValue("删除成功");
                            getCheckListLiveData().postValue(new ArrayList<>());
                        }else {
                            messageLiveData.postValue(stringResultData.getMsg());
                        }
                    }
                    @Override
                    public void onError(Throwable e) {
                        messageLiveData.postValue(e.getMessage());
                    }
                    @Override
                    public void onComplete() {
                    }
                });
    }
    public MutableLiveData<List<FamilyMemorabiliaBean>> getCheckListLiveData() {
        if (checkListLiveData==null){
            checkListLiveData = new MutableLiveData<>();
            checkListLiveData.postValue(new ArrayList<>());
        }
        if (checkListLiveData.getValue() == null){
            checkListLiveData.postValue(new ArrayList<>());
        }
        return checkListLiveData;
    }
    public void setCheckListLiveData(MutableLiveData<List<FamilyMemorabiliaBean>> checkListLiveData) {
        this.checkListLiveData = checkListLiveData;
    }
    public MutableLiveData<List<FamilyMemorabiliaBean>> getDataListLiveData() {
        if (dataListLiveData == null){
            dataListLiveData = new MutableLiveData<>();
        }
        return dataListLiveData;
    }
    public void setDataListLiveData(MutableLiveData<List<FamilyMemorabiliaBean>> dataListLiveData) {
        this.dataListLiveData = dataListLiveData;
    }
    public MutableLiveData<String> getStringMutableLiveData() {
        if (stringMutableLiveData == null){
            stringMutableLiveData = new MutableLiveData<>();
        }
        return stringMutableLiveData;
    }
    public void setStringMutableLiveData(MutableLiveData<String> stringMutableLiveData) {
        this.stringMutableLiveData = stringMutableLiveData;
    }
    public void changeOrder(boolean b) {
        List<FamilyMemorabiliaBean> dataList = getDataListLiveData().getValue();
        if (dataList == null) return;
        if (b){
            dataList.sort(new Comparator<FamilyMemorabiliaBean>() {
                @Override
                public int compare(FamilyMemorabiliaBean o1, FamilyMemorabiliaBean o2) {
                    return (int) (o1.getId() - o2.getId());
                }
            });
        }else {
            dataList.sort(new Comparator<FamilyMemorabiliaBean>() {
                @Override
                public int compare(FamilyMemorabiliaBean o1, FamilyMemorabiliaBean o2) {
                    return (int) (o2.getId() - o1.getId());
                }
            });
        }
        getDataListLiveData().postValue(dataList);
    }
}
app/src/main/java/com/application/zhangshi_app_android/ui/login/LoginActivity.java
@@ -1,12 +1,15 @@
package com.application.zhangshi_app_android.ui.login;
import static com.android.app_base.base.BaseConfig.EXTRA_TYPE;
import android.content.Intent;
import android.view.View;
import androidx.annotation.NonNull;
import com.android.app_base.base.view.BaseActivity;
import com.android.app_base.manager.AppManager;
import com.android.app_base.utils.ScreenSizeUtils;
import com.android.app_base.manager.UserManager;
import com.application.zhangshi_app_android.BR;
import com.application.zhangshi_app_android.R;
import com.application.zhangshi_app_android.databinding.ActivityLoginBinding;
@@ -19,6 +22,7 @@
 * @desc 登录注册 Activity
 */
public class LoginActivity extends BaseActivity<ActivityLoginBinding,LoginActivityViewModel> {
    private int type;
    @Override
    public int getLayoutId() {
        return R.layout.activity_login;
@@ -31,29 +35,56 @@
    @Override
    public void initParam() {
        System.out.println("token"+UserManager.getInstance().getToken());
        if (!UserManager.getInstance().getToken().isEmpty()){
            AppManager.getAppManager().startActivity(MainActivity.class);
            finish();
        }
        type = getIntent().getIntExtra(EXTRA_TYPE,0);
    }
    @Override
    public void initView() {
       binding.tvLogin.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
               AppManager.getAppManager().startActivity(MainActivity.class);
           }
       });
        if (type == 1){
            binding.tvTitle.setText("张氏APP账号注册");
            binding.layoutPasswordAgain.setVisibility(View.VISIBLE);
            binding.layoutWxLogin.setVisibility(View.GONE);
            binding.tvLogin.setText("注册");
            binding.tvRegister.setText("已有账号,立即登录");
        }
        binding.ivPasswordVisibility.setOnClickListener(v -> {
            viewModel.getPasswordVisibility().postValue(Boolean.FALSE.equals(viewModel.getPasswordVisibility().getValue()));
        });
        binding.ivPasswordAgainVisibility.setOnClickListener(v -> {
            viewModel.getAgainPasswordVisibility().postValue(Boolean.FALSE.equals(viewModel.getAgainPasswordVisibility().getValue()));
        });
        binding.tvLogin.setOnClickListener(view -> {
            if (type == 1){
                viewModel.register();
            }else{
                viewModel.login();
            }
//            AppManager.getAppManager().startActivity(MainActivity.class);
        });
        binding.tvRegister.setOnClickListener(v -> {
            if (type == 1){
                finish();
            }else{
                AppManager.getAppManager().startActivity(new Intent(this, LoginActivity.class).putExtra(EXTRA_TYPE,1));
            }
        });
        binding.ivCaptcha.setOnClickListener(v -> viewModel.getCaptchaImage());
    }
    @Override
    public void initData() {
        viewModel.getCaptchaImage();
    }
    @Override
    public void initLiveDataObserve() {
    }
    @NonNull
    @Override
    protected ImmersionBar createStatusBarConfig() {
app/src/main/java/com/application/zhangshi_app_android/ui/login/LoginActivityViewModel.java
@@ -1,11 +1,30 @@
package com.application.zhangshi_app_android.ui.login;
import static com.android.app_base.base.BaseConfig.CODE_SUCCESS;
import android.app.Application;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.lifecycle.MutableLiveData;
import com.android.app_base.base.StateViewEnum;
import com.android.app_base.base.viewmodel.BaseViewModel;
import com.android.app_base.http.ResultData;
import com.android.app_base.manager.AppManager;
import com.android.app_base.manager.UserManager;
import com.android.app_base.utils.RxUtils;
import com.android.app_base.utils.ToastUtils;
import com.application.zhangshi_app_android.bean.CaptchaImageBean;
import com.application.zhangshi_app_android.bean.LoginRequestBean;
import com.application.zhangshi_app_android.bean.LoginResponseBean;
import com.application.zhangshi_app_android.data.DataRepository;
import com.application.zhangshi_app_android.ui.main.MainActivity;
import java.util.Objects;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
/**
 * @author Ljj
@@ -13,12 +32,198 @@
 * @desc 登录注册ViewModel
 */
public class LoginActivityViewModel extends BaseViewModel<DataRepository> {
    private MutableLiveData<CaptchaImageBean> captchaImageLiveData = new MutableLiveData<>();
    private MutableLiveData<String> username = new MutableLiveData<>();
    private MutableLiveData<String> password = new MutableLiveData<>();
    private MutableLiveData<String> againPassword = new MutableLiveData<>();
    private MutableLiveData<Boolean> passwordVisibility = new MutableLiveData<>();
    private MutableLiveData<Boolean> againPasswordVisibility = new MutableLiveData<>();
    private MutableLiveData<String> value = new MutableLiveData<>();
    public LoginActivityViewModel(@NonNull Application application) {
        super(application);
        passwordVisibility.postValue(true);
        againPasswordVisibility.postValue(true);
    }
    @Override
    protected DataRepository initModel() {
        return DataRepository.getInstance();
    }
    public void getCaptchaImage(){
        model.getCaptchaImage()
                .compose(RxUtils.schedulersTransformer())
                .subscribe(new Observer<ResultData<CaptchaImageBean>>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        addSubscribe(d);
                    }
                    @Override
                    public void onNext(ResultData<CaptchaImageBean> captchaImageBeanResultData) {
                        if (captchaImageBeanResultData.getCode() == CODE_SUCCESS){
                            captchaImageLiveData.postValue(captchaImageBeanResultData.getData());
                        }else {
                            changeStateView(StateViewEnum.DATA_ERROR);
                            messageLiveData.postValue(captchaImageBeanResultData.getMsg());
                        }
                    }
                    @Override
                    public void onError(Throwable e) {
                        messageLiveData.postValue(e.getMessage());
                    }
                    @Override
                    public void onComplete() {
                    }
                });
    }
    public void login(){
        if (TextUtils.isEmpty(username.getValue()) || TextUtils.isEmpty(password.getValue())||TextUtils.isEmpty(password.getValue())){
            ToastUtils.showShort("请输入账号密码");
            return;
        }
        if (TextUtils.isEmpty(value.getValue())){
            ToastUtils.showShort("请输入验证码");
            return;
        }
        if (captchaImageLiveData.getValue() != null){
            model.login(new LoginRequestBean(username.getValue(),password.getValue(),captchaImageLiveData.getValue().getValue(),captchaImageLiveData.getValue().getUuid()))
                    .compose(RxUtils.schedulersTransformer())
                    .subscribe(new Observer<ResultData<LoginResponseBean>>() {
                        @Override
                        public void onSubscribe(Disposable d) {
                            addSubscribe(d);
                        }
                        @Override
                        public void onNext(ResultData<LoginResponseBean> loginResponseBeanResultData) {
                            if (loginResponseBeanResultData.getCode() == CODE_SUCCESS){
                                String token = loginResponseBeanResultData.getData().getToken();
                                UserManager.getInstance().setToken(token);
                                ToastUtils.showShort("登陆成功");
                                AppManager.getAppManager().startActivity(MainActivity.class);
                            }else {
                                changeStateView(StateViewEnum.DATA_ERROR);
                                messageLiveData.postValue(loginResponseBeanResultData.getMsg());
                            }
                        }
                        @Override
                        public void onError(Throwable e) {
                            messageLiveData.postValue(e.getMessage());
                        }
                        @Override
                        public void onComplete() {
                        }
                    });
        }
    }
    public void register(){
        if (TextUtils.isEmpty(username.getValue()) || TextUtils.isEmpty(password.getValue())||TextUtils.isEmpty(password.getValue())){
            ToastUtils.showShort("请输入账号密码");
            return;
        }
        if (TextUtils.isEmpty(value.getValue())){
            ToastUtils.showShort("请输入验证码");
            return;
        }
        if (!Objects.equals(password.getValue(), againPassword.getValue())){
            ToastUtils.showShort("两次密码输入不一致");
            return;
        }
        if (captchaImageLiveData.getValue() != null){
            model.register(new LoginRequestBean(username.getValue(),password.getValue(),captchaImageLiveData.getValue().getValue(),captchaImageLiveData.getValue().getUuid()))
                    .compose(RxUtils.schedulersTransformer())
                    .subscribe(new Observer<ResultData<String>>() {
                        @Override
                        public void onSubscribe(Disposable d) {
                            addSubscribe(d);
                        }
                        @Override
                        public void onNext(ResultData<String> stringResultData) {
                            if (stringResultData.getCode() == CODE_SUCCESS){
                                ToastUtils.showShort("注册成功");
                                AppManager.getAppManager().finishCurrentActivity();
                            }else {
                                changeStateView(StateViewEnum.DATA_ERROR);
                                messageLiveData.postValue(stringResultData.getMsg());
                            }
                        }
                        @Override
                        public void onError(Throwable e) {
                            messageLiveData.postValue(e.getMessage());
                        }
                        @Override
                        public void onComplete() {
                        }
                    });
        }
    }
    public MutableLiveData<CaptchaImageBean> getCaptchaImageLiveData() {
        return captchaImageLiveData;
    }
    public void setCaptchaImageLiveData(MutableLiveData<CaptchaImageBean> captchaImageLiveData) {
        this.captchaImageLiveData = captchaImageLiveData;
    }
    public MutableLiveData<String> getUsername() {
        return username;
    }
    public void setUsername(MutableLiveData<String> username) {
        this.username = username;
    }
    public MutableLiveData<String> getPassword() {
        return password;
    }
    public MutableLiveData<String> getAgainPassword() {
        return againPassword;
    }
    public void setAgainPassword(MutableLiveData<String> againPassword) {
        this.againPassword = againPassword;
    }
    public void setPassword(MutableLiveData<String> password) {
        this.password = password;
    }
    public MutableLiveData<Boolean> getPasswordVisibility() {
        return passwordVisibility;
    }
    public void setPasswordVisibility(MutableLiveData<Boolean> passwordVisibility) {
        this.passwordVisibility = passwordVisibility;
    }
    public MutableLiveData<Boolean> getAgainPasswordVisibility() {
        return againPasswordVisibility;
    }
    public void setAgainPasswordVisibility(MutableLiveData<Boolean> againPasswordVisibility) {
        this.againPasswordVisibility = againPasswordVisibility;
    }
    public MutableLiveData<String> getValue() {
        return value;
    }
    public void setValue(MutableLiveData<String> value) {
        this.value = value;
    }
}
app/src/main/res/drawable-xhdpi/bg_login_home.png

app/src/main/res/drawable-xhdpi/function_family_root_net.png

app/src/main/res/drawable-xhdpi/ic_add.png
app/src/main/res/drawable-xhdpi/ic_checked.png
app/src/main/res/drawable-xhdpi/ic_delete_white.png
app/src/main/res/drawable-xhdpi/ic_operate_add.png
app/src/main/res/drawable-xhdpi/ic_operate_finish.png
app/src/main/res/drawable-xhdpi/ic_operate_order.png
app/src/main/res/drawable-xhdpi/ic_operate_select.png
app/src/main/res/drawable-xhdpi/ic_password_invisible.png

app/src/main/res/drawable-xhdpi/ic_password_visible.png
app/src/main/res/drawable-xhdpi/ic_search_by.png
app/src/main/res/drawable-xhdpi/ic_search_gray.png
app/src/main/res/drawable-xhdpi/ic_vector_gray.png
app/src/main/res/drawable-xhdpi/ic_vector_pink.png
app/src/main/res/drawable-xhdpi/ic_wx_login.png
app/src/main/res/drawable-xxhdpi/bg_login_home.png

app/src/main/res/drawable-xxhdpi/function_family_root_net.png

app/src/main/res/drawable-xxhdpi/ic_add.png
app/src/main/res/drawable-xxhdpi/ic_checked.png
app/src/main/res/drawable-xxhdpi/ic_delete_white.png
app/src/main/res/drawable-xxhdpi/ic_operate_add.png
app/src/main/res/drawable-xxhdpi/ic_operate_finish.png
app/src/main/res/drawable-xxhdpi/ic_operate_order.png
app/src/main/res/drawable-xxhdpi/ic_operate_select.png
app/src/main/res/drawable-xxhdpi/ic_password_invisible.png

app/src/main/res/drawable-xxhdpi/ic_password_visible.png
app/src/main/res/drawable-xxhdpi/ic_search_by.png
app/src/main/res/drawable-xxhdpi/ic_search_gray.png
app/src/main/res/drawable-xxhdpi/ic_vector_gray.png
app/src/main/res/drawable-xxhdpi/ic_vector_pink.png
app/src/main/res/drawable-xxhdpi/ic_wx_login.png
app/src/main/res/drawable/selector_checkbox.xml
New file
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item
        android:state_checked="true"
        android:drawable="@drawable/ic_checked" />
<!--    <item-->
<!--        android:state_checked="false"-->
<!--        android:drawable="@null" />-->
<!--    <item-->
<!--        android:drawable="@null" />&lt;!&ndash; The default one &ndash;&gt;-->
</selector>
app/src/main/res/layout/activity_family_memorabilia.xml
@@ -8,79 +8,752 @@
            name="viewModel"
            type="com.application.zhangshi_app_android.ui.function.FamilyMemorabiliaActivityViewModel"/>
    </data>
    <LinearLayout
    <androidx.drawerlayout.widget.DrawerLayout
        android:id="@+id/drawerLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".ui.function.FamilyMemorabiliaActivity"
        android:orientation="vertical">
        <com.hjq.bar.TitleBar
            android:id="@+id/titleBar"
        tools:openDrawer="start"
        >
        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="@dimen/dp_55"
            app:layout_constraintTop_toTopOf="parent"
            android:background="@color/color_title_bar_background"
            android:paddingHorizontal="@dimen/dp_16"
            app:leftIcon="@null"
            app:rightIcon="@null"
            >
            android:layout_height="match_parent"
            tools:context=".ui.function.FamilyMemorabiliaActivity"
            android:orientation="vertical">
            <com.hjq.bar.TitleBar
                android:id="@+id/titleBar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_constraintTop_toTopOf="parent"
                android:paddingHorizontal="0dp"
                android:background="@color/color_title_bar_background"
                app:leftIcon="@null"
                app:rightIcon="@null"
                >
                <ImageView
                    android:id="@+id/iv_menu"
                    android:layout_width="24dp"
                    android:layout_height="24dp"
                    android:layout_marginHorizontal="16dp"
                    android:background="@drawable/ic_menu"
                    android:layout_gravity="center_vertical"
                    />
                <FrameLayout
                    android:layout_width="24dp"
                    android:layout_height="24dp"
                    android:layout_marginHorizontal="16dp"
                    android:layout_gravity="center_vertical|end"
                    >
                    <ImageView
                        android:id="@+id/iv_operate"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center"
                        android:background="@drawable/ic_operate"
                        />
                </FrameLayout>
                <LinearLayout
                    android:id="@+id/layout_default"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_marginHorizontal="56dp"
                    android:gravity="center_vertical"
                    >
                    <TextView
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_marginStart="16dp"
                        android:text="家大事记"
                        android:layout_weight="1"
                        android:textColor="@color/white"
                        android:textSize="@dimen/sp_20"
                        />
                    <ImageView
                        android:id="@+id/iv_search_default"
                        android:layout_width="@dimen/dp_24"
                        android:layout_height="@dimen/dp_24"
                        android:background="@drawable/ic_search"
                        />
                </LinearLayout>
                <LinearLayout
                    android:id="@+id/layout_search"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_marginVertical="4dp"
                    android:layout_marginHorizontal="56dp"
                    android:gravity="center_vertical"
                    android:background="@color/white"
                    android:paddingHorizontal="5dp"
                    >
                    <ImageView
                        android:layout_width="24dp"
                        android:layout_height="24dp"
                        android:background="@drawable/ic_search_gray"
                        />
                    <EditText
                        android:id="@+id/et_search"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:layout_marginStart="5dp"
                        android:textSize="14sp"
                        android:textColor="#61000000"
                        android:background="@null"
                        android:imeOptions="actionSearch"
                        android:text="@={viewModel.stringMutableLiveData}"
                        android:singleLine="true"
                        android:hint="全局搜索"
                        />
                    <ImageView
                        android:id="@+id/iv_search_type"
                        android:layout_width="24dp"
                        android:layout_height="24dp"
                        android:background="@drawable/ic_search_by"
                        />
                </LinearLayout>
            </com.hjq.bar.TitleBar>
            <LinearLayout
                android:id="@+id/layout_data_null"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="start|center_vertical"
                android:orientation="horizontal" >
                android:orientation="vertical"
                android:gravity="center"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/titleBar">
                <ImageView
                    android:id="@+id/menu"
                    android:layout_width="@dimen/dp_24"
                    android:layout_height="@dimen/dp_24"
                    android:background="@drawable/ic_menu"
                    android:layout_gravity="center"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/img_sakura"
                    />
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="@dimen/dp_32"
                    android:text="家大事记"
                    android:textColor="@color/white"
                    android:textSize="@dimen/sp_20"
                    android:layout_marginTop="18dp"
                    android:text="暂时还没有数据哦~\n点击”+”立即创建"
                    android:textSize="14sp"
                    android:textColor="#73000000"
                    />
            </LinearLayout>
            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="end|center_vertical"
                android:orientation="horizontal" >
            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/recyclerView"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:background="@color/color_normal_background"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/titleBar"
                app:layout_constraintVertical_bias="1.0"
                tools:itemCount="20"
                tools:layout_editor_absoluteX="-81dp"
                tools:listitem="@layout/item_family_memorabilia" />
                <ImageView
                    android:layout_width="@dimen/dp_24"
                    android:layout_height="@dimen/dp_24"
                    android:background="@drawable/ic_search"
                    />
                <ImageView
                    android:layout_width="@dimen/dp_24"
                    android:layout_height="@dimen/dp_24"
                    android:background="@drawable/ic_operate"
                    android:layout_marginStart="@dimen/dp_16"
                    />
            </LinearLayout>
        </com.hjq.bar.TitleBar>
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            <com.google.android.material.floatingactionbutton.FloatingActionButton
                android:id="@+id/fab_add"
                android:layout_width="@dimen/dp_56"
                android:layout_height="@dimen/dp_56"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                android:layout_marginEnd="@dimen/dp_25"
                android:layout_marginBottom="@dimen/dp_44"
                android:src="@drawable/ic_add"
                app:fabCustomSize="@dimen/dp_56"
                />
        </androidx.constraintlayout.widget.ConstraintLayout>
        <androidx.core.widget.NestedScrollView
            android:layout_width="211dp"
            android:layout_height="match_parent"
            android:background="@color/color_normal_background"
            tools:listitem="@layout/item_family_memorabilia"
            tools:itemCount="20"
            />
            android:layout_gravity="start"
            android:background="@color/color_card_pink"
            android:paddingTop="25dp"
            >
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"
                android:paddingHorizontal="12dp"
                >
                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_horizontal"
                    android:layout_marginTop="33dp"
                    android:layout_marginBottom="20dp"
                    android:gravity="center"
                    >
                    <androidx.constraintlayout.utils.widget.ImageFilterView
                        android:layout_width="50dp"
                        android:layout_height="50dp"
                        app:roundPercent="1"
                        android:background="@drawable/img_sakura"
                        />
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="张喵"
                        android:textSize="18sp"
                        android:textColor="@color/black"
                        android:layout_marginStart="16dp"
                        />
                </LinearLayout>
                <androidx.cardview.widget.CardView
                    android:layout_width="match_parent"
                    android:layout_height="400dp"
                    app:cardBackgroundColor="@color/white"
                    app:cardCornerRadius="10dp"
                    app:cardElevation="0dp"
                    >
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:orientation="vertical"
                        android:paddingVertical="8dp"
                        >
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="核心板块"
                            android:textColor="@color/black"
                            android:textSize="12sp"
                            android:layout_marginStart="14dp"
                            />
                        <View
                            android:layout_width="match_parent"
                            android:layout_height="1dp"
                            android:background="#FFF3F3F3"
                            />
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:paddingHorizontal="15dp"
                            android:gravity="center"
                            >
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/function_family_root_net"
                                />
                            <TextView
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:text="家根网"
                                android:textColor="@color/black"
                                android:textSize="14sp"
                                android:layout_marginStart="15dp"
                                />
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/ic_vector_gray"
                                />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:paddingHorizontal="15dp"
                            android:gravity="center"
                            >
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/function_family_root_net"
                                />
                            <TextView
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:text="家大事记"
                                android:textColor="@color/black"
                                android:textSize="14sp"
                                android:layout_marginStart="15dp"
                                />
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/ic_vector_gray"
                                />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:paddingHorizontal="15dp"
                            android:gravity="center"
                            >
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/function_family_root_net"
                                />
                            <TextView
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:text="家庭资产"
                                android:textColor="@color/black"
                                android:textSize="14sp"
                                android:layout_marginStart="15dp"
                                />
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/ic_vector_gray"
                                />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:paddingHorizontal="15dp"
                            android:gravity="center"
                            >
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/function_family_root_net"
                                />
                            <TextView
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:text="家庭设备"
                                android:textColor="@color/black"
                                android:textSize="14sp"
                                android:layout_marginStart="15dp"
                                />
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/ic_vector_gray"
                                />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:paddingHorizontal="15dp"
                            android:gravity="center"
                            >
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/function_family_root_net"
                                />
                            <TextView
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:text="收藏、荣誉"
                                android:textColor="@color/black"
                                android:textSize="14sp"
                                android:layout_marginStart="15dp"
                                />
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/ic_vector_gray"
                                />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:paddingHorizontal="15dp"
                            android:gravity="center"
                            >
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/function_family_root_net"
                                />
                            <TextView
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:text="小医生"
                                android:textColor="@color/black"
                                android:textSize="14sp"
                                android:layout_marginStart="15dp"
                                />
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/ic_vector_gray"
                                />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:paddingHorizontal="15dp"
                            android:gravity="center"
                            >
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/function_family_root_net"
                                />
                            <TextView
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:text="保洁、收纳"
                                android:textColor="@color/black"
                                android:textSize="14sp"
                                android:layout_marginStart="15dp"
                                />
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/ic_vector_gray"
                                />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:paddingHorizontal="15dp"
                            android:gravity="center"
                            >
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/function_family_root_net"
                                />
                            <TextView
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:text="通讯录"
                                android:textColor="@color/black"
                                android:textSize="14sp"
                                android:layout_marginStart="15dp"
                                />
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/ic_vector_gray"
                                />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:paddingHorizontal="15dp"
                            android:gravity="center"
                            >
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/function_family_root_net"
                                />
                            <TextView
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:text="魅宠"
                                android:textColor="@color/black"
                                android:textSize="14sp"
                                android:layout_marginStart="15dp"
                                />
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/ic_vector_gray"
                                />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:paddingHorizontal="15dp"
                            android:gravity="center"
                            >
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/function_family_root_net"
                                />
                            <TextView
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:text="家庭收支台账"
                                android:textColor="@color/black"
                                android:textSize="14sp"
                                android:layout_marginStart="15dp"
                                />
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/ic_vector_gray"
                                />
                        </LinearLayout>
                    </LinearLayout>
    </LinearLayout>
                </androidx.cardview.widget.CardView>
                <androidx.cardview.widget.CardView
                    android:layout_width="match_parent"
                    android:layout_height="240dp"
                    app:cardBackgroundColor="@color/white"
                    app:cardCornerRadius="10dp"
                    app:cardElevation="0dp"
                    android:layout_marginTop="26dp"
                    android:layout_marginBottom="14dp"
                    >
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:orientation="vertical"
                        >
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="个人板块"
                            android:textColor="@color/black"
                            android:textSize="12sp"
                            android:layout_marginVertical="8dp"
                            android:layout_marginStart="14dp"
                            />
                        <View
                            android:layout_width="match_parent"
                            android:layout_height="1dp"
                            android:background="#FFF3F3F3"
                            />
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:paddingHorizontal="15dp"
                            android:gravity="center"
                            >
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/function_family_root_net"
                                />
                            <TextView
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:text="成长经历阅历"
                                android:textColor="@color/black"
                                android:textSize="14sp"
                                android:layout_marginStart="15dp"
                                />
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/ic_vector_gray"
                                />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:paddingHorizontal="15dp"
                            android:gravity="center"
                            >
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/function_family_root_net"
                                />
                            <TextView
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:text="婚姻"
                                android:textColor="@color/black"
                                android:textSize="14sp"
                                android:layout_marginStart="15dp"
                                />
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/ic_vector_gray"
                                />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:paddingHorizontal="15dp"
                            android:gravity="center"
                            >
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/function_family_root_net"
                                />
                            <TextView
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:text="财产"
                                android:textColor="@color/black"
                                android:textSize="14sp"
                                android:layout_marginStart="15dp"
                                />
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/ic_vector_gray"
                                />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:paddingHorizontal="15dp"
                            android:gravity="center"
                            >
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/function_family_root_net"
                                />
                            <TextView
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:text="百年心愿"
                                android:textColor="@color/black"
                                android:textSize="14sp"
                                android:layout_marginStart="15dp"
                                />
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/ic_vector_gray"
                                />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:paddingHorizontal="15dp"
                            android:gravity="center"
                            >
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/function_family_root_net"
                                />
                            <TextView
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:text="旅游"
                                android:textColor="@color/black"
                                android:textSize="14sp"
                                android:layout_marginStart="15dp"
                                />
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/ic_vector_gray"
                                />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:paddingHorizontal="15dp"
                            android:gravity="center"
                            >
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/function_family_root_net"
                                />
                            <TextView
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:text="健康保健"
                                android:textColor="@color/black"
                                android:textSize="14sp"
                                android:layout_marginStart="15dp"
                                />
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/ic_vector_gray"
                                />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:paddingHorizontal="15dp"
                            android:gravity="center"
                            >
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/function_family_root_net"
                                />
                            <TextView
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:text="荣誉、证书奖项"
                                android:textColor="@color/black"
                                android:textSize="14sp"
                                android:layout_marginStart="15dp"
                                />
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/ic_vector_gray"
                                />
                        </LinearLayout>
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="0dp"
                            android:layout_weight="1"
                            android:paddingHorizontal="15dp"
                            android:gravity="center"
                            >
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/function_family_root_net"
                                />
                            <TextView
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:text="隐私"
                                android:textColor="@color/black"
                                android:textSize="14sp"
                                android:layout_marginStart="15dp"
                                />
                            <ImageView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:background="@drawable/ic_vector_gray"
                                />
                        </LinearLayout>
                    </LinearLayout>
                </androidx.cardview.widget.CardView>
            </LinearLayout>
        </androidx.core.widget.NestedScrollView>
    </androidx.drawerlayout.widget.DrawerLayout>
</layout>
app/src/main/res/layout/activity_login.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:app="http://schemas.android.com/apk/res-auto"
<layout xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
@@ -7,38 +8,40 @@
            name="viewModel"
            type="com.application.zhangshi_app_android.ui.login.LoginActivityViewModel" />
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingHorizontal="30dp"
        android:background="@color/color_normal_background"
        >
        <LinearLayout
            android:layout_width="0dp"
        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            android:layout_marginHorizontal="@dimen/dp_30"
            android:orientation="vertical"
            app:layout_constraintTop_toTopOf="parent"
            >
            <ImageView
                android:id="@+id/iv_bg_home"
                android:layout_width="match_parent"
                android:layout_height="@dimen/dp_165"
                android:background="@drawable/bg_login_home"
                />
            <androidx.cardview.widget.CardView
                android:layout_width="match_parent"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:cardCornerRadius="@dimen/dp_15"
                android:layout_marginTop="-15dp"
                android:background="@drawable/bg_login_home"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
            <androidx.cardview.widget.CardView
                android:id="@+id/cardView"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginTop="-20dp"
                app:cardCornerRadius="15dp"
                app:cardElevation="0dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="@+id/iv_bg_home"
                app:layout_constraintStart_toStartOf="@+id/iv_bg_home"
                app:layout_constraintTop_toBottomOf="@+id/iv_bg_home"
                >
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/iv_bg_home">
                <RelativeLayout
                    android:layout_width="match_parent"
@@ -48,151 +51,198 @@
                        android:id="@+id/iv_bg_zhang"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginTop="@dimen/dp_20"
                        android:background="@drawable/bg_login_zhang"
                        android:layout_centerHorizontal="true"
                        />
                        android:layout_marginTop="18dp"
                        android:background="@drawable/bg_login_zhang" />
                    <TextView
                        android:id="@+id/tv_welcome"
                        android:id="@+id/tv_title"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginHorizontal="@dimen/dp_25"
                        android:layout_centerHorizontal="true"
                        android:layout_marginTop="15dp"
                        android:text="欢迎来到张氏APP"
                        android:textColor="@color/black"
                        android:textSize="@dimen/sp_20"
                        android:textStyle="bold"
                        android:layout_centerHorizontal="true"
                        android:layout_marginVertical="@dimen/dp_20"
                        />
                        android:textSize="20sp"
                        android:textStyle="bold" />
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginHorizontal="@dimen/dp_27"
                        android:orientation="vertical"
                        android:layout_below="@id/tv_welcome"
                        >
                        android:layout_below="@id/tv_title"
                        android:layout_marginHorizontal="27dp"
                        android:orientation="vertical">
                        <TextView
                            android:id="@+id/tv_account"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="10dp"
                            android:text="账号"
                            android:textColor="#FF484848"
                            android:textSize="@dimen/sp_12"
                            />
                            android:textSize="12sp" />
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="@dimen/dp_10"
                            android:background="@drawable/shape_ffd9d9d9_8_stroke"
                            android:paddingVertical="@dimen/dp_12"
                            >
                            android:layout_height="40dp"
                            android:layout_marginTop="7dp"
                            android:background="@drawable/shape_ffd9d9d9_8_stroke">
                            <EditText
                                android:layout_width="match_parent"
                                android:layout_height="wrap_content"
                                android:layout_gravity="center"
                                android:layout_marginStart="@dimen/dp_16"
                                android:layout_marginStart="16dp"
                                android:background="@null"
                                android:hint="请输入账号"
                                android:inputType="text"
                                android:text="@={viewModel.username}"
                                android:textColor="#FF093878"
                                android:textSize="@dimen/sp_16"
                                android:textColorHint="#FF8F9090"
                                />
                                android:textSize="14sp" />
                        </LinearLayout>
                        <TextView
                            android:id="@+id/tv_password"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="@dimen/dp_20"
                            android:layout_marginTop="20dp"
                            android:text="密码"
                            android:textColor="#FF484848"
                            android:textSize="@dimen/sp_12"
                            />
                            android:textSize="12sp" />
                        <LinearLayout
                            android:id="@+id/layout_password"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="@dimen/dp_7"
                            android:paddingVertical="@dimen/dp_12"
                            android:layout_height="40dp"
                            android:layout_marginTop="2dp"
                            android:background="@drawable/shape_ffd9d9d9_8_stroke"
                            android:gravity="center"
                            android:orientation="horizontal">
                            <EditText
                                android:id="@+id/et_password"
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_marginStart="16dp"
                                android:layout_weight="1"
                                android:background="@null"
                                android:hint="请输入密码"
                                android:inputType="textPassword"
                                android:text="@={viewModel.password}"
                                android:textColor="#FF093878"
                                android:textColorHint="#FF8F9090"
                                android:textSize="14sp"
                                app:passwordVisibility="@{viewModel.passwordVisibility}" />
                            <ImageView
                                android:id="@+id/iv_password_visibility"
                                android:layout_width="16dp"
                                android:layout_height="20dp"
                                android:layout_marginEnd="12sp"
                                android:background="@{viewModel.passwordVisibility?@drawable/ic_password_visible:@drawable/ic_password_invisible}" />
                        </LinearLayout>
                        <LinearLayout
                            android:id="@+id/layout_password_again"
                            android:layout_width="match_parent"
                            android:layout_height="40dp"
                            android:layout_marginTop="2dp"
                            android:background="@drawable/shape_ffd9d9d9_8_stroke"
                            android:gravity="center"
                            android:orientation="horizontal"
                            >
                            android:visibility="gone">
                            <EditText
                                android:id="@+id/et_password_again"
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_marginStart="@dimen/dp_16"
                                android:layout_marginStart="16dp"
                                android:layout_weight="1"
                                android:background="@null"
                                android:hint="请再次输入密码"
                                android:inputType="textPassword"
                                android:text="@={viewModel.againPassword}"
                                android:textColor="#FF093878"
                                android:textSize="@dimen/sp_16"
                                android:hint="请输入账号"
                                android:textColorHint="#FF8F9090"
                                />
                                android:textSize="14sp"
                                app:passwordVisibility="@{viewModel.againPasswordVisibility}" />
                            <ImageView
                                android:layout_width="@dimen/dp_16"
                                android:layout_height="@dimen/dp_20"
                                android:layout_marginEnd="@dimen/dp_12"
                                android:background="@drawable/ic_password_invisable" />
                                android:id="@+id/iv_password_again_visibility"
                                android:layout_width="16dp"
                                android:layout_height="20dp"
                                android:layout_marginEnd="12sp"
                                android:background="@{viewModel.againPasswordVisibility?@drawable/ic_password_visible:@drawable/ic_password_invisible}" />
                            />
                        </LinearLayout>
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="20dp"
                            android:text="验证码"
                            android:textColor="#FF484848"
                            android:textSize="@dimen/sp_12"
                            android:layout_marginTop="@dimen/dp_20"
                            />
                            android:textSize="12sp" />
                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:orientation="horizontal"
                            android:layout_marginTop="@dimen/dp_10"
                            >
                            android:layout_marginTop="2dp"
                            android:orientation="horizontal">
                            <LinearLayout
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:background="@drawable/shape_ffd9d9d9_8_stroke"
                                android:paddingVertical="@dimen/dp_12"
                                android:layout_height="40dp"
                                android:layout_weight="6"
                                >
                                android:background="@drawable/shape_ffd9d9d9_8_stroke">
                                <EditText
                                    android:layout_width="match_parent"
                                    android:layout_height="wrap_content"
                                    android:layout_gravity="center"
                                    android:layout_marginStart="@dimen/dp_16"
                                    android:layout_marginStart="16dp"
                                    android:background="@null"
                                    android:hint="请输入验证码"
                                    android:inputType="number"
                                    android:text="@={viewModel.value}"
                                    android:textColor="#FF093878"
                                    android:textSize="@dimen/sp_16"
                                    android:textColorHint="#FF8F9090"
                                    />
                                    android:textSize="14sp" />
                            </LinearLayout>
                            <ImageView
                                android:id="@+id/iv_captcha"
                                android:layout_width="0dp"
                                android:layout_height="match_parent"
                                android:layout_marginStart="6dp"
                                android:layout_weight="4"
                                android:layout_marginStart="@dimen/dp_6"
                                />
                                app:imageBase64="@{viewModel.captchaImageLiveData.img}" />
                        </LinearLayout>
                        <TextView
                            android:id="@+id/tv_login"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:background="@drawable/shape_ff093878_10_solid"
                            android:text="注册/登录"
                            android:textColor="@color/white"
                            android:gravity="center"
                            android:paddingVertical="@dimen/dp_10"
                            android:paddingHorizontal="@dimen/dp_77"
                            android:textSize="@dimen/sp_12"
                            android:layout_marginVertical="@dimen/dp_27"
                            android:layout_height="35dp"
                            android:layout_gravity="center"
                            />
                            android:layout_marginTop="20dp"
                            android:background="@drawable/shape_ff093878_10_solid"
                            android:gravity="center"
                            android:paddingHorizontal="91dp"
                            android:text="登录"
                            android:textColor="@color/white"
                            android:textSize="12sp" />
                        <TextView
                            android:id="@+id/tv_register"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_gravity="center"
                            android:layout_marginVertical="10dp"
                            android:gravity="center"
                            android:text="立即注册"
                            android:textColor="#FF37AADB"
                            android:textSize="10sp" />
                    </LinearLayout>
@@ -200,9 +250,50 @@
                </RelativeLayout>
            </androidx.cardview.widget.CardView>
        </LinearLayout>
            <LinearLayout
                android:id="@+id/layout_wx_login"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center_horizontal"
                android:orientation="vertical"
                app:layout_constraintTop_toBottomOf="@+id/cardView">
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginVertical="7dp"
                    android:gravity="center_vertical">
                    <View
                        android:layout_width="0dp"
                        android:layout_height="0.2dp"
                        android:layout_weight="1"
                        android:background="#80000000" />
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginHorizontal="18dp"
                        android:text="第三方登录"
                        android:textColor="#80000000"
                        android:textSize="10sp" />
                    <View
                        android:layout_width="0dp"
                        android:layout_height="0.2dp"
                        android:layout_weight="1"
                        android:background="#80000000" />
                </LinearLayout>
                <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@drawable/ic_wx_login" />
            </LinearLayout>
        </androidx.constraintlayout.widget.ConstraintLayout>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
app/src/main/res/layout/fragment_function.xml
@@ -16,10 +16,11 @@
        android:orientation="vertical"
        >
        <com.hjq.bar.TitleBar
            android:id="@+id/titleBar"
            android:layout_width="match_parent"
            android:layout_height="@dimen/dp_55"
            android:layout_height="wrap_content"
            android:background="@color/color_title_bar_background"
            android:paddingHorizontal="@dimen/dp_16"
            app:layout_constraintEnd_toEndOf="parent"
@@ -148,8 +149,8 @@
                        app:layout_constraintTop_toBottomOf="@id/tv_core_module">
                        <ImageView
                            android:layout_width="@dimen/dp_24"
                            android:layout_height="@dimen/dp_24"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:background="@drawable/function_family_root_net" />
                        <TextView
app/src/main/res/layout/item_family_memorabilia.xml
@@ -15,7 +15,7 @@
        <androidx.cardview.widget.CardView
            android:id="@+id/cardView"
            android:layout_width="match_parent"
            android:layout_height="@dimen/dp_40"
            android:layout_height="40dp"
            android:layout_margin="@dimen/dp_2"
            app:cardCornerRadius="@dimen/dp_10"
            app:cardBackgroundColor="@color/color_card_pink"
@@ -24,39 +24,51 @@
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:paddingHorizontal="@dimen/dp_24"
                >
                <LinearLayout
                <RelativeLayout
                    android:id="@+id/layout_title"
                    android:layout_width="match_parent"
                    android:layout_height="@dimen/dp_40"
                    android:gravity="center_vertical"
                    >
                    <CheckBox
                        android:id="@+id/checkbox"
                        android:layout_width="18dp"
                        android:layout_height="18dp"
                        android:layout_marginStart="3dp"
                        android:layout_centerVertical="true"
                        android:button="@drawable/selector_checkbox"
                        android:background="?selectableItemBackgroundBorderless"
                        />
                    <TextView
                        android:layout_width="0dp"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_centerVertical="true"
                        android:layout_marginStart="24dp"
                        android:textSize="@dimen/sp_16"
                        android:textColor="@color/black"
                        android:text="张氏app立项"
                        android:text="@{bean.title}"
                        android:layout_weight="1"
                        android:textStyle="bold"
                        />
                    <TextView
                        android:layout_width="0dp"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:textSize="@dimen/sp_16"
                        android:textColor="@color/black"
                        android:text="2023.3.1"
                        android:text="@{bean.createTime}"
                        android:textStyle="bold"
                        android:gravity="end"
                        android:layout_marginEnd="24dp"
                        android:layout_alignParentEnd="true"
                        android:layout_centerVertical="true"
                        />
                </LinearLayout>
                </RelativeLayout>
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical"
                    android:paddingHorizontal="@dimen/dp_24"
                    >
                    <LinearLayout
                        android:layout_width="match_parent"
@@ -75,7 +87,7 @@
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="01"
                            android:text="@{String.valueOf(bean.id)}"
                            android:textColor="@color/black"
                            android:textSize="@dimen/sp_12"
                            android:textStyle="bold"
@@ -98,7 +110,7 @@
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="张三、李四、张四、李三"
                            android:text="@{bean.people}"
                            android:textColor="@color/black"
                            android:textSize="@dimen/sp_12"
                            android:textStyle="bold"
@@ -121,7 +133,7 @@
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="项目立项"
                            android:text="@{bean.remark}"
                            android:textColor="@color/black"
                            android:textSize="@dimen/sp_12"
                            android:textStyle="bold"
app/src/main/res/layout/item_menu_family_root_net.xml
New file
@@ -0,0 +1,38 @@
<?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="wrap_content">
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="13dp"
        android:layout_height="10dp"
        android:layout_marginStart="15dp"
        android:background="@drawable/function_family_root_net"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="家根网"
        android:textColor="@color/black"
        android:textSize="10sp"
        android:layout_marginStart="15dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@+id/imageView"
        app:layout_constraintTop_toTopOf="parent" />
    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="15dp"
        android:layout_height="15dp"
        android:background="@drawable/ic_delete"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginEnd="18dp"
        />
</androidx.constraintlayout.widget.ConstraintLayout>
app/src/main/res/layout/pop_operate.xml
New file
@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:cardBackgroundColor="#FFFAD1E0"
    app:cardCornerRadius="10dp"
    app:cardElevation="0dp"
    >
    <LinearLayout
        android:layout_width="85dp"
        android:layout_height="122dp"
        android:orientation="vertical"
        android:gravity="center_horizontal"
        >
        <TextView
            android:id="@+id/tv_add"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="新建"
            android:textColor="#FF333333"
            android:textSize="12sp"
            app:drawableStartCompat="@drawable/ic_operate_add"
            android:drawablePadding="5dp"
            android:layout_weight="1"
            />
        <View
            android:layout_width="match_parent"
            android:layout_height="0.3dp"
            android:background="#FF939393"
            />
        <TextView
            android:id="@+id/tv_select"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="选择"
            android:gravity="center"
            android:textColor="#FF333333"
            android:textSize="12sp"
            app:drawableStartCompat="@drawable/ic_operate_select"
            android:drawablePadding="5dp"
            android:layout_weight="1"
            />
        <View
            android:layout_width="match_parent"
            android:layout_height="0.3dp"
            android:background="#FF939393"
            />
        <TextView
            android:id="@+id/tv_from_new_to_old"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="由新到旧"
            android:gravity="center"
            android:textColor="#FF333333"
            android:textSize="12sp"
            app:drawableStartCompat="@drawable/ic_operate_order"
            android:drawablePadding="5dp"
            android:layout_weight="1"
            />
        <View
            android:layout_width="match_parent"
            android:layout_height="0.3dp"
            android:background="#FF939393"
            />
        <TextView
            android:id="@+id/tv_from_old_to_new"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="由旧到新"
            android:gravity="center"
            android:textColor="#FF333333"
            android:textSize="12sp"
            app:drawableStartCompat="@drawable/ic_operate_order"
            android:drawablePadding="5dp"
            android:layout_weight="1"
            />
    </LinearLayout>
</androidx.cardview.widget.CardView>
app/src/main/res/layout/pop_search.xml
New file
@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:cardBackgroundColor="#FFFAD1E0"
    app:cardCornerRadius="10dp"
    app:cardElevation="0dp"
    >
    <LinearLayout
        android:layout_width="200dp"
        android:layout_height="180dp"
        android:orientation="vertical"
        android:gravity="center_horizontal"
        >
        <TextView
            android:id="@+id/tv_global_search"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:gravity="center"
            android:text="全局搜索"
            android:textColor="#FF333333"
            android:textSize="12sp"
            android:layout_weight="1"
            />
        <View
            android:layout_width="match_parent"
            android:layout_height="0.3dp"
            android:background="#FF939393"
            />
        <TextView
            android:id="@+id/tv_search_in_family_memorabilia"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:gravity="center"
            android:text="在“家大事记”内搜索"
            android:textColor="#FF333333"
            android:textSize="12sp"
            android:layout_weight="1"
            />
        <View
            android:layout_width="match_parent"
            android:layout_height="0.3dp"
            android:background="#FF939393"
            />
        <TextView
            android:id="@+id/tv_search_by_title"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="按“大事记标题”搜索"
            android:textColor="#FF333333"
            android:textSize="12sp" />
        <View
            android:layout_width="match_parent"
            android:layout_height="0.3dp"
            android:background="#FF939393"
            />
        <TextView
            android:id="@+id/tv_search_by_people"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:gravity="center"
            android:text="按“人物”搜索"
            android:textColor="#FF333333"
            android:textSize="12sp"
            android:layout_weight="1"
            />
        <View
            android:layout_width="match_parent"
            android:layout_height="0.3dp"
            android:background="#FF939393"
            />
        <TextView
            android:id="@+id/tv_search_by_time"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:gravity="center"
            android:text="按“时间”搜索"
            android:textColor="#FF333333"
            android:textSize="12sp" />
        <View
            android:layout_width="match_parent"
            android:layout_height="0.3dp"
            android:background="#FF939393"
            />
        <TextView
            android:id="@+id/tv_search_by_place"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:gravity="center"
            android:text="按“地点”搜索"
            android:textColor="#FF333333"
            android:textSize="12sp"
            android:layout_weight="1"
            />
    </LinearLayout>
</androidx.cardview.widget.CardView>
app/src/main/res/values/colors.xml
@@ -8,11 +8,21 @@
    <color name="black">#FF000000</color>
    <color name="white">#FFFFFFFF</color>
    <!-- App 样式中引用的颜色 -->
    <color name="colorPrimary">@color/color_main</color>
    <color name="colorPrimaryDark">@color/black</color>
    <color name="colorAccent">#FFF08EBA</color>
    <color name="windowBackground">#F4F4F4</color>
    <color name="transparent">#00000000</color>
    <color name="color_main">#FFF08EBA</color>
    <color name="color_normal_background">#FFFEF7FC</color>
    <color name="color_title_bar_background">#FFF08EBA</color>
    <color name="color_FFF08EBA_text_pink">#FFF08EBA</color>
    <color name="color_FF666666_text_default">#FF666666</color>
    <color name="color_card_pink">#FFFFE2EF</color>
    <color name="color_card_blue">#FFE0EEFE</color>
    <color name="color_shadow">#88666666</color>
</resources>
app/src/main/res/values/strings.xml
@@ -1,5 +1,5 @@
<resources>
    <string name="app_name">zhangshi_app_android</string>
    <string name="app_name">张氏APP</string>
    <string name="title_home">首页</string>
    <string name="title_function">功能</string>
app/src/main/res/values/themes.xml
@@ -13,4 +13,31 @@
        <item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
        <!-- Customize your theme here. -->
    </style>
    <style name="Theme.app" parent="Theme.AppCompat.DayNight.NoActionBar">
        <!-- 窗口背景颜色 -->
        <item name="android:windowBackground">@color/windowBackground</item>
        <!-- 应用的主要色调,ActionBar Toolbar 默认使用该颜色 -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <!-- 应用的主要暗色调,状态栏默认使用该颜色 -->
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <!-- 应用的强调色,CheckBox RadioButton Switch 等一般控件的选中效果默认采用该颜色 -->
        <item name="colorAccent">@color/colorAccent</item>
        <!-- 默认文本颜色,Button、TextView 的文字颜色-->
<!--        <item name="android:textColor">@color/textColor</item>-->
        <!-- 默认提示颜色,Button、TextView 的提示文字颜色 -->
<!--        <item name="android:textColorHint">@color/textColorHint</item>-->
        <!-- ActionMode 覆盖 Actionbar 不被顶下来 -->
        <item name="windowActionModeOverlay">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <!-- ActionMode 的颜色 -->
        <item name="actionModeBackground">@color/colorPrimary</item>
        <!-- 解决 Android 5.1 及以上版本 Button 英文字符串自动变大写的问题 -->
        <item name="android:textAllCaps">false</item>
        <!-- 默认隐藏输入法,开启这个选项后会导致输入对话框在关闭之后不能关闭软键盘   -->
        <!--<item name="android:windowSoftInputMode">stateHidden</item>-->
        <!-- 关闭 RecyclerView ScrollView ViewPager 水波纹效果 -->
        <item name="android:overScrollMode">never</item>
    </style>
</resources>
app_base/build.gradle
@@ -58,12 +58,16 @@
    // 标题栏框架:https://github.com/getActivity/TitleBar
    api 'com.github.getActivity:TitleBar:10.0'
    // 屏幕适配
    api 'com.github.JessYanCoding:AndroidAutoSize:v1.2.1'
    // 基础依赖包,必须要依赖
    api 'com.geyifeng.immersionbar:immersionbar:3.2.2'
    // kotlin扩展(可选)
//    implementation 'com.geyifeng.immersionbar:immersionbar-ktx:3.2.2'
    //图片相关
    api 'com.github.bumptech.glide:glide:4.11.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
    //内存泄露工具
    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
app_base/src/main/java/com/android/app_base/base/BaseApplication.java
@@ -7,6 +7,7 @@
import androidx.annotation.NonNull;
import com.android.app_base.manager.AppManager;
import com.blankj.utilcode.util.Utils;
/**
 *  Application基类
@@ -18,6 +19,7 @@
    public void onCreate() {
        super.onCreate();
        setApplication(this);
        Utils.init(this);
    }
    /**
app_base/src/main/java/com/android/app_base/base/BaseConfig.java
New file
@@ -0,0 +1,16 @@
package com.android.app_base.base;
/**
 * @author Ljj
 * @date 2023.03.02. 15:33
 * @desc
 */
public class BaseConfig {
    public final static String BASE_URL = "http://47.93.189.255:8080";
    public final static int CODE_SUCCESS = 200;
    public static final int TOKEN_INVALID = 401;//token超时或失效
    //页面跳转
    public static final String EXTRA_TYPE = "type";
    public static final String LOGIN_ACTIVITY = "com.application.zhangshi_app_android.ui.login.LoginActivity";
}
app_base/src/main/java/com/android/app_base/base/action/ActivityAction.java
New file
@@ -0,0 +1,55 @@
package com.android.app_base.base.action;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
/**
 * Activity 相关意图
 */
public interface ActivityAction {
    /**
     * 获取 Context
     */
    Context getContext();
    /**
     * 获取 Activity
     */
    default Activity getActivity() {
        Context context = getContext();
        do {
            if (context instanceof Activity) {
                return (Activity) context;
            } else if (context instanceof ContextWrapper) {
                context = ((ContextWrapper) context).getBaseContext();
            } else {
                return null;
            }
        } while (context != null);
        return null;
    }
    /**
     * 启动一个 Activity(简化版)
     */
    default void startActivity(Class<? extends Activity> clazz) {
        startActivity(new Intent(getContext(), clazz));
    }
    /**
     * 启动一个 Activity
     */
    default void startActivity(Intent intent) {
        if (!(getContext() instanceof Activity)) {
            // 如果当前的上下文不是 Activity,调用 startActivity 必须加入新任务栈的标记
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        getContext().startActivity(intent);
    }
}
app_base/src/main/java/com/android/app_base/base/action/AnimAction.java
New file
@@ -0,0 +1,38 @@
package com.android.app_base.base.action;
import com.android.app_base.R;
/**
 * 动画样式
 */
public interface AnimAction {
    /** 默认动画效果 */
    int ANIM_DEFAULT = -1;
    /** 没有动画效果 */
    int ANIM_EMPTY = 0;
    /** 缩放动画 */
    int ANIM_SCALE = R.style.ScaleAnimStyle;
    /** IOS 动画 */
    int ANIM_IOS = R.style.IOSAnimStyle;
    /** 吐司动画 */
    int ANIM_TOAST = android.R.style.Animation_Toast;
    /** 顶部弹出动画 */
    int ANIM_TOP = R.style.TopAnimStyle;
    /** 底部弹出动画 */
    int ANIM_BOTTOM = R.style.BottomAnimStyle;
    /** 左边弹出动画 */
    int ANIM_LEFT = R.style.LeftAnimStyle;
    /** 右边弹出动画 */
    int ANIM_RIGHT = R.style.RightAnimStyle;
}
app_base/src/main/java/com/android/app_base/base/action/ClickAction.java
New file
@@ -0,0 +1,31 @@
package com.android.app_base.base.action;
import android.view.View;
import androidx.annotation.IdRes;
/**
 * 点击行为意图
 */
public interface ClickAction extends View.OnClickListener {
    <V extends View> V findViewById(@IdRes int id);
    @Override
    default void onClick(View v) {
        // 默认不实现,让子类实现
    }
    default void setOnClickListener(@IdRes int... ids) {
        for (int id : ids) {
            findViewById(id).setOnClickListener(this);
        }
    }
    default void setOnClickListener(View... views) {
        for (View view : views) {
            view.setOnClickListener(this);
        }
    }
}
app_base/src/main/java/com/android/app_base/base/action/HandlerAction.java
New file
@@ -0,0 +1,60 @@
package com.android.app_base.base.action;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
/**
 * 统一处理handler
 */
public interface HandlerAction {
    Handler HANDLER = new Handler(Looper.getMainLooper());
    /**
     * 获取 Handler
     */
    default Handler getHandler() {
        return HANDLER;
    }
    /**
     * 延迟执行
     */
    default boolean post(Runnable r) {
        return postDelayed(r, 0);
    }
    /**
     * 延迟一段时间执行
     */
    default boolean postDelayed(Runnable r, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return postAtTime(r, SystemClock.uptimeMillis() + delayMillis);
    }
    /**
     * 在指定的时间执行
     */
    default boolean postAtTime(Runnable r, long uptimeMillis) {
        // 发送和这个 Activity 相关的消息回调
        return HANDLER.postAtTime(r, this, uptimeMillis);
    }
    /**
     * 移除单个消息回调
     */
    default void removeCallbacks(Runnable r) {
        HANDLER.removeCallbacks(r);
    }
    /**
     * 移除全部消息回调
     */
    default void removeCallbacks() {
        HANDLER.removeCallbacksAndMessages(this);
    }
}
app_base/src/main/java/com/android/app_base/base/adapter/EditTextAdapter.java
New file
@@ -0,0 +1,25 @@
package com.android.app_base.base.adapter;
import android.text.method.HideReturnsTransformationMethod;
import android.text.method.PasswordTransformationMethod;
import android.widget.EditText;
import android.widget.ImageView;
import androidx.databinding.BindingAdapter;
/**
 * @author Ljj
 * @date 2023.03.26. 17:38
 * @desc
 */
public class EditTextAdapter {
    @BindingAdapter({"passwordVisibility"})
    public static void setPasswordVisibility(EditText editText, boolean visibility) {
        if(visibility){
            editText.setTransformationMethod(PasswordTransformationMethod.getInstance());
        }else {
            editText.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
        }
        editText.setSelection(editText.length());
    }
}
app_base/src/main/java/com/android/app_base/base/adapter/ImageViewAdapter.java
New file
@@ -0,0 +1,32 @@
package com.android.app_base.base.adapter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Base64;
import android.widget.ImageView;
import androidx.databinding.BindingAdapter;
/**
 * @author Ljj
 * @date 2023.03.24. 17:09
 * @desc ImageView的 BindingAdapter
 */
public class ImageViewAdapter {
    @BindingAdapter({"imageUrl"})
    public static void loadImage(ImageView imageView, String url) {
    }
    @BindingAdapter({"imageBase64"})
    public static void setBase64Image(ImageView imageView, String imageString) {
        if (imageString == null){
            return;
        }
        if (imageString.contains(",")){
            imageString = imageString.split(",")[1];
        }
        byte[] decodedString = Base64.decode(imageString, Base64.DEFAULT);
        Bitmap bitmap = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
        imageView.setImageBitmap(bitmap);
    }
}
app_base/src/main/java/com/android/app_base/base/dialog/BaseDialog.java
New file
@@ -0,0 +1,1345 @@
package com.android.app_base.base.dialog;
import static com.blankj.utilcode.util.StringUtils.getString;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.util.SparseArray;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.FloatRange;
import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.annotation.StyleRes;
import androidx.appcompat.app.AppCompatDialog;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
import com.android.app_base.R;
import com.android.app_base.base.BaseApplication;
import com.android.app_base.base.action.ActivityAction;
import com.android.app_base.base.action.AnimAction;
import com.android.app_base.base.action.ClickAction;
import com.android.app_base.base.action.HandlerAction;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.List;
/**
 * 基类dialog
 */
public class BaseDialog extends AppCompatDialog implements LifecycleOwner,
        ActivityAction, AnimAction, HandlerAction, ClickAction,DialogInterface.OnShowListener,
        DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {
    private final ListenersWrapper<BaseDialog> mListeners = new ListenersWrapper<>(this);
    private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
    private List<OnShowListener> mShowListeners;
    private List<OnCancelListener> mCancelListeners;
    private List<OnDismissListener> mDismissListeners;
    public BaseDialog(Context context) {
        this(context, R.style.BaseDialogStyle);
    }
    public BaseDialog(Context context, @StyleRes int themeResId) {
        super(context, themeResId);
    }
    /**
     * 获取 Dialog 的根布局
     */
    public View getContentView() {
        return findViewById(Window.ID_ANDROID_CONTENT);
    }
    /**
     * 获取当前设置重心
     */
    public int getGravity() {
        Window window = getWindow();
        if (window != null) {
            WindowManager.LayoutParams params = window.getAttributes();
            return params.gravity;
        }
        return Gravity.NO_GRAVITY;
    }
    /**
     * 设置宽度
     */
    public void setWidth(int width) {
        Window window = getWindow();
        if (window != null) {
            WindowManager.LayoutParams params = window.getAttributes();
            params.width = width;
            window.setAttributes(params);
        }
    }
    /**
     * 设置高度
     */
    public void setHeight(int height) {
        Window window = getWindow();
        if (window != null) {
            WindowManager.LayoutParams params = window.getAttributes();
            params.height = height;
            window.setAttributes(params);
        }
    }
    /**
     * 设置 Dialog 重心
     */
    public void setGravity(int gravity) {
        Window window = getWindow();
        if (window != null) {
            window.setGravity(gravity);
        }
    }
    /**
     * 设置 Dialog 的动画
     */
    public void setWindowAnimations(@StyleRes int id) {
        Window window = getWindow();
        if (window != null) {
            window.setWindowAnimations(id);
        }
    }
    /**
     * 获取 Dialog 的动画
     */
    public int getWindowAnimations() {
        Window window = getWindow();
        if (window != null) {
            return window.getAttributes().windowAnimations;
        }
        return BaseDialog.ANIM_DEFAULT;
    }
    /**
     * 设置背景遮盖层开关
     */
    public void setBackgroundDimEnabled(boolean enabled) {
        Window window = getWindow();
        if (window != null) {
            if (enabled) {
                window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
            } else {
                window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
            }
        }
    }
    /**
     * 设置背景遮盖层的透明度(前提条件是背景遮盖层开关必须是为开启状态)
     */
    public void setBackgroundDimAmount(@FloatRange(from = 0.0, to = 1.0) float dimAmount) {
        Window window = getWindow();
        if (window != null) {
            window.setDimAmount(dimAmount);
        }
    }
    @Override
    public void dismiss() {
        removeCallbacks();
        View focusView = getCurrentFocus();
        if (focusView != null) {
            BaseApplication.getInstance().getSystemService(InputMethodManager.class).hideSoftInputFromWindow(focusView.getWindowToken(), 0);
        }
        super.dismiss();
    }
    /**
     * 设置一个显示监听器
     *
     * @param listener       显示监听器对象
     * @deprecated           请使用 {@link #addOnShowListener(OnShowListener)}}
     */
    @Deprecated
    @Override
    public void setOnShowListener(@Nullable DialogInterface.OnShowListener listener) {
        if (listener == null) {
            return;
        }
        addOnShowListener(new ShowListenerWrapper(listener));
    }
    /**
     * 设置一个取消监听器
     *
     * @param listener       取消监听器对象
     * @deprecated           请使用 {@link #addOnCancelListener(OnCancelListener)}
     */
    @Deprecated
    @Override
    public void setOnCancelListener(@Nullable DialogInterface.OnCancelListener listener) {
        if (listener == null) {
            return;
        }
        addOnCancelListener(new CancelListenerWrapper(listener));
    }
    /**
     * 设置一个销毁监听器
     *
     * @param listener       销毁监听器对象
     * @deprecated           请使用 {@link #addOnDismissListener(OnDismissListener)}
     */
    @Deprecated
    @Override
    public void setOnDismissListener(@Nullable DialogInterface.OnDismissListener listener) {
        if (listener == null) {
            return;
        }
        addOnDismissListener(new DismissListenerWrapper(listener));
    }
    /**
     * 设置一个按键监听器
     *
     * @param listener       按键监听器对象
     * @deprecated           请使用 {@link #setOnKeyListener(OnKeyListener)}
     */
    @Deprecated
    @Override
    public void setOnKeyListener(@Nullable DialogInterface.OnKeyListener listener) {
        super.setOnKeyListener(listener);
    }
    public void setOnKeyListener(@Nullable OnKeyListener listener) {
        super.setOnKeyListener(new KeyListenerWrapper(listener));
    }
    /**
     * 添加一个显示监听器
     *
     * @param listener      监听器对象
     */
    public void addOnShowListener(@Nullable OnShowListener listener) {
        if (mShowListeners == null) {
            mShowListeners = new ArrayList<>();
            super.setOnShowListener(mListeners);
        }
        mShowListeners.add(listener);
    }
    /**
     * 添加一个取消监听器
     *
     * @param listener      监听器对象
     */
    public void addOnCancelListener(@Nullable OnCancelListener listener) {
        if (mCancelListeners == null) {
            mCancelListeners = new ArrayList<>();
            super.setOnCancelListener(mListeners);
        }
        mCancelListeners.add(listener);
    }
    /**
     * 添加一个销毁监听器
     *
     * @param listener      监听器对象
     */
    public void addOnDismissListener(@Nullable OnDismissListener listener) {
        if (mDismissListeners == null) {
            mDismissListeners = new ArrayList<>();
            super.setOnDismissListener(mListeners);
        }
        mDismissListeners.add(listener);
    }
    /**
     * 移除一个显示监听器
     *
     * @param listener      监听器对象
     */
    public void removeOnShowListener(@Nullable OnShowListener listener) {
        if (mShowListeners != null) {
            mShowListeners.remove(listener);
        }
    }
    /**
     * 移除一个取消监听器
     *
     * @param listener      监听器对象
     */
    public void removeOnCancelListener(@Nullable OnCancelListener listener) {
        if (mCancelListeners != null) {
            mCancelListeners.remove(listener);
        }
    }
    /**
     * 移除一个销毁监听器
     *
     * @param listener      监听器对象
     */
    public void removeOnDismissListener(@Nullable OnDismissListener listener) {
        if (mDismissListeners != null) {
            mDismissListeners.remove(listener);
        }
    }
    /**
     * 设置显示监听器集合
     */
    private void setOnShowListeners(@Nullable List<OnShowListener> listeners) {
        super.setOnShowListener(mListeners);
        mShowListeners = listeners;
    }
    /**
     * 设置取消监听器集合
     */
    private void setOnCancelListeners(@Nullable List<OnCancelListener> listeners) {
        super.setOnCancelListener(mListeners);
        mCancelListeners = listeners;
    }
    /**
     * 设置销毁监听器集合
     */
    private void setOnDismissListeners(@Nullable List<OnDismissListener> listeners) {
        super.setOnDismissListener(mListeners);
        mDismissListeners = listeners;
    }
    /**
     * {@link DialogInterface.OnShowListener}
     */
    @Override
    public void onShow(DialogInterface dialog) {
        mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
        if (mShowListeners != null) {
            for (int i = 0; i < mShowListeners.size(); i++) {
                mShowListeners.get(i).onShow(this);
            }
        }
    }
    /**
     * {@link DialogInterface.OnCancelListener}
     */
    @Override
    public void onCancel(DialogInterface dialog) {
        if (mCancelListeners != null) {
            for (int i = 0; i < mCancelListeners.size(); i++) {
                mCancelListeners.get(i).onCancel(this);
            }
        }
    }
    /**
     * {@link DialogInterface.OnDismissListener}
     */
    @Override
    public void onDismiss(DialogInterface dialog) {
        mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
        if (mDismissListeners != null) {
            for (int i = 0; i < mDismissListeners.size(); i++) {
                mDismissListeners.get(i).onDismiss(this);
            }
        }
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
    }
    @Override
    protected void onStart() {
        super.onStart();
        mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START);
    }
    @Override
    protected void onStop() {
        super.onStop();
        mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
    }
    @SuppressWarnings("unchecked")
    public static class Builder<B extends Builder> implements LifecycleOwner, ActivityAction,ClickAction{
        /** 上下文对象 */
        private final Context mContext;
        /** Dialog 对象 */
        private BaseDialog mDialog;
        /** Dialog 布局 */
        private View mContentView;
        /** 主题样式 */
        private int mThemeId = R.style.BaseDialogStyle;
        /** 动画样式 */
        private int mAnimStyle = BaseDialog.ANIM_DEFAULT;
        /** 重心位置 */
        private int mGravity = Gravity.NO_GRAVITY;
        /** 水平偏移 */
        private int mXOffset;
        /** 垂直偏移 */
        private int mYOffset;
        /** 宽度和高度 */
        private int mWidth = ViewGroup.LayoutParams.WRAP_CONTENT;
        private int mHeight = ViewGroup.LayoutParams.WRAP_CONTENT;
        /** 背景遮盖层开关 */
        private boolean mBackgroundDimEnabled = true;
        /** 背景遮盖层透明度 */
        private float mBackgroundDimAmount = 0.5f;
        /** 是否能够被取消 */
        private boolean mCancelable = true;
        /** 点击空白是否能够取消  前提是这个对话框可以被取消 */
        private boolean mCanceledOnTouchOutside = true;
        /** Dialog Show 监听 */
        private List<OnShowListener> mOnShowListeners;
        /** Dialog Cancel 监听 */
        private List<OnCancelListener> mOnCancelListeners;
        /** Dialog Dismiss 监听 */
        private List<OnDismissListener> mOnDismissListeners;
        /** Dialog Key 监听 */
        private OnKeyListener mOnKeyListener;
        /** 点击事件集合 */
        private SparseArray<OnClickListener> mClickArray;
        public Builder(Activity activity) {
            this((Context) activity);
        }
        public Builder(Context context) {
            mContext = context;
        }
        /**
         * 设置主题 id
         */
        public B setThemeStyle(@StyleRes int id) {
            if (isCreated()) {
                // Dialog 创建之后不能再设置主题 id
                throw new IllegalStateException("are you ok?");
            }
            mThemeId = id;
            return (B) this;
        }
        /**
         * 设置布局
         */
        public B setContentView(@LayoutRes int id) {
            // 这里解释一下,为什么要传 new FrameLayout,因为如果不传的话,XML 的根布局获取到的 LayoutParams 对象会为空,也就会导致宽高参数解析不出来
            return setContentView(LayoutInflater.from(mContext).inflate(id, new FrameLayout(mContext), false));
        }
        public B setContentView(View view) {
            mContentView = view;
            if (isCreated()) {
                mDialog.setContentView(view);
            } else {
                if (mContentView != null) {
                    ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
                    if (layoutParams != null && mWidth == ViewGroup.LayoutParams.WRAP_CONTENT && mHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
                        // 如果当前 Dialog 的宽高设置了自适应,就以布局中设置的宽高为主
                        setWidth(layoutParams.width);
                        setHeight(layoutParams.height);
                    }
                    // 如果当前没有设置重心,就自动获取布局重心
                    if (mGravity == Gravity.NO_GRAVITY) {
                        if (layoutParams instanceof FrameLayout.LayoutParams) {
                            setGravity(((FrameLayout.LayoutParams) layoutParams).gravity);
                        } else if (layoutParams instanceof LinearLayout.LayoutParams) {
                            setGravity(((LinearLayout.LayoutParams) layoutParams).gravity);
                        } else {
                            // 默认重心是居中
                            setGravity(Gravity.CENTER);
                        }
                    }
                }
            }
            return (B) this;
        }
        /**
         * 设置重心位置
         */
        public B setGravity(int gravity) {
            // 适配 Android 4.2 新特性,布局反方向(开发者选项 - 强制使用从右到左的布局方向)
            mGravity = gravity;
            if (isCreated()) {
                mDialog.setGravity(gravity);
            }
            return (B) this;
        }
        /**
         * 设置水平偏移
         */
        public B setXOffset(int offset) {
            mXOffset = offset;
            return (B) this;
        }
        /**
         * 设置垂直偏移
         */
        public B setYOffset(int offset) {
            mYOffset = offset;
            return (B) this;
        }
        /**
         * 设置宽度
         */
        public B setWidth(int width) {
            mWidth = width;
            if (isCreated()) {
                mDialog.setWidth(width);
            } else {
                ViewGroup.LayoutParams params = mContentView != null ? mContentView.getLayoutParams() : null;
                if (params != null) {
                    params.width = width;
                    mContentView.setLayoutParams(params);
                }
            }
            return (B) this;
        }
        /**
         * 设置高度
         */
        public B setHeight(int height) {
            mHeight = height;
            if (isCreated()) {
                mDialog.setHeight(height);
            } else {
                // 这里解释一下为什么要重新设置 LayoutParams
                // 因为如果不这样设置的话,第一次显示的时候会按照 Dialog 宽高显示
                // 但是 Layout 内容变更之后就不会按照之前的设置宽高来显示
                // 所以这里我们需要对 View 的 LayoutParams 也进行设置
                ViewGroup.LayoutParams params = mContentView != null ? mContentView.getLayoutParams() : null;
                if (params != null) {
                    params.height = height;
                    mContentView.setLayoutParams(params);
                }
            }
            return (B) this;
        }
        /**
         * 是否可以取消
         */
        public B setCancelable(boolean cancelable) {
            mCancelable = cancelable;
            if (isCreated()) {
                mDialog.setCancelable(cancelable);
            }
            return (B) this;
        }
        /**
         * 是否可以通过点击空白区域取消
         */
        public B setCanceledOnTouchOutside(boolean cancel) {
            mCanceledOnTouchOutside = cancel;
            if (isCreated() && mCancelable) {
                mDialog.setCanceledOnTouchOutside(cancel);
            }
            return (B) this;
        }
        /**
         * 设置动画,已经封装好几种样式,具体可见{@link AnimAction}类
         */
        public B setAnimStyle(@StyleRes int id) {
            mAnimStyle = id;
            if (isCreated()) {
                mDialog.setWindowAnimations(id);
            }
            return (B) this;
        }
        /**
         * 设置背景遮盖层开关
         */
        public B setBackgroundDimEnabled(boolean enabled) {
            mBackgroundDimEnabled = enabled;
            if (isCreated()) {
                mDialog.setBackgroundDimEnabled(enabled);
            }
            return (B) this;
        }
        /**
         * 设置背景遮盖层的透明度(前提条件是背景遮盖层开关必须是为开启状态)
         */
        public B setBackgroundDimAmount(@FloatRange(from = 0.0, to = 1.0) float dimAmount) {
            mBackgroundDimAmount = dimAmount;
            if (isCreated()) {
                mDialog.setBackgroundDimAmount(dimAmount);
            }
            return (B) this;
        }
        /**
         * 添加显示监听
         */
        public B addOnShowListener(@NonNull OnShowListener listener) {
            if (isCreated()) {
                mDialog.addOnShowListener(listener);
            } else {
                if (mOnShowListeners == null) {
                    mOnShowListeners = new ArrayList<>();
                }
                mOnShowListeners.add(listener);
            }
            return (B) this;
        }
        /**
         * 添加取消监听
         */
        public B addOnCancelListener(@NonNull OnCancelListener listener) {
            if (isCreated()) {
                mDialog.addOnCancelListener(listener);
            } else {
                if (mOnCancelListeners == null) {
                    mOnCancelListeners = new ArrayList<>();
                }
                mOnCancelListeners.add(listener);
            }
            return (B) this;
        }
        /**
         * 添加销毁监听
         */
        public B addOnDismissListener(@NonNull OnDismissListener listener) {
            if (isCreated()) {
                mDialog.addOnDismissListener(listener);
            } else {
                if (mOnDismissListeners == null) {
                    mOnDismissListeners = new ArrayList<>();
                }
                mOnDismissListeners.add(listener);
            }
            return (B) this;
        }
        /**
         * 设置按键监听
         */
        public B setOnKeyListener(@NonNull OnKeyListener listener) {
            if (isCreated()) {
                mDialog.setOnKeyListener(listener);
            } else {
                mOnKeyListener = listener;
            }
            return (B) this;
        }
        /**
         * 设置文本
         */
        public B setText(@IdRes int viewId, @StringRes int stringId) {
            return setText(viewId, getString(stringId));
        }
        public B setText(@IdRes int id, CharSequence text) {
            ((TextView) findViewById(id)).setText(text);
            return (B) this;
        }
        /**
         * 设置文本颜色
         */
        public B setTextColor(@IdRes int id, @ColorInt int color) {
            ((TextView) findViewById(id)).setTextColor(color);
            return (B) this;
        }
        /**
         * 设置提示
         */
        public B setHint(@IdRes int viewId, @StringRes int stringId) {
            return setHint(viewId, getString(stringId));
        }
        public B setHint(@IdRes int id, CharSequence text) {
            ((TextView) findViewById(id)).setHint(text);
            return (B) this;
        }
        /**
         * 设置可见状态
         */
        public B setVisibility(@IdRes int id, int visibility) {
            findViewById(id).setVisibility(visibility);
            return (B) this;
        }
        /**
         * 设置背景
         */
        public B setBackground(@IdRes int viewId, @DrawableRes int drawableId) {
            return setBackground(viewId, ContextCompat.getDrawable(mContext, drawableId));
        }
        public B setBackground(@IdRes int id, Drawable drawable) {
            findViewById(id).setBackground(drawable);
            return (B) this;
        }
        /**
         * 设置图片
         */
        public B setImageDrawable(@IdRes int viewId, @DrawableRes int drawableId) {
            return setBackground(viewId, ContextCompat.getDrawable(mContext, drawableId));
        }
        public B setImageDrawable(@IdRes int id, Drawable drawable) {
            ((ImageView) findViewById(id)).setImageDrawable(drawable);
            return (B) this;
        }
        /**
         * 设置点击事件
         */
        public B setOnClickListener(@IdRes int id, @NonNull OnClickListener listener) {
            if (isCreated()) {
                View view = mDialog.findViewById(id);
                if (view != null) {
                    view.setOnClickListener(new ViewClickWrapper(mDialog, listener));
                }
            } else {
                if (mClickArray == null) {
                    mClickArray = new SparseArray<>();
                }
                mClickArray.put(id, listener);
            }
            return (B) this;
        }
        /**
         * 创建
         */
        @SuppressLint("RtlHardcoded")
        public BaseDialog create() {
            // 判断布局是否为空
            if (mContentView == null) {
                throw new IllegalArgumentException("are you ok?");
            }
            // 如果当前没有设置重心,就设置一个默认的重心
            if (mGravity == Gravity.NO_GRAVITY) {
                mGravity = Gravity.CENTER;
            }
            // 如果当前没有设置动画效果,就设置一个默认的动画效果
            if (mAnimStyle == BaseDialog.ANIM_DEFAULT) {
                switch (mGravity) {
                    case Gravity.TOP:
                        mAnimStyle = BaseDialog.ANIM_TOP;
                        break;
                    case Gravity.BOTTOM:
                        mAnimStyle = BaseDialog.ANIM_BOTTOM;
                        break;
                    case Gravity.LEFT:
                        mAnimStyle = BaseDialog.ANIM_LEFT;
                        break;
                    case Gravity.RIGHT:
                        mAnimStyle = BaseDialog.ANIM_RIGHT;
                        break;
                    default:
                        mAnimStyle = BaseDialog.ANIM_DEFAULT;
                        break;
                }
            }
            mDialog = createDialog(mContext, mThemeId);
            mDialog.setContentView(mContentView);
            mDialog.setCancelable(mCancelable);
            if (mCancelable) {
                mDialog.setCanceledOnTouchOutside(mCanceledOnTouchOutside);
            }
            // 设置参数
            Window window = mDialog.getWindow();
            if (window != null) {
                WindowManager.LayoutParams params = window.getAttributes();
                params.width = mWidth;
                params.height = mHeight;
                params.gravity = mGravity;
                params.x = mXOffset;
                params.y = mYOffset;
                params.windowAnimations = mAnimStyle;
                window.setAttributes(params);
                if (mBackgroundDimEnabled) {
                    window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
                    window.setDimAmount(mBackgroundDimAmount);
                } else {
                    window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
                }
            }
            if (mOnShowListeners != null) {
                mDialog.setOnShowListeners(mOnShowListeners);
            }
            if (mOnCancelListeners != null) {
                mDialog.setOnCancelListeners(mOnCancelListeners);
            }
            if (mOnDismissListeners != null) {
                mDialog.setOnDismissListeners(mOnDismissListeners);
            }
            if (mOnKeyListener != null) {
                mDialog.setOnKeyListener(mOnKeyListener);
            }
            for (int i = 0; mClickArray != null && i < mClickArray.size(); i++) {
                mContentView.findViewById(mClickArray.keyAt(i)).setOnClickListener(new ViewClickWrapper(mDialog, mClickArray.valueAt(i)));
            }
            Activity activity = getActivity();
            if (activity != null) {
                DialogLifecycle.with(activity, mDialog);
            }
            return mDialog;
        }
        /**
         * 显示
         */
        public BaseDialog show() {
            if (!isCreated()) {
                create();
            }
            mDialog.show();
            return mDialog;
        }
        /**
         * 销毁当前 Dialog
         */
        public void dismiss() {
            if (mDialog != null) {
                mDialog.dismiss();
            }
        }
        @Override
        public Context getContext() {
            return mContext;
        }
        /**
         * 当前 Dialog 是否创建了
         */
        public boolean isCreated() {
            return mDialog != null;
        }
        /**
         * 当前 Dialog 是否显示了
         */
        public boolean isShowing() {
            return mDialog != null && mDialog.isShowing();
        }
        /**
         * 创建 Dialog 对象(子类可以重写此方法来改变 Dialog 类型)
         */
        protected BaseDialog createDialog(Context context, @StyleRes int themeId) {
            return new BaseDialog(context, themeId);
        }
        /**
         * 延迟执行
         */
        public final void post(Runnable r) {
            if (isShowing()) {
                mDialog.post(r);
            } else {
                addOnShowListener(new ShowPostWrapper(r));
            }
        }
        /**
         * 延迟一段时间执行
         */
        public final void postDelayed(Runnable r, long delayMillis) {
            if (isShowing()) {
                mDialog.postDelayed(r, delayMillis);
            } else {
                addOnShowListener(new ShowPostDelayedWrapper(r, delayMillis));
            }
        }
        /**
         * 在指定的时间执行
         */
        public final void postAtTime(Runnable r, long uptimeMillis) {
            if (isShowing()) {
                mDialog.postAtTime(r, uptimeMillis);
            } else {
                addOnShowListener(new ShowPostAtTimeWrapper(r, uptimeMillis));
            }
        }
        /**
         * 获取 Dialog 的根布局
         */
        public View getContentView() {
            return mContentView;
        }
        /**
         * 根据 id 查找 View
         */
        @Override
        public  <V extends View> V findViewById(@IdRes int id) {
            if (mContentView == null) {
                // 没有 setContentView 就想 findViewById ?
                throw new IllegalStateException("are you ok?");
            }
            return mContentView.findViewById(id);
        }
        /**
         * 获取当前 Dialog 对象
         */
        @Nullable
        public BaseDialog getDialog() {
            return mDialog;
        }
        @Nullable
        @Override
        public Lifecycle getLifecycle() {
            if (mDialog != null) {
                return mDialog.getLifecycle();
            }
            return null;
        }
    }
    /**
     * Dialog 生命周期管理
     */
    private static final class DialogLifecycle implements
            Application.ActivityLifecycleCallbacks,
            OnShowListener,
            OnDismissListener {
        private static void with(Activity activity, BaseDialog dialog) {
            new DialogLifecycle(activity, dialog);
        }
        private BaseDialog mDialog;
        private Activity mActivity;
        /** Dialog 动画样式(避免 Dialog 从后台返回到前台后再次触发动画效果) */
        private int mDialogAnim;
        private DialogLifecycle(Activity activity, BaseDialog dialog) {
            mActivity = activity;
            dialog.addOnShowListener(this);
            dialog.addOnDismissListener(this);
        }
        @Override
        public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {}
        @Override
        public void onActivityStarted(@NonNull Activity activity) {}
        @Override
        public void onActivityResumed(@NonNull Activity activity) {
            if (mActivity != activity) {
                return;
            }
            if (mDialog != null && mDialog.isShowing()) {
                // 还原 Dialog 动画样式(这里必须要使用延迟设置,否则还是有一定几率会出现)
                mDialog.postDelayed(() -> {
                    if (mDialog != null && mDialog.isShowing()) {
                        mDialog.setWindowAnimations(mDialogAnim);
                    }
                }, 100);
            }
        }
        @Override
        public void onActivityPaused(@NonNull Activity activity) {
            if (mActivity != activity) {
                return;
            }
            if (mDialog != null && mDialog.isShowing()) {
                // 获取 Dialog 动画样式
                mDialogAnim = mDialog.getWindowAnimations();
                // 设置 Dialog 无动画效果
                mDialog.setWindowAnimations(BaseDialog.ANIM_EMPTY);
            }
        }
        @Override
        public void onActivityStopped(@NonNull Activity activity) {}
        @Override
        public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {}
        @Override
        public void onActivityDestroyed(@NonNull Activity activity) {
            if (mActivity != activity) {
                return;
            }
            if (mDialog != null) {
                mDialog.removeOnShowListener(this);
                mDialog.removeOnDismissListener(this);
                if (mDialog.isShowing()) {
                    mDialog.dismiss();
                }
                mDialog = null;
            }
            unregisterActivityLifecycleCallbacks();
            // 释放 Activity 对象
            mActivity = null;
        }
        @Override
        public void onShow(BaseDialog dialog) {
            mDialog = dialog;
            registerActivityLifecycleCallbacks();
        }
        @Override
        public void onDismiss(BaseDialog dialog) {
            mDialog = null;
            unregisterActivityLifecycleCallbacks();
        }
        /**
         * 注册 Activity 生命周期监听
         */
        private void registerActivityLifecycleCallbacks() {
            if (mActivity == null) {
                return;
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                mActivity.registerActivityLifecycleCallbacks(this);
            } else {
                mActivity.getApplication().registerActivityLifecycleCallbacks(this);
            }
        }
        /**
         * 反注册 Activity 生命周期监听
         */
        private void unregisterActivityLifecycleCallbacks() {
            if (mActivity == null) {
                return;
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                mActivity.unregisterActivityLifecycleCallbacks(this);
            } else {
                mActivity.getApplication().unregisterActivityLifecycleCallbacks(this);
            }
        }
    }
    /**
     * Dialog 监听包装类(修复原生 Dialog 监听器对象导致的内存泄漏)
     */
    private static final class ListenersWrapper<T extends DialogInterface.OnShowListener & DialogInterface.OnCancelListener & DialogInterface.OnDismissListener>
            extends SoftReference<T> implements DialogInterface.OnShowListener, DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {
        private ListenersWrapper(T referent) {
            super(referent);
        }
        @Override
        public void onShow(DialogInterface dialog) {
            if (get() != null) {
                get().onShow(dialog);
            }
        }
        @Override
        public void onCancel(DialogInterface dialog) {
            if (get() != null) {
                get().onCancel(dialog);
            }
        }
        @Override
        public void onDismiss(DialogInterface dialog) {
            if (get() != null) {
                get().onDismiss(dialog);
            }
        }
    }
    /**
     * 点击事件包装类
     */
    private static final class ViewClickWrapper
            implements View.OnClickListener {
        private final BaseDialog mDialog;
        private final OnClickListener mListener;
        private ViewClickWrapper(BaseDialog dialog, OnClickListener listener) {
            mDialog = dialog;
            mListener = listener;
        }
        @SuppressWarnings("unchecked")
        @Override
        public final void onClick(View v) {
            mListener.onClick(mDialog, v);
        }
    }
    /**
     * 显示监听包装类
     */
    private static final class ShowListenerWrapper
            extends SoftReference<DialogInterface.OnShowListener>
            implements OnShowListener {
        private ShowListenerWrapper(DialogInterface.OnShowListener referent) {
            super(referent);
        }
        @Override
        public void onShow(BaseDialog dialog) {
            // 在横竖屏切换后监听对象会为空
            if (get() != null) {
                get().onShow(dialog);
            }
        }
    }
    /**
     * 取消监听包装类
     */
    private static final class CancelListenerWrapper
            extends SoftReference<DialogInterface.OnCancelListener>
            implements OnCancelListener {
        private CancelListenerWrapper(DialogInterface.OnCancelListener referent) {
            super(referent);
        }
        @Override
        public void onCancel(BaseDialog dialog) {
            // 在横竖屏切换后监听对象会为空
            if (get() != null) {
                get().onCancel(dialog);
            }
        }
    }
    /**
     * 销毁监听包装类
     */
    private static final class DismissListenerWrapper
            extends SoftReference<DialogInterface.OnDismissListener>
            implements OnDismissListener {
        private DismissListenerWrapper(DialogInterface.OnDismissListener referent) {
            super(referent);
        }
        @Override
        public void onDismiss(BaseDialog dialog) {
            // 在横竖屏切换后监听对象会为空
            if (get() != null) {
                get().onDismiss(dialog);
            }
        }
    }
    /**
     * 按键监听包装类
     */
    private static final class KeyListenerWrapper
            implements DialogInterface.OnKeyListener {
        private final OnKeyListener mListener;
        private KeyListenerWrapper(OnKeyListener listener) {
            mListener = listener;
        }
        @Override
        public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
            // 在横竖屏切换后监听对象会为空
            if (mListener != null && dialog instanceof BaseDialog) {
                mListener.onKey((BaseDialog) dialog, event);
            }
            return false;
        }
    }
    /**
     * post 任务包装类
     */
    private static final class ShowPostWrapper implements OnShowListener {
        private final Runnable mRunnable;
        private ShowPostWrapper(Runnable r) {
            mRunnable = r;
        }
        @Override
        public void onShow(BaseDialog dialog) {
            if (mRunnable != null) {
                dialog.removeOnShowListener(this);
                dialog.post(mRunnable);
            }
        }
    }
    /**
     * postDelayed 任务包装类
     */
    private static final class ShowPostDelayedWrapper implements OnShowListener {
        private final Runnable mRunnable;
        private final long mDelayMillis;
        private ShowPostDelayedWrapper(Runnable r, long delayMillis) {
            mRunnable = r;
            mDelayMillis = delayMillis;
        }
        @Override
        public void onShow(BaseDialog dialog) {
            if (mRunnable != null) {
                dialog.removeOnShowListener(this);
                dialog.postDelayed(mRunnable, mDelayMillis);
            }
        }
    }
    /**
     * postAtTime 任务包装类
     */
    private static final class ShowPostAtTimeWrapper implements OnShowListener {
        private final Runnable mRunnable;
        private final long mUptimeMillis;
        private ShowPostAtTimeWrapper(Runnable r, long uptimeMillis) {
            mRunnable = r;
            mUptimeMillis = uptimeMillis;
        }
        @Override
        public void onShow(BaseDialog dialog) {
            if (mRunnable != null) {
                dialog.removeOnShowListener(this);
                dialog.postAtTime(mRunnable, mUptimeMillis);
            }
        }
    }
    /**
     * 点击监听器
     */
    public interface OnClickListener<V extends View> {
        void onClick(BaseDialog dialog, V view);
    }
    /**
     * 显示监听器
     */
    public interface OnShowListener {
        /**
         * Dialog 显示了
         */
        void onShow(BaseDialog dialog);
    }
    /**
     * 取消监听器
     */
    public interface OnCancelListener {
        /**
         * Dialog 取消了
         */
        void onCancel(BaseDialog dialog);
    }
    /**
     * 销毁监听器
     */
    public interface OnDismissListener {
        /**
         * Dialog 销毁了
         */
        void onDismiss(BaseDialog dialog);
    }
    /**
     * 按键监听器
     */
    public interface OnKeyListener {
        /**
         * 触发了按键
         */
        boolean onKey(BaseDialog dialog, KeyEvent event);
    }
}
app_base/src/main/java/com/android/app_base/base/dialog/UIDialog.java
New file
@@ -0,0 +1,145 @@
package com.android.app_base.base.dialog;
import static com.blankj.utilcode.util.StringUtils.getString;
import android.content.Context;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.LayoutRes;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import com.android.app_base.R;
/**
 * 具体实现类dialog,通用类型
 */
public final class UIDialog {
    @SuppressWarnings("unchecked")
    public static class Builder<B extends UIDialog.Builder<?>>
            extends BaseDialog.Builder<B> {
        @Nullable
        private OnListener mListener;
        private boolean mAutoDismiss = true;
        private final ViewGroup mContainerLayout;
        private final TextView mTitleView;
        private final TextView mContentView;
        private final TextView mCancelView;
        private final TextView mConfirmView;
        public Builder(Context context) {
            super(context);
            setContentView(R.layout.dialog_ui);
            setAnimStyle(BaseDialog.ANIM_IOS);
            setGravity(Gravity.CENTER);
            mContainerLayout = findViewById(R.id.ll_ui_container);
            mTitleView = findViewById(R.id.tv_ui_title);
            mContentView = findViewById(R.id.tv_content);
            mCancelView = findViewById(R.id.tv_ui_cancel);
            mConfirmView = findViewById(R.id.tv_ui_confirm);
            setOnClickListener(mCancelView, mConfirmView);
        }
        public B setCustomView(@LayoutRes int id) {
            return setCustomView(LayoutInflater.from(getContext()).inflate(id, mContainerLayout, false));
        }
        public B setCustomView(View view) {
            mContainerLayout.addView(view, 1);
            return (B) this;
        }
        public B setTitle(@StringRes int id) {
            return setTitle(getString(id));
        }
        public B setTitle(CharSequence text) {
            mTitleView.setText(text);
            return (B) this;
        }
        public B setContent(CharSequence text) {
            mContentView.setText(text);
            return (B) this;
        }
        public B setCancel(@StringRes int id) {
            return setCancel(getString(id));
        }
        public B setCancel(CharSequence text) {
            mCancelView.setText(text);
            return (B) this;
        }
        public B setConfirm(@StringRes int id) {
            return setConfirm(getString(id));
        }
        public B setConfirm(CharSequence text) {
            mConfirmView.setText(text);
            return (B) this;
        }
        public B setAutoDismiss(boolean dismiss) {
            mAutoDismiss = dismiss;
            return (B) this;
        }
        public void autoDismiss() {
            if (mAutoDismiss) {
                dismiss();
            }
        }
        public B setListener(OnListener listener) {
            mListener = listener;
            return (B) this;
        }
        @Override
        public BaseDialog show() {
            return super.show();
        }
        @Override
        public void onClick(View view) {
            int viewId = view.getId();
            if (viewId == R.id.tv_ui_confirm) {
                autoDismiss();
                if (mListener == null) {
                    return;
                }
                mListener.onConfirm(getDialog());
            } else if (viewId == R.id.tv_ui_cancel) {
                autoDismiss();
                if (mListener == null) {
                    return;
                }
                mListener.onCancel(getDialog());
            }
        }
    }
    public interface OnListener {
        /**
         * 点击确定时回调
         */
        void onConfirm(BaseDialog dialog);
        /**
         * 点击取消时回调
         */
        default void onCancel(BaseDialog dialog) {}
    }
}
app_base/src/main/java/com/android/app_base/base/view/BaseActivity.java
@@ -20,12 +20,12 @@
import com.android.app_base.action.TitleBarAction;
import com.android.app_base.base.BaseApplication;
import com.android.app_base.base.action.ClickAction;
import com.android.app_base.base.viewmodel.BaseViewModel;
import com.android.app_base.base.StateViewEnum;
import com.android.app_base.utils.ScreenSizeUtils;
import com.blankj.utilcode.util.AdaptScreenUtils;
import com.blankj.utilcode.util.ToastUtils;
import com.gyf.immersionbar.ImmersionBar;
import com.hjq.bar.OnTitleBarListener;
import com.hjq.bar.TitleBar;
import java.lang.reflect.ParameterizedType;
@@ -34,7 +34,7 @@
/**
 *  Activity基类,所有的 Activity 都要继承此类
 */
public abstract class BaseActivity<V extends ViewDataBinding,VM extends BaseViewModel> extends AppCompatActivity implements TitleBarAction{
public abstract class BaseActivity<V extends ViewDataBinding,VM extends BaseViewModel> extends AppCompatActivity implements TitleBarAction, ClickAction {
    protected V binding;
    protected VM viewModel;
    private int viewModelId;
@@ -49,10 +49,6 @@
    private ImmersionBar mImmersionBar;
    @Override
    protected void onResume() {
        super.onResume();
    }
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -63,13 +59,16 @@
        initParam();
        //页面view初始化方法
        initView();
        //页面数据初始化方法
        initData();
        //页面事件监听的方法,用于ViewModel层转到View层的事件注册
        initLiveDataObserve();
        ScreenSizeUtils.setCustomDensity(this, BaseApplication.getInstance());
    }
    @Override
    protected void onResume() {
        super.onResume();
        //页面数据初始化方法
        initData();
    }
    @Override
    protected void onDestroy() {
@@ -163,6 +162,12 @@
                    default:
                        break;
                }
            }
        });
        viewModel.getMessageLivaData().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String message) {
                ToastUtils.showShort(message);
            }
        });
    }
@@ -287,6 +292,7 @@
            InputMethodManager manager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            if (manager != null && manager.isActive(view)) {
                manager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
                view.clearFocus();
            }
        }
    }
app_base/src/main/java/com/android/app_base/base/viewmodel/BaseViewModel.java
@@ -31,7 +31,8 @@
    /**
     * 控制状态视图的LiveData
     */
    private MutableLiveData<StateViewEnum> stateViewLiveData;
    protected MutableLiveData<StateViewEnum> stateViewLiveData;
    protected MutableLiveData<String> messageLiveData;
    //管理RxJava,主要针对RxJava异步操作造成的内存泄漏
    private CompositeDisposable mCompositeDisposable;
@@ -66,6 +67,12 @@
        }
        return stateViewLiveData;
    }
    public LiveData<String> getMessageLivaData(){
        if(messageLiveData == null){
            messageLiveData = new MutableLiveData<>();
        }
        return messageLiveData;
    }
    /**
     * 更改状态视图的状态
     */
app_base/src/main/java/com/android/app_base/http/OkHttpHelper.java
@@ -7,6 +7,7 @@
import com.android.app_base.BuildConfig;
import com.android.app_base.base.BaseApplication;
import com.android.app_base.http.interceptor.CacheInterceptor;
import com.android.app_base.http.interceptor.LogInterceptor;
import com.blankj.utilcode.util.LogUtils;
import com.franmontiel.persistentcookiejar.PersistentCookieJar;
import com.franmontiel.persistentcookiejar.cache.SetCookieCache;
@@ -69,6 +70,7 @@
                return chain.proceed(build);
            }
        });
        clientBuilder.addInterceptor(new LogInterceptor());//拦截器添加公共参数
        //log日志拦截
        if (BuildConfig.DEBUG) {
            clientBuilder.addInterceptor(new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
app_base/src/main/java/com/android/app_base/http/ResultData.java
@@ -13,7 +13,7 @@
    /**
     * 提示信息
     */
    private String message;
    private String msg;
    /**
     * 返回数据
     */
@@ -35,11 +35,11 @@
        this.code = code;
    }
    public String getMessage() {
        return message;
    public String getMsg() {
        return msg;
    }
    public void setMessage(String message) {
        this.message = message;
    public void setMsg(String msg) {
        this.msg = msg;
    }
}
app_base/src/main/java/com/android/app_base/http/interceptor/LogInterceptor.java
New file
@@ -0,0 +1,93 @@
package com.android.app_base.http.interceptor;
import android.annotation.SuppressLint;
import android.text.TextUtils;
import com.android.app_base.base.BaseConfig;
import com.android.app_base.manager.AppManager;
import com.android.app_base.manager.UserManager;
import com.blankj.utilcode.util.ActivityUtils;
import com.blankj.utilcode.util.DeviceUtils;
import com.blankj.utilcode.util.NetworkUtils;
import com.blankj.utilcode.util.PhoneUtils;
import com.blankj.utilcode.util.RomUtils;
import com.blankj.utilcode.util.ToastUtils;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.nio.charset.Charset;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
/**
 * 网络请求拦截器,添加公共参数
 */
public class LogInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        //以参数的方式添加
        //重定向URL
        @SuppressLint("MissingPermission") HttpUrl modifiedUrl = request.url().newBuilder()
                //添加的公共参数
                .addQueryParameter("deviceId", PhoneUtils.getDeviceId())
                .addQueryParameter("udid", "")
                .addQueryParameter("channel", "")
                .addQueryParameter("version", "")
                .addQueryParameter("brand", DeviceUtils.getManufacturer())//手机品牌
                .addQueryParameter("model", DeviceUtils.getModel())
//                .addQueryParameter("isWifi", NetworkUtils.isWifiConnected() ? "1" : "0")
                .addQueryParameter("ui", RomUtils.getRomInfo().getName())
                .addQueryParameter("uiVersion", RomUtils.getRomInfo().getVersion())
                .addQueryParameter("os", "android")
                .addQueryParameter("osVersion", DeviceUtils.getSDKVersionName())
                .addQueryParameter("isSimulator", DeviceUtils.isEmulator() ? "1" : "0")
                .addQueryParameter("imei", PhoneUtils.getIMEI())
                .addQueryParameter("oaid", "android")
                .addQueryParameter("androidId", DeviceUtils.getAndroidID())
//                .addQueryParameter("networkType", NetworkUtils.getNetworkType().name())
//                .addQueryParameter("mac", DeviceUtils.getMacAddress())
                .build();
        Request.Builder builder = request.newBuilder();
        //添加头部token
        String token = UserManager.getInstance().getToken();
        if (!TextUtils.isEmpty(token)) {
            builder.addHeader("Authorization", token);
        }
        Request newRequest = builder.url(modifiedUrl).build();
        Response response = chain.proceed(newRequest);
        //解决response.body().string();只能打印一次
        ResponseBody responseBody = response.body();
        BufferedSource source = responseBody.source();
        source.request(Long.MAX_VALUE); // Buffer the entire body.
        Buffer buffer = source.getBuffer();
        Charset UTF8 = Charset.forName("UTF-8");
        String string = buffer.clone().readString(UTF8);
        try {
            JSONObject jsonObject = new JSONObject(string);
            int code = jsonObject.getInt("code");
            if (code == BaseConfig.TOKEN_INVALID ) {
                ToastUtils.showShort("登录状态失效,请重新登录");
                UserManager.getInstance().clearToken();
                AppManager.getAppManager().finishAllActivity();
                AppManager.getAppManager().startActivityForName(BaseConfig.LOGIN_ACTIVITY);
            }
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
        return response;
    }
}
app_base/src/main/java/com/android/app_base/manager/AppManager.java
@@ -2,6 +2,7 @@
import android.app.Activity;
import android.content.Intent;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
@@ -93,6 +94,14 @@
        return ActivityUtils.startActivity(intent);
    }
    public void startActivityForName(String name) {
        if(TextUtils.isEmpty(name))return;
        try {
            startActivity(Class.forName(name));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    /**
     * 结束当前Activity(堆栈中最后一个压入的)
     */
app_base/src/main/java/com/android/app_base/manager/UserManager.java
New file
@@ -0,0 +1,34 @@
package com.android.app_base.manager;
import com.android.app_base.utils.SPUtils;
/**
 * @author Ljj
 * @date 2023.03.25. 19:50
 * @desc
 */
public class UserManager {
    private static UserManager instance;
    private UserManager(){
    }
    public static UserManager getInstance() {
        if (instance == null){
            instance = new UserManager();
        }
        return instance;
    }
    public void setToken(String token){
        SPUtils.getInstance("tokenInfo").put("token",token);
    }
    public void clearToken(){
        SPUtils.getInstance("tokenInfo").clear();
    }
    public String getToken(){
        return SPUtils.getInstance("tokenInfo").getString("token");
    }
}
app_base/src/main/java/com/android/app_base/utils/RxUtils.java
New file
@@ -0,0 +1,24 @@
package com.android.app_base.utils;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
/**
* @author Ljj
* @date 2023.03.24. 17:42
* @desc
*/public class RxUtils {
    public static <T> ObservableTransformer<T, T> schedulersTransformer() {
        return upstream -> upstream.subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }
}
app_base/src/main/java/com/android/app_base/utils/ScreenSizeUtils.java
@@ -89,6 +89,7 @@
        return 0;
    }
    //今日头条屏幕适配方案
    private static float sNoncompatDensity;
    private static float sNoncompatScaledDensity;
    public static void setCustomDensity(@NonNull Activity activity, @NonNull final Application application){
app_base/src/main/java/com/android/app_base/widget/CustomScrollView.java
File was deleted
app_base/src/main/res/anim/bottom_in_window.xml
New file
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="400"
        android:fromYDelta="100%p" />
</set>
app_base/src/main/res/anim/bottom_out_window.xml
New file
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="400"
        android:toYDelta="100%p" />
</set>
app_base/src/main/res/anim/ios_in_window.xml
New file
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:duration="300"
        android:fromXScale="1.1"
        android:fromYScale="1.1"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1.0"
        android:toYScale="1.0" />
    <alpha
        android:duration="300"
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />
</set>
app_base/src/main/res/anim/ios_out_window.xml
New file
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:duration="300"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1.1"
        android:toYScale="1.1" />
    <alpha
        android:duration="300"
        android:fromAlpha="1.0"
        android:toAlpha="0.0" />
</set>
app_base/src/main/res/anim/left_in_window.xml
New file
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="400"
        android:fromXDelta="-100%p" />
</set>
app_base/src/main/res/anim/left_out_window.xml
New file
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="400"
        android:toXDelta="-100%p" />
</set>
app_base/src/main/res/anim/pop_add_hide.xml
New file
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha
        android:duration="200"
        android:fromAlpha="1.0"
        android:toAlpha="0.0"/>
    <scale
        android:duration="200"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:pivotX="85%"
        android:pivotY="0%"
        android:toXScale="0"
        android:toYScale="0"/>
</set>
app_base/src/main/res/anim/pop_add_show.xml
New file
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha
        android:duration="200"
        android:fromAlpha="0.0"
        android:toAlpha="1.0"/>
    <scale
        android:duration="200"
        android:fromXScale="0"
        android:fromYScale="0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:pivotX="85%"
        android:pivotY="0%"
        android:toXScale="1.0"
        android:toYScale="1.0"/>
</set>
app_base/src/main/res/anim/popup_down.xml
New file
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="200">
    <scale
        android:fromXScale="1.0"
        android:fromYScale="0.0"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:toXScale="1.0"
        android:toYScale="1.0" />
</set>
app_base/src/main/res/anim/popup_up.xml
New file
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="200">
    <scale
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:toXScale="1.0"
        android:toYScale="0.0"/>
</set>
app_base/src/main/res/anim/right_in_window.xml
New file
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="400"
        android:fromXDelta="100%p" />
</set>
app_base/src/main/res/anim/right_out_window.xml
New file
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="400"
        android:toXDelta="100%p" />
</set>
app_base/src/main/res/anim/scale_in_window.xml
New file
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <scale
        android:duration="135"
        android:fromXScale="0.8"
        android:fromYScale="0.8"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1.05"
        android:toYScale="1.05" />
    <scale
        android:duration="105"
        android:fromXScale="1.05"
        android:fromYScale="1.05"
        android:pivotX="50%"
        android:pivotY="50%"
        android:startOffset="135"
        android:toXScale="0.95"
        android:toYScale="0.95" />
    <scale
        android:duration="60"
        android:fromXScale="0.95"
        android:fromYScale="0.95"
        android:pivotX="50%"
        android:pivotY="50%"
        android:startOffset="240"
        android:toXScale="1.0"
        android:toYScale="1.0" />
    <alpha
        android:duration="90"
        android:fromAlpha="0.0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toAlpha="1.0" />
</set>
app_base/src/main/res/anim/scale_out_window.xml
New file
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <scale
        android:duration="150"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="0.6"
        android:toYScale="0.6" />
    <alpha
        android:duration="150"
        android:fromAlpha="1.0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toAlpha="0.0" />
</set>
app_base/src/main/res/anim/top_in_window.xml
New file
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="400"
        android:fromYDelta="-100%p" />
</set>
app_base/src/main/res/anim/top_out_window.xml
New file
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="400"
        android:toYDelta="-100%p" />
</set>
app_base/src/main/res/layout/dialog_ui.xml
New file
@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView 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="@dimen/dp_240"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    app:cardBackgroundColor="#FFFFFF"
    app:cardCornerRadius="15dp"
    app:cardElevation="0px"
    >
    <LinearLayout
        android:id="@+id/ll_ui_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:paddingTop="@dimen/dp_20">
        <TextView
            android:id="@+id/tv_ui_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:textColor="#DE000000"
            android:textSize="20sp"
            android:textStyle="bold"
            tools:text="标题" />
        <TextView
            android:id="@+id/tv_content"
            android:padding="10dp"
            android:text="内容"
            android:gravity="center"
            android:textColor="#FF757575"
            android:textSize="16sp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
            <TextView
                android:id="@+id/tv_ui_cancel"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:focusable="true"
                android:gravity="center"
                android:paddingVertical="@dimen/dp_15"
                android:text="取消"
                android:textColor="#FFF83F39"
                android:textSize="@dimen/sp_14" />
            <androidx.appcompat.widget.AppCompatTextView
                android:id="@+id/tv_ui_confirm"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:focusable="true"
                android:gravity="center"
                android:paddingVertical="15dp"
                android:text="确定"
                android:textColor="#2B83DD"
                android:textSize="14sp" />
        </LinearLayout>
    </LinearLayout>
</androidx.cardview.widget.CardView>
app_base/src/main/res/values-sw1024dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw1280dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw1365dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw1440dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw240dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw320dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw360dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw384dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw392dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw400dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw410dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw411dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw432dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw480dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw533dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw592dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw600dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw640dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw662dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw720dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw768dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw800dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw811dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw820dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw960dp/dimens.xml
File was deleted
app_base/src/main/res/values-sw961dp/dimens.xml
File was deleted
app_base/src/main/res/values/arrts.xml
@@ -9,4 +9,5 @@
        <attr name="border_radius" format="dimension"/>
    </declare-styleable>
</resources>
app_base/src/main/res/values/styles.xml
New file
@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="pop_add">
        <item name="android:windowEnterAnimation">@anim/pop_add_show</item>
        <item name="android:windowExitAnimation">@anim/pop_add_hide</item>
    </style>
    <!-- 对话框默认样式 -->
    <style name="BaseDialogStyle" parent="Theme.AppCompat.DayNight.Dialog.Alert"><!-- @android:style/Theme.Dialog -->
        <!-- 无边框 -->
        <item name="android:windowFrame">@null</item>
        <!-- 浮在 Activity 之上 -->
        <item name="android:windowIsFloating">true</item>
        <!-- 半透明 -->
        <item name="android:windowIsTranslucent">true</item>
        <!-- 背景透明 -->
        <item name="android:windowBackground">@android:color/transparent</item>
        <!-- 遮盖层 -->
        <item name="android:backgroundDimEnabled">true</item>
        <!-- 无标题 -->
        <item name="android:windowNoTitle">true</item>
        <!-- 动画效果 -->
        <item name="android:windowEnterAnimation">@anim/scale_in_window</item>
        <item name="android:windowExitAnimation">@anim/scale_out_window</item>
        <!-- Base.Theme.AppCompat.Light.Dialog.Alert 特有的属性,用于指定默认宽度,这里需要禁用 -->
        <item name="android:windowMinWidthMajor">0dp</item>
        <item name="android:windowMinWidthMinor">0dp</item>
        <!-- 解决 ActionBar 占位导致 Dialog 无法全屏显示的问题 -->
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
        <!-- ActionMode 覆盖 Actionbar,不顶下来 -->
        <item name="windowActionModeOverlay">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <!-- 不感知敏感的切换 -->
        <!--<item name="android:configChanges">orientation|screenSize|keyboardHidden</item>-->
        <!-- 默认隐藏输入法 -->
        <!--<item name="android:windowSoftInputMode">stateHidden</item>-->
        <!-- Dialog 全屏显示 -->
        <!--<item name="android:windowFullscreen">true</item>-->
    </style>
    <!-- 缩放动画 -->
    <style name="ScaleAnimStyle" parent="android:Animation">
        <item name="android:windowEnterAnimation">@anim/scale_in_window</item>
        <item name="android:windowExitAnimation">@anim/scale_out_window</item>
    </style>
    <!-- ios 动画 -->
    <style name="IOSAnimStyle" parent="android:Animation">
        <item name="android:windowEnterAnimation">@anim/ios_in_window</item>
        <item name="android:windowExitAnimation">@anim/ios_out_window</item>
    </style>
    <!-- 顶部弹出动画 -->
    <style name="TopAnimStyle" parent="android:Animation">
        <item name="android:windowEnterAnimation">@anim/top_in_window</item>
        <item name="android:windowExitAnimation">@anim/top_out_window</item>
    </style>
    <!-- 底部弹出动画 -->
    <style name="BottomAnimStyle" parent="android:Animation">
        <item name="android:windowEnterAnimation">@anim/bottom_in_window</item>
        <item name="android:windowExitAnimation">@anim/bottom_out_window</item>
    </style>
    <!-- 左边弹出动画 -->
    <style name="LeftAnimStyle" parent="android:Animation">
        <item name="android:windowEnterAnimation">@anim/left_in_window</item>
        <item name="android:windowExitAnimation">@anim/left_out_window</item>
    </style>
    <!-- 右边弹出动画 -->
    <style name="RightAnimStyle" parent="android:Animation">
        <item name="android:windowEnterAnimation">@anim/right_in_window</item>
        <item name="android:windowExitAnimation">@anim/right_out_window</item>
    </style>
</resources>