riku
2021-02-25 e102578ebfc95c27aeb13dce13fb82af53a2bead
1. 新增夜间施工查询界面
2. 新增夜间施工管理统计界面
已修改37个文件
已删除2个文件
已添加52个文件
4606 ■■■■ 文件已修改
app/build.gradle 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/AndroidManifest.xml 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/CommonApplication.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/bean/entity/MediaFileCache.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/business/widgettype2/HomeFragment_comptent.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/business/widgettype3/HomeFragment_scene.java 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/common/database/DbFlatMapUtil.kt 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/common/net/FlatMapUtil.kt 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/common/net/ResultObserver.kt 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/httpservice/NightWorkService.kt 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/model/bean/BaseResponse.kt 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/model/bean/NightWorkFileVo.kt 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/model/bean/NightWorkSummary.kt 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/module/base/BaseActivity.kt 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/module/base/BaseFragment.kt 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/module/base/BaseFragmentActivity.kt 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/module/base/BaseFragmentListActivity.kt 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/module/base/ToolbarSetInterface.kt 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/module/common/FileBrowseViewModel.kt 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/module/common/FileDownloadFragment.kt 170 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/module/common/OfficeFileManageActivity.kt 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/module/common/OfficeFileReadFragment.kt 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/module/inspection/MenuCameraActivity.kt 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/module/nightwork/NightWorkManageActivity.kt 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/module/nightwork/NightWorkRecordActivity.kt 161 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/module/nightwork/NightWorkViewModel.kt 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/repository/MediaFileRepository.kt 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/repository/NightWorkRepository.kt 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/repository/dao/MediaFileDao.kt 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/util/CommonUtils.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/util/Constant.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/util/CrashHandler.java 198 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/util/DateUtil.kt 346 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/util/DialogUtil2.kt 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/util/SystemServiceUtils.kt 49 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/util/download/UpDownloadUtil.kt 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/util/file/FileUtils.kt 376 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/util/tbs/Tbs.kt 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/view/recyclerview/DataLoadInterface.kt 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/view/recyclerview/DataLoadModel.kt 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/view/recyclerview/EmptyLoadMoreView.kt 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/view/recyclerview/RecyclerViewPanel.kt 337 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/cn/flightfeather/thirdapp/view/recyclerview/RecyclerViewSetInterface.kt 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/ping/greendao/gen/DaoMaster.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/ping/greendao/gen/DaoSession.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/ping/greendao/gen/MediaFileCacheDao.java 157 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/anim/left_enter_3.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/anim/left_exit_3.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/anim/right_enter_2.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/anim/right_exit_2.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable/selector_bg_green_or_yellow.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/drawable/shape_bg_gradient_2.xml 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/activity_fragment_container.xml 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/activity_night_work.xml 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/activity_night_work_manage.xml 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/dialog_scene_list.xml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/fragment_file_download.xml 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/fragment_home_competent.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/fragment_home_pollution_scene.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/fragment_office_file.xml 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/function_card4_scene.xml 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/function_card5_competent.xml 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/function_card5_scene.xml 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/item_night_work.xml 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/item_night_work_2.xml 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/item_night_work_3.xml 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/item_night_work_no_more.xml 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/item_scene_new_task.xml 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/item_scene_task.xml 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/layout_empty_load_more.xml 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/layout_empty_view.xml 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/layout_load_fail_view.xml 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/layout_loading.xml 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/layout_loading_view.xml 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/layout_night_work_empty.xml 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/layout_recycler_view_refresh.xml 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/layout_toolbar_2.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/recycler_item_section_head.xml 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/tool_bar_layout.xml 103 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/mipmap-hdpi/ic_developing.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/mipmap-mdpi/ic_developing.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/mipmap-xhdpi/file_ic_detail_excel.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/mipmap-xhdpi/file_ic_detail_pdf.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/mipmap-xhdpi/ic_developing.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/mipmap-xhdpi/ic_share.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/mipmap-xxhdpi/ic_developing.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/mipmap-xxxhdpi/ic_developing.png 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/values/strings.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/values/styles.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/test/java/cn/flightfeather/thirdapp/Test.kt 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
build.gradle 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/build.gradle
@@ -13,12 +13,17 @@
        applicationId "cn.flightfeather.thirdapp"
        minSdkVersion 19
        targetSdkVersion 28
        versionCode 25
        versionName "1.1.14.08"
        versionCode 27
        versionName "1.1.14.10"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        renderscriptTargetApi 25
        renderscriptSupportModeEnabled true
        multiDexEnabled true
        ndk {
            //x5 å…¼å®¹64位手机
            abiFilters 'armeabi', 'armeabi-v7a', 'x86', 'mips'
        }
    }
    buildTypes {
        release {
@@ -45,7 +50,7 @@
}
greendao {
    schemaVersion 12
    schemaVersion 13
    daoPackage 'com.ping.greendao.gen'
    targetGenDir 'src/main/java'
}
@@ -118,6 +123,19 @@
    //kotlin plugin
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "org.jetbrains.anko:anko:$anko_version"
    //腾讯TBS文件浏览服务
    api 'com.tencent.tbs.tbssdk:sdk:43697'
    //文件下载
    implementation "com.liulishuo.okdownload:okdownload:${file_download_version}"
    implementation "com.liulishuo.okdownload:sqlite:${file_download_version}"
    implementation "com.liulishuo.okdownload:okhttp:${file_download_version}"
    implementation "com.liulishuo.okdownload:ktx:${file_download_version}"
    implementation "com.liulishuo.okdownload:filedownloader:${file_download_version}"
    //圆形进度条
    implementation "com.mikhaellopez:circularprogressbar:${progressbar_version}"
}
repositories {
    mavenCentral()
app/src/main/AndroidManifest.xml
@@ -56,7 +56,7 @@
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="cn.flightfeather.thirdapp.fileProvider"
            android:authorities="@string/file_provide"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
@@ -191,6 +191,15 @@
            android:name=".module.task.SceneDetailActivity"
            android:theme="@style/AppTheme.NoActionBar" />
        <activity
            android:name=".module.nightwork.NightWorkRecordActivity"
            android:theme="@style/AppTheme.NoActionBar" />
        <activity
            android:name=".module.nightwork.NightWorkManageActivity"
            android:theme="@style/AppTheme.NoActionBar" />
        <activity
            android:name=".module.common.OfficeFileManageActivity"
            android:theme="@style/AppTheme.NoActionBar" />
        <activity
            android:name=".module.inspection.MenuGradeActivity"
            android:screenOrientation="portrait"
            android:theme="@style/AppTheme"/>
app/src/main/java/cn/flightfeather/thirdapp/CommonApplication.java
@@ -17,6 +17,7 @@
import cn.flightfeather.thirdapp.bean.entity.Userinfo;
import cn.flightfeather.thirdapp.common.net.RetrofitFactory;
import cn.flightfeather.thirdapp.util.crashreport.MyCrashHandler;
import cn.flightfeather.thirdapp.util.tbs.Tbs;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
@@ -52,6 +53,9 @@
        //初始化网络请求
        RetrofitFactory.init(this);
        //x5内核初始化
        Tbs.Companion.init(this);
        if (instance == null) {
            instance = this;
        }
app/src/main/java/cn/flightfeather/thirdapp/bean/entity/MediaFileCache.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,56 @@
package cn.flightfeather.thirdapp.bean.entity;
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Generated;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Property;
/**
 * @author riku
 * Date: 2020/4/18
 */
@Entity
public class MediaFileCache {
    @Id(autoincrement = true)
    private Long id;
    @Property
    private String url;
    @Property
    private String path;
    @Property
    private String thumbnailPath;
    @Generated(hash = 554333244)
    public MediaFileCache(Long id, String url, String path, String thumbnailPath) {
        this.id = id;
        this.url = url;
        this.path = path;
        this.thumbnailPath = thumbnailPath;
    }
    @Generated(hash = 545339127)
    public MediaFileCache() {
    }
    public Long getId() {
        return this.id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getUrl() {
        return this.url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public String getPath() {
        return this.path;
    }
    public void setPath(String path) {
        this.path = path;
    }
    public String getThumbnailPath() {
        return this.thumbnailPath;
    }
    public void setThumbnailPath(String thumbnailPath) {
        this.thumbnailPath = thumbnailPath;
    }
}
app/src/main/java/cn/flightfeather/thirdapp/business/widgettype2/HomeFragment_comptent.java
@@ -2,11 +2,13 @@
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.support.constraint.ConstraintLayout;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
@@ -43,6 +45,7 @@
import java.util.List;
import java.util.Map;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
import cn.flightfeather.thirdapp.CommonApplication;
@@ -58,6 +61,7 @@
import cn.flightfeather.thirdapp.bean.vo.TaskVo;
import cn.flightfeather.thirdapp.httpservice.ProblemListService;
import cn.flightfeather.thirdapp.httpservice.TaskService;
import cn.flightfeather.thirdapp.module.nightwork.NightWorkManageActivity;
import cn.flightfeather.thirdapp.util.ChartGenerator;
import cn.flightfeather.thirdapp.util.CommonUtils;
import cn.flightfeather.thirdapp.util.Constant;
@@ -324,6 +328,7 @@
        viewHolder1.initViewHolder1();
        viewHolder2.initViewholder2();
        viewHolder3.initViewHolder3();
        viewHolder5.initViewHolder5();
    }
@@ -1186,38 +1191,21 @@
        }
    }
    @BindView(R.id.cl_night_work)
    ConstraintLayout cl_night_work;
    public class ViewHolder5  {
//        ImageView task1,task2;
//        TextView task1date, task1name,task2date, task2name;
        ViewHolder5(Bundle savedInstanceState, View itemView) {
//            task2 = (ImageView) itemView.findViewById(R.id.iv_tody_task2);
//            task1date = (TextView) itemView.findViewById(R.id.tv_tody_task1date);
//            task1name = (TextView) itemView.findViewById(R.id.tv_tody_task1name);
//            task2date = (TextView) itemView.findViewById(R.id.tv_tody_task2date);
//            task2name = (TextView) itemView.findViewById(R.id.tv_tody_task2name);
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
//                    mRecyclerViewAdapter.addData(0);
                }
            });
            itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View view) {
//                    mRecyclerViewAdapter.addData(0);
                    return true;
                }
            });
        }
        void refreshView() {
//            task1.setBackgroundResource(R.drawable.icon_tody_task_1);
//            task2.setBackgroundResource(R.drawable.icon_tody_task_2);
//            task1date.setTitle(new Date().toString());
//            task2date.setTitle(new Date().toString());
//            task1name.setTitle("任务名称任务名称任务名称");
//            task2name.setTitle("任务名称任务名称任务名称");
            initViewHolder5();
        }
        private void initViewHolder5() {
            cl_night_work.setOnClickListener(v -> startActivity(new Intent(getContext(), NightWorkManageActivity.class)));
        }
    }
app/src/main/java/cn/flightfeather/thirdapp/business/widgettype3/HomeFragment_scene.java
@@ -1,6 +1,7 @@
package cn.flightfeather.thirdapp.business.widgettype3;
import android.arch.lifecycle.ViewModelProviders;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
@@ -11,7 +12,6 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -32,9 +32,7 @@
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import butterknife.BindView;
import butterknife.ButterKnife;
@@ -42,24 +40,23 @@
import butterknife.Unbinder;
import cn.flightfeather.thirdapp.CommonApplication;
import cn.flightfeather.thirdapp.R;
import cn.flightfeather.thirdapp.bean.entity.Domainitem;
import cn.flightfeather.thirdapp.bean.entity.Scense;
import cn.flightfeather.thirdapp.bean.entity.Subtask;
import cn.flightfeather.thirdapp.bean.vo.InspectionInfoVo;
import cn.flightfeather.thirdapp.bean.vo.InspectionVo;
import cn.flightfeather.thirdapp.bean.vo.RankVo;
import cn.flightfeather.thirdapp.bean.vo.TaskVo;
import cn.flightfeather.thirdapp.common.net.ResultCallBack;
import cn.flightfeather.thirdapp.dataanalysis.AnalysisOverViewFragment;
import cn.flightfeather.thirdapp.httpservice.InspectionService;
import cn.flightfeather.thirdapp.httpservice.TaskService;
import cn.flightfeather.thirdapp.model.bean.NightWorkFileVo;
import cn.flightfeather.thirdapp.module.nightwork.NightWorkRecordActivity;
import cn.flightfeather.thirdapp.module.nightwork.NightWorkViewModel;
import cn.flightfeather.thirdapp.util.Constant;
import cn.flightfeather.thirdapp.util.DateFormatter;
import cn.flightfeather.thirdapp.util.ScreenUtils;
import cn.flightfeather.thirdapp.view.MyScrollView;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
/**
 * A simple {@link Fragment} subclass.
@@ -86,33 +83,19 @@
    private ViewHolder2 viewHolder2;
    private ViewHolder3 viewHolder3;
    private ViewHolder4 viewHolder4;
    private ViewHolder5 viewHolder5;
    //ViewHolder1(今日任务)
    private Map<String, List<TaskVo>> taskAllMapList = new HashMap<>();//Map<时间, æ‰€æœ‰ä»»åŠ¡ï¼ˆé¡¶å±‚ä»»åŠ¡ã€æ—¥ä»»åŠ¡ã€å­ä»»åŠ¡ï¼‰>
    private ArrayList<Subtask> mSubtaskList = new ArrayList<>();
    private ArrayList<Subtask> subtaskListOfUser = new ArrayList<>();
    private ArrayList<TaskVo> mDayTaskList = new ArrayList<>();
    private Calendar calendarCurrent;
    private String mCurYearMonth;
    private String mToday;
    private boolean requestAgain;
    private Retrofit mRetrofit;
    private boolean firstLoad = true;
    private final int VISIBLENUM = 2;//今日任务显示最少的任务数
    private Boolean visibility = false;
    private Subtask subtask;
    private InspectionVo inspectionVo;
    //当前场景类型
    private String curSceneType = "1";
    private List<Domainitem> sceneTypeData = new ArrayList<>();//场景类型
    //状态栏与标题栏的高度和为滑动组件悬停的最大高度
    private int topHeight;
    //是否在切换回来时刷新
    private boolean isUnHiddenRefresh;
    private Unbinder unbinder;
    private NightWorkViewModel viewModel;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        viewModel = ViewModelProviders.of(this).get(NightWorkViewModel.class);
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_home_pollution_scene, container, false);
        unbinder = ButterKnife.bind(this, view);
@@ -161,26 +144,14 @@
    @Override
    public void onStart() {
        super.onStart();
        int statusBarHeight = ScreenUtils.getStatusHeight(getActivity());//状态栏高度
        int titleBarHeight = getActivity().getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();//标题栏高度
        topHeight = titleBarHeight + statusBarHeight;
    }
    public HomeFragment_scene() {
        // Required empty public constructor
    }
    MyScrollView sv_home_base;
    LinearLayout ll_weather_detail;
    private void initData(){
        application = (CommonApplication) getActivity().getApplication();
        mRetrofit = application.getRetrofit();
        Date now = Calendar.getInstance().getTime();
        mCurYearMonth = DateFormatter.YearMonthFormat.format(now);
        mToday = DateFormatter.dateFormat2.format(now);
    }
    private void initUI(View view) {
@@ -210,10 +181,13 @@
        viewHolder2 = new ViewHolder2(savedInstanceState, sv_home_page);
        viewHolder3 = new ViewHolder3(savedInstanceState, sv_home_page);
        viewHolder4 = new ViewHolder4(savedInstanceState, sv_home_page);
        viewHolder5 = new ViewHolder5();
        viewHolder1.initViewHolder1();
        viewHolder1.refreshView();
        viewHolder2.refreshView();
//        viewHolder3.initViewHolder3();
        viewHolder5.init();
    }
@@ -712,9 +686,45 @@
    }
    //</editor-fold>
    @BindView(R.id.cl_night_work) ConstraintLayout cl_night_work;
    @BindView(R.id.txt_news) TextView txt_news;
    public class ViewHolder5 {
        void init() {
            cl_night_work.setOnClickListener(v -> startActivity(new Intent(getContext(), NightWorkRecordActivity.class)));
            viewModel.getNightWorkFile(false, 1, new ResultCallBack<List<NightWorkFileVo>>(){
                @Override
                public void onCacheSuccess(@org.jetbrains.annotations.Nullable List<NightWorkFileVo> result) {
                }
                @Override
                public void onPage(int current, int total) {
                }
                @Override
                public void onSuccess(@org.jetbrains.annotations.Nullable List<NightWorkFileVo> result) {
                    if (result == null || result.isEmpty()) {
                        txt_news.setText("暂无新许可证");
                    } else {
                        txt_news.setText("有新许可证下发,请查看");
                    }
                }
                @Override
                public void onFailure() {
                    txt_news.setText("网络连接失败,请退出重试");
                }
            });
        }
    }
    //<editor-fold desc="点击事件">
    @OnClick({R.id.text_goto_change, R.id.image_goto_change})
    @OnClick({R.id.card_change_problem, R.id.card_changed_problem})
    void OnClick() {
        Intent intent = new Intent("cn.flightfeather.thirdapp.broadcasereceiver.MainReceiver");
        intent.setAction(Constant.GOTO_INSPECTION_FRAGMENT);
app/src/main/java/cn/flightfeather/thirdapp/common/database/DbFlatMapUtil.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,131 @@
package cn.flightfeather.thirdapp.common.database
import com.ping.greendao.gen.DaoSession
import org.greenrobot.greendao.AbstractDao
import retrofit2.Response
/**
 * @author riku
 * Date: 2019/4/25
 * æ•°æ®åº“操作步骤抽象
 */
/**
 * å‘数据库保存实体信息
 * @param <T> Entity type
 * @param <K> Primary key (PK) type; use Void if entity does not have exactly one PK
 */
fun <E, K> flatMapDbSaveResult(dao: AbstractDao<E, K>, listener: FlatSaveInterface<E, K>): Boolean {
    val results = listener.onQuery(dao)
    try {
        return if (results.isEmpty()) {
            val entities = listener.onInsert()
            entities.forEach {
                dao.insert(it)
            }
            true
        } else {
            listener.onUpdate(results)
            results.forEach {
                dao.update(it)
            }
            true
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
    return false
}
interface FlatSaveInterface<E, K> {
    //保存前的步骤,查看要保存的数据是否存在
    fun onQuery(dao: AbstractDao<E, K>): List<E>
    //数据已存在,选择更新
    fun onUpdate(list: List<E>)
    //数据不存在,插入新的保存实体
    fun onInsert(): List<E>
}
/**
 * å‘数据库保存网络获取的实体信息
 */
fun <E, K, T> FlatMapDbSaveResult(dao: AbstractDao<E, K>, response: Response<T>, listener: FlatSaveInterface<E, K>): Boolean {
    if (response.isSuccessful) {
        val results = listener.onQuery(dao)
        try {
            return if (results.isEmpty()) {
                val entities = listener.onInsert()
                entities.forEach {
                    dao.insert(it)
                }
                true
            } else {
                listener.onUpdate(results)
                results.forEach {
                    dao.update(it)
                }
                true
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
    return false
}
/**
 * èŽ·å–æ•°æ®åº“ä¿å­˜çš„åˆ—è¡¨ä¿¡æ¯
 */
fun<E, T, R> FlatMapDbReadList(daoSession: DaoSession, listener:FlatDbReadConversionListInterface<E, T, R>): ArrayList<R> {
    val result = listener.onQuery(daoSession)
    val list = ArrayList<T>()
    if (result.isNotEmpty()) {
        result.forEach {
            list.addAll(listener.onJson(it))
        }
    }
    val dataList = ArrayList<R>()
    list.forEach {
        dataList.add(listener.onConversion(it))
    }
    return dataList
}
//用于数据库中,需要将存储的字段按Json格式转换
interface FlatDbReadConversionListInterface<E,T, R> {
    //查询语句
    fun onQuery(d: DaoSession): List<E>
    //存储的Json转换为需要的实体
    fun onJson(e: E): List<T>
    //如果使用dataBinding, åˆ™å¯ä»¥è½¬æ¢ä¸ºå¯¹åº”的实体;或用于前端展示与网络传输的数据实体结构不同的情况
    fun onConversion(t: T): R
}
/**
 * èŽ·å–æ•°æ®åº“ä¿å­˜çš„åˆ—è¡¨ä¿¡æ¯
 */
fun<E, T, R> FlatMapDbReadList(daoSession: DaoSession, listener:FlatDbReadConversionObjectInterface<E, T, R>): ArrayList<R> {
    val result = listener.onQuery(daoSession)
    val list = ArrayList<T>()
    if (result.isNotEmpty()) {
        result.forEach {
            list.add(listener.onBean(it))
        }
    }
    val dataList = ArrayList<R>()
    list.forEach {
        dataList.add(listener.onConversion(it))
    }
    return dataList
}
//用于数据库中,需要将完整的表转换为对应的bean实体
interface FlatDbReadConversionObjectInterface<E,T, R> {
    //查询语句
    fun onQuery(d: DaoSession): List<E>
    //存储的Json转换为需要的实体
    fun onBean(e: E): T
    //如果使用dataBinding, åˆ™å¯ä»¥è½¬æ¢ä¸ºå¯¹åº”的实体;或用于前端展示与网络传输的数据实体结构不同的情况
    fun onConversion(t: T): R
}
app/src/main/java/cn/flightfeather/thirdapp/common/net/FlatMapUtil.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,76 @@
package cn.flightfeather.thirdapp.common.net
import io.reactivex.ObservableSource
import io.reactivex.Observer
import retrofit2.Response
/**
 * @author riku
 * Date: 2019/4/29
 */
/**
 * å°†Response转化为实体数据
 */
class FlatMapResponse2Result<T>(private val response: Response<T>) : ObservableSource<T> {
    override fun subscribe(observer: Observer<in T?>) {
        if (response.isSuccessful) {
            observer.onNext(response.body())
        } else {
            observer.onError(Throwable(response.code().toString(), Throwable(response.errorBody().toString())))
        }
    }
}
/**
 * å°†å®žä½“数据转化为Response
 */
class FlatMapResult2Response<T>(private val t: T) : ObservableSource<Response<T>> {
    override fun subscribe(observer: Observer<in Response<T>?>) {
        observer.onNext(Response.success(t))
    }
}
/**
 * ä¸æŸå¤±header的情况下转化Response中的 åˆ—表 æ•°æ®
 */
class FlatMapResponse2ResponseResult<T>(private val response: Response<T>, private val conversionCallBack: FlatConversionInterface<T>) :
    ObservableSource<Response<ArrayList<Any>>> {
    override fun subscribe(observer: Observer<in Response<ArrayList<Any>>>) {
        if (response.isSuccessful) {
            val result = conversionCallBack.onConversion(response.body())
            observer.onNext(Response.success(result, response.headers()))
        } else {
            observer.onError(Throwable(response.code().toString(), Throwable(response.errorBody().toString())))
        }
    }
}
/**
 * ä¸æŸå¤±header的情况下转化Response中的 å®žä½“ æ•°æ®
 */
class FlatMapResponse2ResponseObject<T, R>(private val response: Response<T>, private val conversionCallBack: FlatConversionObjectInterface<T, R>) :
    ObservableSource<Response<R>> {
    override fun subscribe(observer: Observer<in Response<R>>) {
        if (response.isSuccessful) {
            val result = conversionCallBack.onConversion(response.body())
            observer.onNext(Response.success(result, response.headers()))
        } else {
            observer.onError(Throwable(response.code().toString(), Throwable(response.errorBody().toString())))
        }
    }
}
interface FlatConversionInterface<T> {
    fun onConversion(t: T?): ArrayList<Any>
}
interface FlatConversionObjectInterface<T, R> {
    fun onConversion(t: T?): R
}
app/src/main/java/cn/flightfeather/thirdapp/common/net/ResultObserver.kt
@@ -1,6 +1,7 @@
package cn.flightfeather.thirdapp.common.net
import android.accounts.NetworkErrorException
import cn.flightfeather.thirdapp.model.bean.BaseResponse
import io.reactivex.Observer
import io.reactivex.disposables.Disposable
import retrofit2.Response
@@ -66,8 +67,11 @@
        var currentPage = -1
        var totalPage = -1
        try {
            currentPage = response.headers().get("currentPage")?.toInt() ?: -1
            totalPage = response.headers().get("totalPage")?.toInt() ?: -1
            val body = response.body()
            if (body is BaseResponse<*>) {
                currentPage = body.head?.page ?: -1
                totalPage = body.head?.totalPage ?: -1
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
app/src/main/java/cn/flightfeather/thirdapp/httpservice/NightWorkService.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,46 @@
package cn.flightfeather.thirdapp.httpservice
import cn.flightfeather.thirdapp.model.bean.BaseResponse
import cn.flightfeather.thirdapp.model.bean.NightWorkFileVo
import cn.flightfeather.thirdapp.model.bean.NightWorkSummary
import cn.flightfeather.thirdapp.util.Constant
import io.reactivex.Observable
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Query
/**
 * @author riku
 * Date: 2020/12/29
 */
interface NightWorkService {
    @GET("nightwork/record/all")
    fun getRecord(
//            @Query("cityCode") cityCode: String?,
            @Query("districtCode") districtCode: String,
            @Query("page") page: Int,
            @Query("perPage") perPage: Int = Constant.PAGE_SIZE
    ): Observable<Response<BaseResponse<List<NightWorkFileVo>>>>
    @GET("nightwork/record")
    fun getNightWorkFile(
            @Query("userId") userId: String,
            @Query("isRead") isRead: Boolean? = null,
            @Query("page") page: Int,
            @Query("perPage") perPage: Int = Constant.PAGE_SIZE
    ): Observable<Response<BaseResponse<List<NightWorkFileVo>>>>
    @POST("nightwork/sign")
    fun signFile(
            @Query("userId") userId: String,
            @Query("fileNum") fileNum: String,
            @Query("id") id: Int
    ): Observable<Response<BaseResponse<Int>>>
    @GET("nightwork/summary")
    fun getSummary(
//            @Query("cityCode") cityCode: String?,
            @Query("districtCode") districtCode: String
    ): Observable<Response<BaseResponse<NightWorkSummary>>>
}
app/src/main/java/cn/flightfeather/thirdapp/model/bean/BaseResponse.kt
@@ -8,5 +8,11 @@
data class BaseResponse<T>(
        val success: Boolean,
        val message: String,
        val head: DataHead? = null,
        val data: T?
)
data class DataHead(
        var page: Int = 1,
        var totalPage: Int = 1
)
app/src/main/java/cn/flightfeather/thirdapp/model/bean/NightWorkFileVo.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,54 @@
package cn.flightfeather.thirdapp.model.bean
import com.google.gson.annotations.SerializedName
import java.util.*
/**
 * @author riku
 * Date: 2020/12/29
 * å·¥åœ°å¤œé—´æ–½å·¥æ–‡ä»¶
 */
class NightWorkFileVo {
    @SerializedName("ncId")
    var id: Int? = null
    @SerializedName("ncNum")
    var num: String? = null
    @SerializedName("ncItemName")
    var itemName: String? = null
    @SerializedName("ncItemUnit")
    var itemUnit: String? = null
    @SerializedName("ncProvinceCode")
    var pCode: String? = null
    @SerializedName("ncProvinceName")
    var pName: String? = null
    @SerializedName("ncCityCode")
    var cCode: String? = null
    @SerializedName("ncCityName")
    var cName: String? = null
    @SerializedName("ncDistrictCode")
    var dCode: String? = null
    @SerializedName("ncDistrictName")
    var dName: String? = null
    @SerializedName("ncConstructionUnit")
    var constructionUnit: String? = null
    @SerializedName("ncPerson")
    var person: String? = null
    @SerializedName("ncApplyContent")
    var applyContent: String? = null
    @SerializedName("ncStartDate")
    var startDate: Date? = null
    @SerializedName("ncEndDate")
    var endDate: Date? = null
    @SerializedName("ncFileName")
    var fileName: String? = null
    @SerializedName("ncCreateTime")
    var createTime: Date? = null
    @SerializedName("ncUrl")
    var url: String? = null
    @SerializedName("ncUserId")
    var userId: String? = null
    @SerializedName("ncSceneId")
    var sceneId: String? = null
    @SerializedName("ncRead")
    var isRead: Boolean? = null
}
app/src/main/java/cn/flightfeather/thirdapp/model/bean/NightWorkSummary.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
package cn.flightfeather.thirdapp.model.bean
/**
 * @author riku
 * Date: 2021/2/24
 */
class NightWorkSummary {
    //文件总数
    val totalCount: Int = 0
    //已签收文件数
    var signedCount: Int = 0
}
app/src/main/java/cn/flightfeather/thirdapp/module/base/BaseActivity.kt
@@ -1,6 +1,7 @@
package cn.flightfeather.thirdapp.module.base
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
@@ -12,6 +13,7 @@
import android.support.v7.widget.Toolbar
import android.view.MenuItem
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import com.bumptech.glide.Glide
import com.bumptech.glide.util.Util
import io.reactivex.disposables.Disposable
@@ -78,3 +80,14 @@
inline fun FragmentManager.inTransaction(func: FragmentTransaction.() -> FragmentTransaction) {
    beginTransaction().func().commit()
}
/**
 * æ‹“展fragment中隐藏软键盘的方法
 */
fun Activity.hideKeyboard() {
    this.window?.peekDecorView()?.let {
        val inputManager =
                this.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
        inputManager.hideSoftInputFromWindow(it.windowToken, 0)
    }
}
app/src/main/java/cn/flightfeather/thirdapp/module/base/BaseFragment.kt
@@ -3,12 +3,18 @@
import android.app.Activity
import android.content.Context
import android.graphics.drawable.Drawable
import android.os.Build
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v7.widget.Toolbar
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.TextView
import cn.flightfeather.thirdapp.R
import kotlinx.android.synthetic.main.tool_bar_layout.*
import org.greenrobot.eventbus.EventBus
/**
@@ -16,20 +22,45 @@
 * 2019.7.29
 * åŸºç±»fragment
 */
abstract class BaseFragment : Fragment() {
abstract class BaseFragment : Fragment(), ToolbarSetInterface {
    var mContext: Context? = null
    var mRootView: ViewGroup? = null
    private lateinit var contentView: View
    override fun getToolBar(): Toolbar = contentView.findViewById(R.id.tool_bar)
    override fun toolbarEnabled(): Boolean =false
    override fun getHeadIcon(): View = contentView.findViewById(R.id.img_back)
    override fun onHeadIconClick() { activity?.onBackPressed() }
    override fun getMyTitleTextView(): TextView? = contentView.findViewById(R.id.tv_main_title)
    override fun getTitleEnabled(): Boolean = true
    override fun getTitleText(): String? = ""
    override fun getMenus(): List<View>? = listOf(contentView.findViewById(R.id.img_menu_1), contentView.findViewById(R.id.img_menu_2), contentView.findViewById(R.id.img_menu_3))
    override fun getMenuVisibility(): List<Int?> = listOf(View.VISIBLE, View.VISIBLE, View.VISIBLE)
    override fun getMenuRes(): List<Drawable?> = listOf(null)
    override fun getMenuClickListener(): List<View.OnClickListener?> = listOf(null)
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
    ): View? {
        mRootView = container
        val view = inflater.inflate(getLayoutId(), container, false)
        contentView = inflater.inflate(getLayoutId(), container, false)
        onCreateView()
        return view
        initToolbar()
        return contentView
    }
    override fun onAttach(context: Context?) {
@@ -51,8 +82,23 @@
        }
    }
    open fun onBackPressed(onActivityBack: () -> Unit) {
        onActivityBack()
    }
    open fun onCreateView() = Unit
    abstract fun getLayoutId(): Int
    /**
     * æ‹“展fragment中隐藏软键盘的方法
     */
    fun Fragment.hideKeyboard() {
        this.activity?.window?.peekDecorView()?.let {
            val inputManager =
                    this.activity?.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            inputManager.hideSoftInputFromWindow(it.windowToken, 0)
        }
    }
}
app/src/main/java/cn/flightfeather/thirdapp/module/base/BaseFragmentActivity.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
package cn.flightfeather.thirdapp.module.base
import android.support.v7.widget.Toolbar
import cn.flightfeather.thirdapp.R
import kotlinx.android.synthetic.main.tool_bar_layout.*
/**
 * @author riku
 * Date: 2019/5/8
 */
abstract class BaseFragmentActivity:BaseFragmentListActivity() {
    override fun getFragmentList(): ArrayList<BaseFragment>? = if (getInitFragment() == null) {
        null
    } else {
        arrayListOf(getInitFragment()!!)
    }
//    override fun getToolBar(): Toolbar? = tool_bar
    override fun getFragmentContainerID(): Int = R.id.container
    override fun getLayoutId(): Int = R.layout.activity_fragment_container
    abstract fun getInitFragment(): BaseFragment?
    override fun onBackPressed() {
        hideKeyboard()
        if (fragments?.isNotEmpty() == true) {
            fragments?.last()?.onBackPressed {
                if (fragments?.size ?: 0 > 1) {
                    navigateBack()
                } else {
                    super.onBackPressed()
                }
            }
        } else {
            super.onBackPressed()
        }
    }
}
app/src/main/java/cn/flightfeather/thirdapp/module/base/BaseFragmentListActivity.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,106 @@
package cn.flightfeather.thirdapp.module.base
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.support.v4.app.FragmentTransaction
import android.support.v7.widget.Toolbar
import cn.flightfeather.thirdapp.R
/**
 * @author riku
 * Date: 2019/4/16
 * åŒ…含fragment的基类activity
 */
abstract class BaseFragmentListActivity : BaseActivity(){
    var lastFragmentPos = -1
    var fragments: ArrayList<BaseFragment>? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        fragments = getFragmentList()
        initToolbar()
        navigateTo(0)
    }
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
//        fragments?.forEach { it.onActivityResult(requestCode, resultCode, data) }
    }
    private fun initToolbar() {
//        getToolBar()?.let { setSupportActionBar(it)}
    }
    //fragment切换
    @SuppressLint("CommitTransaction")
    open fun navigateTo(p: Int, reStart: Boolean = false, transaction: FragmentTransaction? = null) {
        fragments?.let {
            if (p >= it.size || p < 0) return
            (transaction ?: supportFragmentManager.beginTransaction())
                .apply {
                    if (lastFragmentPos >= 0 && lastFragmentPos < it.size) hide(it[lastFragmentPos])
                    if (!it[p].isAdded) {
                        add(getFragmentContainerID(), it[p], it[p].javaClass.simpleName)
                    }
                    show(it[p])
                }.commitAllowingStateLoss()
            lastFragmentPos = p
        }
    }
    @SuppressLint("CommitTransaction")
    fun navigateToNext(fragment: BaseFragment) {
        fragments?.add(fragment)
        if (fragments?.size ?: 0 > 1) {
            navigateTo((fragments?.size ?: 0) - 1,
                transaction = supportFragmentManager.beginTransaction().apply {
                    setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
                    setCustomAnimations(R.anim.right_enter_2, R.anim.left_exit_3)
                })
        }
    }
    @SuppressLint("CommitTransaction")
    fun navigateBack() {
        if (fragments?.size ?: 0 > 1) {
            navigateTo((fragments?.size ?: 0) - 2,
                transaction = supportFragmentManager.beginTransaction().apply {
                    setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE)
                    setCustomAnimations(R.anim.left_enter_3, R.anim.right_exit_2)
                })
        }
        fragments?.removeAt(fragments?.size!! - 1)
    }
    /**
     * å°†fragment ä»Žå¯¼èˆªæ ˆä¸­åˆ é™¤
     */
    fun deleteFragmentFromNavigation(fragment: BaseFragment) {
        fragments?.let {list ->
            if (list.contains(fragment)) {
                var index = 0
                for (i in 0 until list.size) {
                    if (list[i] == fragment) {
                        break
                    }
                    index++
                }
                fragments?.remove(fragment)
                if (lastFragmentPos >= index) {
                    lastFragmentPos -= 1
                }
            }
        }
    }
    abstract fun getFragmentList(): ArrayList<BaseFragment>?
    abstract fun getFragmentContainerID(): Int
//    abstract fun getToolBar(): Toolbar?
}
app/src/main/java/cn/flightfeather/thirdapp/module/base/ToolbarSetInterface.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,83 @@
package cn.flightfeather.thirdapp.module.base
import android.content.Context
import android.graphics.drawable.Drawable
import android.support.v7.widget.Toolbar
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import org.jetbrains.anko.topPadding
/**
 * @author riku
 * Date: 2019/5/8
 * toolbar设置接口
 */
interface ToolbarSetInterface {
    fun initToolbar() {
        if (toolbarEnabled()) {
            //设置用户头像点击事件
            getHeadIcon().setOnClickListener {
                onHeadIconClick()
            }
            //左侧按钮
            getHeadIconRes()?.let {
                val icon = getHeadIcon()
                if (icon is ImageView) {
                    icon.setImageDrawable(it)
                }
            }
            //toolbar标题文字
            getMyTitleTextView()?.apply {
                getTitleText()?.let {
                    text = it
                    visibility = if (getTitleEnabled()) View.VISIBLE else View.INVISIBLE
                }
            }
            //右侧菜单按钮
            val menuList = getMenus() ?: emptyList()
            val visibilities = getMenuVisibility()
            val resources = getMenuRes()
            val listeners = getMenuClickListener()
            for (index in menuList.indices) {
                menuList[index].apply {
                    visibility = if (index < visibilities.size) visibilities[index]
                            ?: View.GONE else View.GONE
                    if (this is ImageView) {
                        setImageDrawable(if (index < resources.size) resources[index] else null)
                    }
                    setOnClickListener(if (index < listeners.size) listeners[index] else null)
                }
            }
        }
    }
    fun getToolBar(): Toolbar
    fun toolbarEnabled(): Boolean
    //toolbar左侧图标
    fun getHeadIcon(): View
    //toolbar左侧图标点击事件
    fun onHeadIconClick()
    //左侧按钮的图片资源
    fun getHeadIconRes(): Drawable? = null
    //toolbar居中标题
    fun getMyTitleTextView(): TextView?
    //是否展示标题栏中间标题
    fun getTitleEnabled(): Boolean
    //标题内容
    fun getTitleText(): String?
    //toolbar å³ä¾§èœå•
    fun getMenus():List<View>?
    //三个菜单按钮的可见性
    fun getMenuVisibility(): List<Int?>
    //三个菜单按钮的图片资源
    fun getMenuRes(): List<Drawable?>
    //三个菜单按钮的文本
    fun getMenuText(): List<String?> = emptyList()
    //三个菜单按钮的点击事件
    fun getMenuClickListener(): List<View.OnClickListener?>
}
app/src/main/java/cn/flightfeather/thirdapp/module/common/FileBrowseViewModel.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,34 @@
package cn.flightfeather.thirdapp.module.common
import cn.flightfeather.thirdapp.common.net.ResultCallBack
import cn.flightfeather.thirdapp.module.base.BaseViewModel
import cn.flightfeather.thirdapp.repository.MediaFileRepository
import cn.flightfeather.thirdapp.util.file.FileItem
/**
 * @author riku
 * Date: 2019/11/22
 */
class FileBrowseViewModel  : BaseViewModel() {
    private val mediaFileRepository = MediaFileRepository()
    val selectedFilePathList = ArrayList<String>()
    //所有文件,按照文件类型分类
    val totalFiles = mutableMapOf<String, MutableList<FileItem>>()
    //类型文件展示状态,记录该类型文件的部分是否已经展示在界面上
    private val fileShowState = mutableMapOf<String, Boolean>()
    //同一类型文件查询到多少个后需要刷新展示到界面上
    private val needShowNum = 10
    fun getFileCache(url: String, resultCallBack: ResultCallBack<String>) {
        mediaFileRepository.getFileCache(url, resultCallBack)
    }
    fun saveFileCache(url: String, localPath: String) {
        mediaFileRepository.saveFileCache(url, localPath)
    }
}
app/src/main/java/cn/flightfeather/thirdapp/module/common/FileDownloadFragment.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,170 @@
package cn.flightfeather.thirdapp.module.common
import android.arch.lifecycle.ViewModelProviders
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.view.View
import cn.flightfeather.thirdapp.R
import cn.flightfeather.thirdapp.common.net.ResultCallBack
import cn.flightfeather.thirdapp.module.base.BaseFragment
import cn.flightfeather.thirdapp.module.base.BaseFragmentActivity
import cn.flightfeather.thirdapp.util.file.FileUtils
import com.liulishuo.okdownload.DownloadTask
import com.liulishuo.okdownload.StatusUtil
import com.liulishuo.okdownload.core.cause.EndCause
import com.liulishuo.okdownload.kotlin.execute1
import kotlinx.android.synthetic.main.fragment_file_download.*
import org.jetbrains.anko.doAsync
import java.io.File
/**
 * @author riku
 * Date: 2019/12/31
 */
class FileDownloadFragment : BaseFragment() {
    companion object {
        fun newInstance(filePos: Int, filePath: String?, fileName: String?): FileDownloadFragment {
            val bundle = Bundle().apply {
                putInt("filePos", filePos)
                putString("filePath", filePath)
                putString("fileName", fileName)
            }
            return FileDownloadFragment().apply { arguments = bundle }
        }
    }
    override fun getTitleText(): String? = "文件下载"
    override fun toolbarEnabled(): Boolean = true
    private var filePos = 0
    private var filePath: String? = ""
    private var fileName: String? = ""
    private var task: DownloadTask? = null
    private var downloadFilePath = ""
    private lateinit var fileBrowseViewModel: FileBrowseViewModel
    override fun getLayoutId(): Int = R.layout.fragment_file_download
    override fun onCreateView() {
        super.onCreateView()
        fileBrowseViewModel = ViewModelProviders.of(this).get(FileBrowseViewModel::class.java)
        arguments?.let {
            filePos = it.getInt("filePos")
            filePath = it.getString("filePath")
            fileName = it.getString("fileName")
        }
    }
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
//        img_file_type.setImageResource(FileIcons.bigIcon(fileName))
        txt_file_name.text = fileName
        showLoadingText(false)
        initTask()
        initStatus()
        filePath?.let {url ->
            fileBrowseViewModel.getFileCache(url, object : ResultCallBack<String> {
                override fun onSuccess(result: String?) {
                    result?.let {
                        downloadFilePath = it
                        navigateToNextFragment()
                    }
                }
                override fun onFailure() {
                    startTask()
                }
            })
        }
    }
    override fun onDestroy() {
        super.onDestroy()
        task?.cancel()
    }
    private fun initTask() {
        context?.let {
            val parentFile = FileUtils.getCacheDir(it)
            downloadFilePath = parentFile.path + File.separator + fileName
            filePath?.let {p ->
                task = DownloadTask.Builder(p, parentFile)
                    .setFilename(fileName)
                    .setMinIntervalMillisCallbackProcess(16)
                    .setPassIfAlreadyCompleted(false)
                    .build()
            }
        }
    }
    private fun initStatus() =task?.let {
        val status = StatusUtil.getStatus(it)
        if (status == StatusUtil.Status.COMPLETED) {
        }
    }
    private fun startTask() {
        txt_progress.postDelayed({
            if (activity != null && !activity!!.isFinishing && !activity!!.isDestroyed) {
                showLoadingText(true)
            }
        }, 3000)
        doAsync {
            task?.execute1(
                connected = {task, blockCount, currentOffset, totalLength ->
                    // todo: 2019/12/31
                },
                progress = {task, currentOffset, totalLength ->
                    circularProgressBar?.apply {
                        progress = currentOffset.toFloat()
                        progressMax = totalLength.toFloat()
                    }
                    val t = "${FileUtils.parseToFileSize(currentOffset)}/${FileUtils.parseToFileSize(totalLength)}"
                    txt_progress?.text = t
                }
            ) { task, cause, realCause, model ->
                task.tag = null
                if (cause == EndCause.COMPLETED) {
                    filePath?.let {
                        fileBrowseViewModel.saveFileCache(it, downloadFilePath)
                    }
                    navigateToNextFragment()
                } else if (cause == EndCause.ERROR) {
                    // todo: 2019/12/31
                }
            }
        }
    }
    private fun showLoadingText(visible: Boolean) {
        if (visible) {
            circularProgressBar.visibility = View.VISIBLE
            txt_progress.visibility = View.VISIBLE
            progress_circular.visibility = View.GONE
        } else {
            circularProgressBar.visibility = View.GONE
            txt_progress.visibility = View.GONE
            progress_circular.visibility = View.VISIBLE
        }
    }
    private fun navigateToNextFragment() {
        val a = activity
        if (a is BaseFragmentActivity) {
            a.navigateToNext(OfficeFileReadFragment.newInstance(filePos, downloadFilePath, fileName))
            a.deleteFragmentFromNavigation(this@FileDownloadFragment)
        }
    }
}
app/src/main/java/cn/flightfeather/thirdapp/module/common/OfficeFileManageActivity.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,41 @@
package cn.flightfeather.thirdapp.module.common
import android.os.Bundle
import cn.flightfeather.thirdapp.module.base.BaseFragment
import cn.flightfeather.thirdapp.module.base.BaseFragmentActivity
/**
 * @author riku
 * Date: 2019/12/31
 */
class OfficeFileManageActivity : BaseFragmentActivity() {
    companion object {
        const val FILE_PATH = "FILE_PATH"
        const val FILE_POS = "FILE_POS"
    }
    private var filePos = 0
    private var filePath: String? = ""
    private var fileName: String? = ""
    private var isRemoteFile = true
    override fun onCreate(savedInstanceState: Bundle?) {
        filePos = intent.getIntExtra("filePos", 0)
        filePath = intent.getStringExtra("filePath")
        fileName = intent.getStringExtra("fileName")
        isRemoteFile = intent.getBooleanExtra("isRemoteFile", true)
        super.onCreate(savedInstanceState)
    }
    override fun getInitFragment(): BaseFragment? =
            if (isRemoteFile) {
                FileDownloadFragment.newInstance(filePos, filePath, fileName)
            } else {
                OfficeFileReadFragment.newInstance(filePos, filePath, fileName)
            }
}
app/src/main/java/cn/flightfeather/thirdapp/module/common/OfficeFileReadFragment.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,131 @@
package cn.flightfeather.thirdapp.module.common
import android.app.Activity
import android.content.Intent
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.os.Environment
import android.support.v4.content.ContextCompat
import android.view.View
import android.view.ViewGroup
import cn.flightfeather.thirdapp.R
import cn.flightfeather.thirdapp.module.base.BaseFragment
import cn.flightfeather.thirdapp.util.SystemServiceUtils
import cn.flightfeather.thirdapp.util.file.FileUtils
import com.tencent.smtt.sdk.QbSdk
import com.tencent.smtt.sdk.TbsReaderView
import kotlinx.android.synthetic.main.fragment_office_file.*
import org.json.JSONException
import org.json.JSONObject
import java.io.File
/**
 * @author riku
 * Date: 2019/12/31
 * office文件浏览
 */
class OfficeFileReadFragment : BaseFragment() {
    companion object {
        fun newInstance(filePos: Int, filePath: String?, fileName: String?): OfficeFileReadFragment {
            val bundle = Bundle().apply {
                putInt("filePos", filePos)
                putString("filePath", filePath)
                putString("fileName", fileName)
            }
            return OfficeFileReadFragment().apply { arguments = bundle }
        }
    }
    override fun toolbarEnabled(): Boolean = true
    override fun getMenuVisibility(): List<Int?> = listOf(View.VISIBLE)
    override fun getMenuRes(): List<Drawable?> = listOf(ContextCompat.getDrawable(context!!, R.drawable.icon_share_blue))
    override fun getMenuClickListener(): List<View.OnClickListener?> = listOf(View.OnClickListener {
        SystemServiceUtils.shareFile(activity, filePath)
    })
    override fun getTitleText(): String? = fileName
    private var filePos = 0
    private var filePath: String? = ""
    private var fileName: String? = ""
    private lateinit var tbsReaderView: TbsReaderView
    override fun getLayoutId(): Int = R.layout.fragment_office_file
    override fun onCreateView() {
        arguments?.let {
            filePos = it.getInt("filePos")
            filePath = it.getString("filePath")
            fileName = it.getString("fileName")
        }
        super.onCreateView()
    }
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
//        init()
        openLocalFile()
        val intent = Intent()
        intent.putExtra(OfficeFileManageActivity.FILE_PATH, filePath)
        intent.putExtra(OfficeFileManageActivity.FILE_POS, filePos)
        activity?.setResult(Activity.RESULT_OK, intent)
    }
    override fun onDetach() {
        super.onDetach()
        tbsReaderView.onStop()
    }
    override fun onDestroy() {
        super.onDestroy()
        tbsReaderView.onStop()
    }
    private fun init() {
        val params = hashMapOf<String, String>()
        params["local"] = "true"
        val obj = JSONObject()
        try {
            obj.put("pkgName", context?.applicationContext?.packageName)
        } catch (e: JSONException) {
            e.printStackTrace()
        }
        params["menuData"] = obj.toString()
        QbSdk.getMiniQBVersion(context)
        QbSdk.openFileReader(context, filePath, params) {
            activity?.finish()
        }
    }
    private fun openLocalFile() {
        tbsReaderView = TbsReaderView(context, null)
        tbs_reader_container.addView(tbsReaderView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
        if (!filePath.isNullOrEmpty()) {
            val tempFile = File("/storage/emulated/0/TbsReaderTemp")
            if (!tempFile.exists()) {
                tempFile.mkdirs()
            }
            //加载文件
            val localBundle = Bundle()
            localBundle.putString("filePath", filePath)
            localBundle.putString(
                    "tempPath",
                    Environment.getExternalStorageDirectory().path + File.separator + "TbsReaderTemp"
            )
            val result = tbsReaderView.preOpen(FileUtils.getExtensionName(filePath), false)
            if (result) {
                tbsReaderView.openFile(localBundle)
            }
        }
    }
}
app/src/main/java/cn/flightfeather/thirdapp/module/inspection/MenuCameraActivity.kt
@@ -51,6 +51,7 @@
    //当前选择的拍照类型
    private var currentType = MediaFileType.RoutineRecord
    private var currentTypeName = currentType.des
    lateinit var viewModel: MenuCameraViewModel
@@ -94,7 +95,9 @@
                    val oldFile = File(it)
                    val cal = Calendar.getInstance().apply { time = subTask?.executionstarttime }
                    scene?.run {
                        val path = "FlightFeather/Photo/" + districtname + "/"+ cal.get(Calendar.YEAR) + "å¹´" + (cal.get(Calendar.MONTH) + 1) + "月/"+ (cal.get(Calendar.MONTH) + 1) + "月" + cal.get(Calendar.DAY_OF_MONTH) + "日/"+ name + "/任意拍照/"
                        val path = "FlightFeather/Photo/" + districtname + "/" + cal.get(Calendar.YEAR) + "å¹´" + (cal.get(Calendar.MONTH) + 1) + "月/" +
                                (cal.get(Calendar.MONTH) + 1) + "月" + cal.get(Calendar.DAY_OF_MONTH) + "日/" + name + "/任意拍照/" + currentTypeName + "/"
                        val fileName = UUIDGenerator.generateUUID(4) + ".jpg"
                        val newFile = File(Environment.getExternalStorageDirectory(), path + fileName)
                        if (!newFile.parentFile.exists()) {
@@ -154,6 +157,7 @@
            addOnItemTouchListener(RecyclerItemClickListener(this@MenuCameraActivity, this, object : RecyclerItemClickListener.OnItemClickListener {
                override fun onItemClick(view: View?, position: Int) {
                    currentType = type
                    currentTypeName = title.text.toString()
                    //拍照
                    if (dataList[position].guid == null) {
                        PhotoUtil.pickPhoto2(this@MenuCameraActivity, TAKE_PHOTO, 9)
app/src/main/java/cn/flightfeather/thirdapp/module/nightwork/NightWorkManageActivity.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,99 @@
package cn.flightfeather.thirdapp.module.nightwork
import android.arch.lifecycle.Observer
import android.arch.lifecycle.ViewModelProviders
import android.content.Intent
import android.os.Bundle
import android.view.View
import cn.flightfeather.thirdapp.R
import cn.flightfeather.thirdapp.model.bean.NightWorkFileVo
import cn.flightfeather.thirdapp.module.base.BaseActivity
import cn.flightfeather.thirdapp.module.common.OfficeFileManageActivity
import cn.flightfeather.thirdapp.util.CommonUtils
import cn.flightfeather.thirdapp.view.recyclerview.BaseCustomViewHolder
import cn.flightfeather.thirdapp.view.recyclerview.MySection
import cn.flightfeather.thirdapp.view.recyclerview.RecyclerViewPanel
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.BaseViewHolder
import kotlinx.android.synthetic.main.activity_night_work_manage.*
import kotlinx.android.synthetic.main.layout_toolbar_2.*
/**
 * @author riku
 * Date: 2021/1/4
 */
class NightWorkManageActivity : BaseActivity() {
    override fun getLayoutId(): Int = R.layout.activity_night_work_manage
    lateinit var viewModel: NightWorkViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        viewModel = ViewModelProviders.of(this).get(NightWorkViewModel::class.java)
        initToolbar()
        initView()
        initRecyclerView()
        initObserver()
        viewModel.getSummary()
    }
    private fun initToolbar() {
        img_back.setOnClickListener { finish() }
        tv_main_title.text = "夜间施工许可"
    }
    private fun initView() {
    }
    private fun initRecyclerView() {
        object : RecyclerViewPanel<NightWorkFileVo>(viewModel.dataLoadModel3, recycler_view, this) {
            override fun getItemLayoutId(): Int? = R.layout.item_night_work_3
            override fun onBindView(holder: BaseCustomViewHolder, item: MySection<NightWorkFileVo>?) {
                item?.t?.let {vo ->
                    val time = CommonUtils.getStartEndDate(vo.startDate, vo.endDate)
                    holder.setText(R.id.txt_content, vo.itemName)
                            .setText(R.id.txt_night_work_num, vo.num)
                            .setText(R.id.txt_time, time)
                            if (vo.isRead == true) {
                                holder.setSelected(R.id.txt_signed, true)
                                        .setText(R.id.txt_signed, getString(R.string.signed))
                            } else{
                                holder.setSelected(R.id.txt_signed, false)
                                        .setText(R.id.txt_signed, getString(R.string.unsigned))
                            }
                }
            }
            override fun onItemClick(adapter: BaseQuickAdapter<Any?, BaseViewHolder>, view: View, position: Int, dataList: List<NightWorkFileVo>) {
                super.onItemClick(adapter, view, position, dataList)
                openDetail(dataList[position])
            }
        }.run {
            init()
            startRefresh()
        }
    }
    private fun initObserver() {
        viewModel.summary.observe(this, Observer {
            it?.let { n ->
                txt_total_count.text = n.totalCount.toString()
                txt_signed_count.text = n.signedCount.toString()
            }
        })
    }
    private fun openDetail(nightWorkFileVo: NightWorkFileVo) {
        val intent = Intent(this, OfficeFileManageActivity::class.java)
        intent.putExtra("filePath", nightWorkFileVo.url)
        intent.putExtra("fileName", nightWorkFileVo.fileName)
        intent.putExtra("isRemoteFile", nightWorkFileVo.url?.contains("http") == true)
        startActivity(intent)
    }
}
app/src/main/java/cn/flightfeather/thirdapp/module/nightwork/NightWorkRecordActivity.kt
@@ -1,10 +1,25 @@
package cn.flightfeather.thirdapp.module.nightwork
import android.arch.lifecycle.ViewModelProviders
import android.content.Intent
import android.os.Bundle
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import cn.flightfeather.thirdapp.R
import cn.flightfeather.thirdapp.common.net.ResultCallBack
import cn.flightfeather.thirdapp.model.bean.NightWorkFileVo
import cn.flightfeather.thirdapp.module.base.BaseActivity
import cn.flightfeather.thirdapp.module.common.OfficeFileManageActivity
import cn.flightfeather.thirdapp.util.CommonUtils
import cn.flightfeather.thirdapp.view.recyclerview.BaseCustomViewHolder
import cn.flightfeather.thirdapp.view.recyclerview.EmptyLoadMoreView
import cn.flightfeather.thirdapp.view.recyclerview.MySection
import cn.flightfeather.thirdapp.view.recyclerview.RecyclerViewPanel
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.BaseViewHolder
import com.chad.library.adapter.base.loadmore.LoadMoreView
import kotlinx.android.synthetic.main.activity_night_work.*
import kotlinx.android.synthetic.main.layout_toolbar_2.*
@@ -12,10 +27,25 @@
 * @author riku
 * Date: 2020/12/24
 */
class NightWorkRecordActivity : BaseActivity(), View.OnClickListener {
    override fun getLayoutId(): Int = R.layout.activity_night_work
class NightWorkRecordActivity : BaseActivity() {
    inner class FileLoadMoreView : LoadMoreView() {
        override fun getLayoutId(): Int = R.layout.item_night_work_no_more
        override fun getLoadingViewId(): Int = R.id.no_more
        override fun getLoadFailViewId(): Int = R.id.no_more
        override fun getLoadEndViewId(): Int = R.id.no_more
    }
    lateinit var viewModel: NightWorkViewModel
    private lateinit var recyclerViewPanel1: RecyclerViewPanel<NightWorkFileVo>
    private lateinit var recyclerViewPanel2: RecyclerViewPanel<NightWorkFileVo>
    override fun getLayoutId(): Int = R.layout.activity_night_work
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
@@ -28,23 +58,142 @@
    }
    private fun initToolbar() {
        img_back.setOnClickListener(this)
        img_back.setOnClickListener { finish() }
        tv_main_title.text = "夜间施工许可"
    }
    /**
     * æœ€æ–°æœªè¯»æ–‡ä»¶
     */
    private fun initRecyclerView1() {
        recycler_view
        recyclerViewPanel1 = object : RecyclerViewPanel<NightWorkFileVo>(viewModel.dataLoadModel1, recycler_view, this) {
            private val TYPE_ITEM = 1
            private val TYPE_EMPTY = 2
            override fun getItemLayoutId(): Int? = R.layout.item_night_work
//            override fun getItemLayoutIdMap(): Map<Int, Int> = mapOf(
//                    Pair(TYPE_ITEM, R.layout.item_night_work),
//                    Pair(TYPE_EMPTY, R.layout.item_night_work_no_more)
//            )
//            override fun convertToSection(list: List<NightWorkFileVo>): MutableList<MySection<NightWorkFileVo>> {
//                val resultList = mutableListOf<MySection<NightWorkFileVo>>()
//                list.forEach {
//                    if (it.id != null) {
//                        resultList.add(MySection(it, TYPE_ITEM))
//                    }
//                }
//                resultList.add(MySection(NightWorkFileVo(), TYPE_EMPTY))
//                return resultList
//            }
            override fun onBindView(holder: BaseCustomViewHolder, item: MySection<NightWorkFileVo>?) {
                item?.t?.let { vo ->
//                    when (holder.itemViewType) {
//                        TYPE_ITEM -> {
//
//                        }
//                        TYPE_EMPTY -> Unit
//                        else -> Unit
//                    }
                    val time = CommonUtils.getStartEndDate(vo.startDate, vo.endDate)
                    holder.setText(R.id.txt_night_work_num, vo.num)
                            .setText(R.id.txt_content, vo.applyContent)
                            .setText(R.id.txt_time, time)
                            .addOnClickListener(R.id.txt_sign)
                }
            }
            override fun onItemClick(adapter: BaseQuickAdapter<Any?, BaseViewHolder>, view: View, position: Int, dataList: List<NightWorkFileVo>) {
                super.onItemClick(adapter, view, position, dataList)
                val d = dataList[position]
                openDetail(d)
                d.id?.let { id ->
                    d.num?.let { num ->
                        viewModel.signFile(id, num, object : ResultCallBack<Int> {
                            override fun onSuccess(result: Int?) {
                                adapter.remove(position)
                                recyclerViewPanel2.addData(0, listOf(d))
                            }
                            override fun onFailure() {
                            }
                        })
                    }
                }
            }
            override fun onItemChildClick(adapter: BaseQuickAdapter<Any?, BaseViewHolder>, view: View, position: Int, dataList: List<NightWorkFileVo>) {
                super.onItemChildClick(adapter, view, position, dataList)
                val d = dataList[position]
                when (view.id) {
                    R.id.txt_sign -> {
                        d.id?.let { id ->
                            d.num?.let { num ->
                                viewModel.signFile(id, num, object : ResultCallBack<Int> {
                                    override fun onSuccess(result: Int?) {
                                        adapter.remove(position)
                                        recyclerViewPanel2.addData(0, listOf(d))
                                    }
                                    override fun onFailure() {
                                    }
                                })
                            }
                        }
                    }
                }
            }
            override fun getMyLayoutManager(): RecyclerView.LayoutManager = LinearLayoutManager(this@NightWorkRecordActivity, LinearLayoutManager.HORIZONTAL, false)
            override fun needSwipeRefresh(): Boolean = false
            override fun getLoadMoreView(): LoadMoreView? = FileLoadMoreView()
            override fun getMyEmptyView(): View? = LayoutInflater.from(this@NightWorkRecordActivity).inflate(R.layout.layout_night_work_empty, null)
        }.also {
            it.init()
            it.startRefresh()
        }
    }
    /**
     * åŽ†å²æ–‡ä»¶
     */
    private fun initRecyclerView2() {
        recyclerViewPanel2 = object : RecyclerViewPanel<NightWorkFileVo>(viewModel.dataLoadModel2, recycler_view_2, this) {
            override fun getItemLayoutId(): Int? = R.layout.item_night_work_2
            override fun onBindView(holder: BaseCustomViewHolder, item: MySection<NightWorkFileVo>?) {
                item?.t?.let { vo ->
                    val time = CommonUtils.getStartEndDate(vo.startDate, vo.endDate)
                    holder.setText(R.id.txt_content, vo.applyContent)
                            .setText(R.id.txt_time, time)
                }
            }
            override fun onItemClick(adapter: BaseQuickAdapter<Any?, BaseViewHolder>, view: View, position: Int, dataList: List<NightWorkFileVo>) {
                super.onItemClick(adapter, view, position, dataList)
                openDetail(dataList[position])
            }
        }.also {
            it.init()
            it.startRefresh()
        }
    }
    private fun initObserver() {
    }
    override fun onClick(v: View?) {
        TODO("Not yet implemented")
    private fun openDetail(nightWorkFileVo: NightWorkFileVo) {
        val intent = Intent(this, OfficeFileManageActivity::class.java)
        intent.putExtra("filePath", nightWorkFileVo.url)
        intent.putExtra("fileName", nightWorkFileVo.fileName)
        intent.putExtra("isRemoteFile", nightWorkFileVo.url?.contains("http") == true)
        startActivity(intent)
    }
}
app/src/main/java/cn/flightfeather/thirdapp/module/nightwork/NightWorkViewModel.kt
@@ -1,6 +1,12 @@
package cn.flightfeather.thirdapp.module.nightwork
import android.arch.lifecycle.MutableLiveData
import cn.flightfeather.thirdapp.common.net.ResultCallBack
import cn.flightfeather.thirdapp.model.bean.NightWorkFileVo
import cn.flightfeather.thirdapp.model.bean.NightWorkSummary
import cn.flightfeather.thirdapp.module.base.BaseViewModel
import cn.flightfeather.thirdapp.repository.NightWorkRepository
import cn.flightfeather.thirdapp.view.recyclerview.DataLoadModel
/**
 * @author riku
@@ -8,4 +14,64 @@
 */
class NightWorkViewModel : BaseViewModel() {
    private val nightWorkRepository = NightWorkRepository()
    var summary = MutableLiveData<NightWorkSummary>()
    //获取最新未读文件
    val dataLoadModel1 = object : DataLoadModel<NightWorkFileVo>(application) {
        override fun loadDataByRefresh() {
            getNightWorkFile(false, 1, this)
        }
        override fun loadDataByLoadMore(page: Int) {
            getNightWorkFile(false, page, this)
        }
    }
    //获取历史已读文件
    val dataLoadModel2 = object : DataLoadModel<NightWorkFileVo>(application) {
        override fun loadDataByRefresh() {
            getNightWorkFile(true, 1, this)
        }
        override fun loadDataByLoadMore(page: Int) {
            getNightWorkFile(true, page, this)
        }
    }
    //获取全部文件
    val dataLoadModel3 = object : DataLoadModel<NightWorkFileVo>(application) {
        override fun loadDataByRefresh() {
            getRecord(application.currentUser.dguid, 1, this)
        }
        override fun loadDataByLoadMore(page: Int) {
            getRecord(application.currentUser.dguid, page, this)
        }
    }
    fun getNightWorkFile(isRead: Boolean, page: Int, callBack: ResultCallBack<List<NightWorkFileVo>>) {
        nightWorkRepository.getNightWorkFile(userId, isRead, page, callBack)
    }
    fun signFile(fileId: Int, fileNum: String, callBack: ResultCallBack<Int>) {
        nightWorkRepository.signFile(userId, fileNum, fileId, callBack)
    }
    fun getRecord(districtCode: String, page: Int, callBack: ResultCallBack<List<NightWorkFileVo>>) {
        nightWorkRepository.getRecord(districtCode, page, callBack)
    }
    fun getSummary() {
        nightWorkRepository.getSummary(application.currentUser.dguid, object : ResultCallBack<NightWorkSummary> {
            override fun onSuccess(result: NightWorkSummary?) {
                result?.let { summary.value = it }
            }
            override fun onFailure() {
//                summary.value = NightWorkSummary()
            }
        })
    }
}
app/src/main/java/cn/flightfeather/thirdapp/repository/MediaFileRepository.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,51 @@
package cn.flightfeather.thirdapp.repository
import cn.flightfeather.thirdapp.common.net.ResultCallBack
import cn.flightfeather.thirdapp.common.net.ResultObserver
import cn.flightfeather.thirdapp.common.net.RetrofitFactory
import cn.flightfeather.thirdapp.repository.dao.MediaFileDao
import retrofit2.Response
import java.io.File
/**
 * @author riku
 * Date: 2020/4/18
 */
class MediaFileRepository {
    private val mediaFileDao =  MediaFileDao()
    fun getFileCache(url: String?, resultCallBack: ResultCallBack<String>) {
        //url ä¸æ˜¯ç½‘络路径时,返回其自身
        if (url?.contains("http") != true) {
            resultCallBack.onSuccess(url)
            return
        }
        val dbService = mediaFileDao.getFileCache(url).map {
            Response.success(it)
        }
        RetrofitFactory.executeResult(dbService, object : ResultObserver<String>() {
            override fun onSuccess(result: String?) {
                if (result.isNullOrBlank()) {
                    resultCallBack.onFailure()
                } else {
                    val file = File(result)
                    if (file.exists()) {
                        resultCallBack.onSuccess(result)
                    } else {
                        resultCallBack.onFailure()
                    }
                }
            }
            override fun onFailure(e: Throwable, isNetWorkError: Boolean) {
                resultCallBack.onFailure()
            }
        })
    }
    fun saveFileCache(url: String, localPath: String) {
        mediaFileDao.saveFileCache(url, localPath)
    }
}
app/src/main/java/cn/flightfeather/thirdapp/repository/NightWorkRepository.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,84 @@
package cn.flightfeather.thirdapp.repository
import cn.flightfeather.thirdapp.common.net.ResultCallBack
import cn.flightfeather.thirdapp.common.net.ResultObserver
import cn.flightfeather.thirdapp.common.net.RetrofitFactory
import cn.flightfeather.thirdapp.httpservice.NightWorkService
import cn.flightfeather.thirdapp.model.bean.BaseResponse
import cn.flightfeather.thirdapp.model.bean.NightWorkFileVo
import cn.flightfeather.thirdapp.model.bean.NightWorkSummary
/**
 * @author riku
 * Date: 2020/12/29
 */
class NightWorkRepository {
    val retrofit = RetrofitFactory.instance.retrofit
    fun getRecord(districtCode: String, page: Int, resultCallBack: ResultCallBack<List<NightWorkFileVo>>) {
        val service = retrofit.create(NightWorkService::class.java).getRecord(districtCode, page)
        RetrofitFactory.executeResult(service, object : ResultObserver<BaseResponse<List<NightWorkFileVo>>>() {
            override fun onSuccess(result: BaseResponse<List<NightWorkFileVo>>?) {
                resultCallBack.onSuccess(result?.data)
            }
            override fun onPage(current: Int, total: Int) {
                super.onPage(current, total)
                resultCallBack.onPage(current, total)
            }
            override fun onFailure(e: Throwable, isNetWorkError: Boolean) {
                resultCallBack.onFailure()
            }
        })
    }
    fun getNightWorkFile(userId: String, isRead: Boolean? = null, page: Int, resultCallBack: ResultCallBack<List<NightWorkFileVo>>) {
        val service = retrofit.create(NightWorkService::class.java).getNightWorkFile(userId, isRead, page)
        RetrofitFactory.executeResult(service, object : ResultObserver<BaseResponse<List<NightWorkFileVo>>>() {
            override fun onSuccess(result: BaseResponse<List<NightWorkFileVo>>?) {
                resultCallBack.onSuccess(result?.data)
            }
            override fun onPage(current: Int, total: Int) {
                super.onPage(current, total)
                resultCallBack.onPage(current, total)
            }
            override fun onFailure(e: Throwable, isNetWorkError: Boolean) {
                resultCallBack.onFailure()
            }
        })
    }
    fun signFile(userId: String, fileNum: String, id: Int, resultCallBack: ResultCallBack<Int>) {
        val service = retrofit.create(NightWorkService::class.java).signFile(userId, fileNum, id)
        RetrofitFactory.executeResult(service, object : ResultObserver<BaseResponse<Int>>() {
            override fun onSuccess(result: BaseResponse<Int>?) {
                resultCallBack.onSuccess(result?.data)
            }
            override fun onFailure(e: Throwable, isNetWorkError: Boolean) {
                resultCallBack.onFailure()
            }
        })
    }
    fun getSummary(districtCode: String, resultCallBack: ResultCallBack<NightWorkSummary>) {
        val service = retrofit.create(NightWorkService::class.java).getSummary(districtCode)
        RetrofitFactory.executeResult(service, object : ResultObserver<BaseResponse<NightWorkSummary>>() {
            override fun onSuccess(result: BaseResponse<NightWorkSummary>?) {
                resultCallBack.onSuccess(result?.data)
            }
            override fun onFailure(e: Throwable, isNetWorkError: Boolean) {
                resultCallBack.onFailure()
            }
        })
    }
}
app/src/main/java/cn/flightfeather/thirdapp/repository/dao/MediaFileDao.kt
@@ -1,9 +1,14 @@
package cn.flightfeather.thirdapp.repository.dao
import cn.flightfeather.thirdapp.bean.entity.MediaFileCache
import cn.flightfeather.thirdapp.bean.entity.Mediafile
import cn.flightfeather.thirdapp.common.database.DbFactory
import cn.flightfeather.thirdapp.common.database.FlatSaveInterface
import cn.flightfeather.thirdapp.common.database.flatMapDbSaveResult
import com.ping.greendao.gen.MediaFileCacheDao
import com.ping.greendao.gen.MediafileDao
import io.reactivex.Observable
import org.greenrobot.greendao.AbstractDao
/**
 * @author riku
@@ -70,4 +75,47 @@
            true
        }
    }
    /**
     * èŽ·å–ç¼“å­˜çš„æ–‡ä»¶
     */
    fun getFileCache(url: String?): Observable<String> {
        return DbFactory.getGreenDaoObservable().map {
            val resultList = it.mediaFileCacheDao.queryBuilder()
                    .where(MediaFileCacheDao.Properties.Url.eq(url))
                    .list()
            if (resultList.isNotEmpty()) {
                resultList[0].path
            } else {
                ""
            }
        }
    }
    /**
     * ä¿å­˜ç¼“存的文件
     */
    fun saveFileCache(url: String, localPath: String, thumbnailPath: String? = null) {
        flatMapDbSaveResult(DbFactory.getInstance().mediaFileCacheDao,
                object : FlatSaveInterface<MediaFileCache, Long> {
                    override fun onQuery(dao: AbstractDao<MediaFileCache, Long>): List<MediaFileCache> {
                        return dao.queryBuilder()
                                .where(MediaFileCacheDao.Properties.Url.eq(url))
                                .list()
                    }
                    override fun onUpdate(list: List<MediaFileCache>) {
                        list[0].apply {
                            path = localPath
                        }
                    }
                    override fun onInsert(): List<MediaFileCache> {
                        return listOf(MediaFileCache().apply {
                            this.url = url
                            this.path = localPath
                        })
                    }
                })
    }
}
app/src/main/java/cn/flightfeather/thirdapp/util/CommonUtils.java
@@ -5,10 +5,12 @@
import com.ping.greendao.gen.DaoSession;
import com.ping.greendao.gen.DomainitemDao;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import cn.flightfeather.thirdapp.R;
import cn.flightfeather.thirdapp.bean.entity.Domainitem;
@@ -18,6 +20,7 @@
 */
public class CommonUtils {
    public static List<Domainitem> getDomainItemByCalalogGuid(DaoSession daoSession, String guid) {
        return daoSession.getDomainitemDao().queryBuilder()
                .where(DomainitemDao.Properties.Dcguid.eq(guid))
@@ -210,6 +213,26 @@
        cal.setTime(getCurrentYearEndTime());
        cal.add(Calendar.YEAR, -1);
        return cal.getTime();
    }
    /**
     * èŽ·å–æ—¶é—´æ®µæ–‡æœ¬
     */
    public static String getStartEndDate(Date startDate, Date endDate) {
        SimpleDateFormat format1 = new SimpleDateFormat("yyyy.MM.dd", Locale.CHINESE);
        String s = format1.format(startDate);
        String e = format1.format(endDate);
        String str = "";
        try {
            if (s.substring(0, 4).equals(e.substring(0, 4))) {
                str = s + "-" + e.substring(5);
            } else {
                str = s + "-" + e;
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return str;
    }
    /**
@@ -457,4 +480,5 @@
    public static byte intToByte(int x) {
        return (byte) x;
    }
}
app/src/main/java/cn/flightfeather/thirdapp/util/Constant.java
@@ -123,4 +123,6 @@
    //展示类型
    String UNCHANGED = "unchanged";//问题展示类型
    String CHANGED = "changed"; //整改展示类型
    int PAGE_SIZE = 10;
}
app/src/main/java/cn/flightfeather/thirdapp/util/CrashHandler.java
ÎļþÒÑɾ³ý
app/src/main/java/cn/flightfeather/thirdapp/util/DateUtil.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,346 @@
package cn.flightfeather.thirdapp.util
import cn.flightfeather.thirdapp.CommonApplication
import java.lang.Exception
import java.text.SimpleDateFormat
import java.util.*
import kotlin.math.round
/**
 * @author riku
 * Date: 2019/4/9
 * é€šç”¨å·¥å…·ç±»
 */
object DateUtil {
    private const val MILLIS_LIMIT = 1000.0
    private const val SECONDS_LIMIT = 60 * MILLIS_LIMIT
    private const val MINUTES_LIMIT = 60 * SECONDS_LIMIT
    private const val HOURS_LIMIT = 24 * MINUTES_LIMIT
    private const val YESTERDAY_LIMIT = 2 * HOURS_LIMIT
    private const val DAYS_LIMIT = 30 * HOURS_LIMIT
    private val weekDays = listOf("周日", "周一", "周二", "周三", "周四", "周五", "周六")
    /**
     * yyyy-MM-dd HH:mm:ss
     */
    fun getDateStr(date: Date?, chinese: Boolean = false): String {
        if (date == null) {
            return ""
        }
        try {
            return if (chinese) {
                SimpleDateFormat("yyyyå¹´MM月dd日 HH:mm:ss", Locale.getDefault()).format(date)
            } else {
                SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(date)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return ""
    }
    /**
     * HH:mm:ss
     */
    fun getTimeStr(date: Date?): String {
        try {
            return getDateStr(date).substring(11)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return ""
    }
    /**
     * HH:mm
     */
    fun getHourMinStr(date: Date?): String {
        try {
            return getDateStr(date).substring(11, 16)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return ""
    }
    /**
     * YYYY
     */
    fun getYearStr(date: Date?): String {
        try {
            return getDateStr(date).substring(0, 4)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return ""
    }
    /**
     * dd
     */
    fun getDayStr(date: Date?): String {
        try {
            return getDateStr(date).substring(8, 10)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return ""
    }
    /**
     * yyyy-MM
     */
    fun getYearMonthStr(date: Date?, chinese: Boolean = false): String {
        try {
            return getDateStr(date,chinese).substring(0, if (chinese) 8 else 7)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return ""
    }
    /**
     * MM-dd
     */
    fun getMonthDayStr(date: Date?, chinese: Boolean = false): String {
        try {
            return getDateStr(date, chinese).substring(5, if (chinese) 11 else 10)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return ""
    }
    /**
     * yyyy-MM-dd
     */
    fun getYearMonthDayStr(date: Date?, chinese: Boolean = false): String {
        try {
            return getDateStr(date, chinese).substring(0, if (chinese) 11 else 10)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return ""
    }
    /**
     * yyyy-MM-dd HH:mm
     */
    fun getYearToMinStr(date: Date?): String {
        try {
            return getDateStr(date).substring(0, 16)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return ""
    }
    /**
     * èŽ·å–æ˜ŸæœŸ
     */
    fun getWeekDay(date: Date?): String {
        val index = Calendar.getInstance(Locale.getDefault()).apply {
            date?.let { time = it }
        }.get(Calendar.DAY_OF_WEEK) - 1
        return weekDays[index]
    }
    fun parseYearMonth(str: String): Date {
        try {
            return SimpleDateFormat("yyyy-MM", Locale.getDefault()).parse(str)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return Date()
    }
    fun parseYearToMin(str: String): Date {
        try {
            return SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()).parse(str)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return Date()
    }
    fun parseYearToHour(str: String): Date {
        try {
            return SimpleDateFormat("yyyy-MM-dd HH", Locale.getDefault()).parse(str)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return Date()
    }
    /**
     * èŽ·å–æœˆåˆ
     */
    fun getMonthFirstDay(date: Date?): Date {
        return Calendar.getInstance().apply { time = date }
            .apply {
                set(Calendar.DAY_OF_MONTH, 1)
                set(Calendar.HOUR_OF_DAY, 0)
                set(Calendar.MINUTE, 0)
                set(Calendar.SECOND, 0)
            }.time
    }
    /**
     * èŽ·å–ä¸‹æœˆåˆ
     */
    fun getNextMonthFirstDay(date: Date?): Date {
        return Calendar.getInstance().apply { time = date }
            .apply {
                set(Calendar.DAY_OF_MONTH, 1)
                set(Calendar.HOUR_OF_DAY, 0)
                set(Calendar.MINUTE, 0)
                set(Calendar.SECOND, 0)
                val m = get(Calendar.MONTH)
                if (m == 11) {
                    add(Calendar.YEAR, 1)
                    set(Calendar.MONTH, 0)
                } else {
                    add(Calendar.MONTH, 1)
                }
            }.time
    }
    /**
     * æŒ‰ç»™å®šçš„æœˆä»½ä»¥åŠå‘¨æœŸï¼Œå¾—出当前月份所在周期的开始月(例,一年以季度分为4段时间,即周期为3月,则5月所在周期开始月为4月)
     */
    fun getStartMonthByPeriod(currentMon: Int, period: Int):Int? {
        return if (period in 1..12 && currentMon in 1..12) {
            val m = currentMon % period
            val r = currentMon / period
            period * r + if (m == 0) 1 - period else 1
        } else {
            null
        }
    }
    /**
     * æŒ‰ç»™å®šçš„æœˆä»½ä»¥åŠå‘¨æœŸï¼Œå¾—出当前月份所在周期的开始月
     */
    fun getEndMonthByPeriod(currentMon: Int, period: Int): Int? {
        val s = getStartMonthByPeriod(currentMon, period)
        return if (s != null) {
            s + period - 1
        } else {
            null
        }
    }
    /**
     * èŽ·å–è¯­éŸ³æ—¶é—´æ ¼å¼åŒ– 1‘23’‘
     * @param sec ç§’
     */
    fun getAudioTimeStr(sec: Int):String {
        return when (sec * 1000) {
            in 0 until SECONDS_LIMIT.toInt() -> "$sec\""
            in SECONDS_LIMIT.toInt() until MINUTES_LIMIT.toInt() -> "${sec / 60}\'${sec % 60}\""
            else -> ""
        }
    }
    /**
     * èŽ·å–æ—¶é—´æ ¼å¼åŒ–
     */
    fun getNewsTimeStr(date: Date?, chinese: Boolean = false): String {
        if (date == null) {
            return ""
        }
        val subTime = Date().time - date.time
        val now = Calendar.getInstance().apply {
            time = Date()
            set(Calendar.HOUR_OF_DAY, 0)
            set(Calendar.MINUTE, 0)
            set(Calendar.SECOND, 0)
            set(Calendar.MILLISECOND, 0)
        }
        val objDate = Calendar.getInstance().apply {
            time = date
            set(Calendar.HOUR_OF_DAY, 0)
            set(Calendar.MINUTE, 0)
            set(Calendar.SECOND, 0)
            set(Calendar.MILLISECOND, 0)
        }
        val thisYear = now.get(Calendar.YEAR)
        val thisMonth = now.get(Calendar.MONTH)
        val thisDay = now.get(Calendar.DAY_OF_MONTH)
        val objYear = objDate.get(Calendar.YEAR)
        val objMonth = objDate.get(Calendar.MONTH)
        val objDay = objDate.get(Calendar.DAY_OF_MONTH)
        when {
            now.time == objDate.time -> return when {
                subTime < MILLIS_LIMIT -> "刚刚"
                subTime < SECONDS_LIMIT -> round(subTime / MILLIS_LIMIT).toString() + " " + "秒前"
                subTime < MINUTES_LIMIT -> round(subTime / SECONDS_LIMIT).toString() + " " + "分钟前"
                subTime < HOURS_LIMIT -> round(subTime / MINUTES_LIMIT).toString() + " " + "小时前"
                else -> getYearMonthStr(date, chinese)
            }
            objYear < thisYear -> return getYearMonthStr(date, chinese)
            objMonth < thisMonth -> return getMonthDayStr(date, chinese)
            else -> return if (thisDay - objDay == 1) {
                "昨天"
            } else {
                getMonthDayStr(date, chinese)
            }
        }
    }
    /**
     * èŽ·å–æ ¼å¼åŒ–çš„æ—¶é—´å·®
     * @param from å¼€å§‹æ—¶é—´
     * @param to ç»“束时间
     * @return è¿”回开始时间与结束时间的时间差,例3天、1天、24小时、50分钟等,时间单位只取 å¹´ã€æœˆã€å¤©ã€å°æ—¶ã€åˆ†é’Ÿ
     */
    fun getTimeDiffFormat(from: Date?, to: Date?): String? {
        if (from == null || to == null) {
            return null
        }
        val subTime = to.time - from.time
        //保证from å°äºŽç­‰äºŽ to
        if (subTime < 0) {
            return null
        }
        val fromTime = Calendar.getInstance().apply {
            time = from
        }
        val toTime = Calendar.getInstance().apply {
            time = to
        }
        val fromYear = fromTime.get(Calendar.YEAR)
        val fromMonth = fromTime.get(Calendar.MONTH)
        val fromDay = fromTime.get(Calendar.DAY_OF_YEAR)
        val toYear = toTime.get(Calendar.YEAR)
        val toMonth = toTime.get(Calendar.MONTH)
        val toDay = toTime.get(Calendar.DAY_OF_YEAR)
        return when {
            fromYear < toYear -> "${toYear - fromYear}" + "å¹´"
            fromMonth < toMonth -> "${toMonth - fromMonth}" + "月"
            fromDay < toDay -> "${toDay - fromDay}" + "天"
            fromDay == toDay -> when {
                subTime < MINUTES_LIMIT -> round(subTime / SECONDS_LIMIT).toInt().toString() + " " + "分钟"
                subTime < HOURS_LIMIT -> round(subTime / MINUTES_LIMIT).toInt().toString() + " " + "小时"
                else -> throw IllegalStateException("this branch is impossible!")
            }
            else -> throw IllegalStateException("this branch is impossible!")
        }
    }
}
app/src/main/java/cn/flightfeather/thirdapp/util/DialogUtil2.kt
@@ -21,6 +21,29 @@
 */
object DialogUtil2 {
    fun showLoadingDialog(context: Context, message: CharSequence?, cancelable: Boolean, cancelListener: DialogInterface.OnCancelListener?): Dialog? {
        val dialog = Dialog(context)
        val view = LayoutInflater.from(context).inflate(R.layout.layout_loading, null)
        dialog.setContentView(view)
        if (message.isNullOrBlank()) {
            view.findViewById<TextView>(R.id.txt_tip).visibility = View.GONE
        } else {
            view.findViewById<TextView>(R.id.txt_tip).apply {
                visibility = View.VISIBLE
                text = message
            }
        }
        dialog.setCanceledOnTouchOutside(false)
        dialog.setCancelable(cancelable)
        dialog.setOnCancelListener(cancelListener)
        dialog.window?.attributes?.gravity = Gravity.CENTER
        val lp = dialog.window?.attributes
        lp?.dimAmount = 0.2f
        dialog.window?.attributes = lp
        dialog.show()
        return dialog
    }
    fun showAlertDialog(
            context: Context?,
            content: String,
app/src/main/java/cn/flightfeather/thirdapp/util/SystemServiceUtils.kt
@@ -1,5 +1,7 @@
package cn.flightfeather.thirdapp.util
import android.app.Activity
import android.app.Dialog
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
@@ -9,6 +11,10 @@
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentActivity
import android.support.v4.content.FileProvider
import android.webkit.MimeTypeMap
import cn.flightfeather.thirdapp.util.file.FileUtils
import com.flightfeather.taizhang.common.utils.download.UpDownloadUtil
import org.jetbrains.anko.toast
import java.io.File
import java.io.FileOutputStream
@@ -41,22 +47,53 @@
        } ?: ""
    }
    fun shareFile(activity: Activity?, path: String?) {
        if (path?.contains("http") == true) {
            var d: Dialog? = null
            activity?.let {
                d = DialogUtil2.showLoadingDialog(it, "下载中", false, null)
            }
            UpDownloadUtil.download(activity, path, FileUtils.getFileName(path), {
                d?.dismiss()
                share(activity, it)
            }, {
                activity?.toast("下载失败")
                d?.dismiss()
            })
        } else {
            share(activity, path)
        }
    }
    fun saveBitmap(path: String, bitmap: Bitmap) {
    fun saveBitmap(path: String, bitmap: Bitmap): Boolean {
        val file = File(path)
        if (!file.parentFile.exists()) {
            file.parentFile.mkdirs()
        }else if (file.exists()) {
        } else if (file.exists()) {
            file.delete()
        }
        try {
            val out = FileOutputStream(file)
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out)
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)
            out.flush()
            out.close()
            return true
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return false
    }
    private fun share(activity: Activity?, path: String?) {
        val uri = FileUtils.getUri(activity, path)
        val extension = FileUtils.getExtensionName(path)
        val intent = Intent().apply {
            action = Intent.ACTION_SEND
            putExtra(Intent.EXTRA_STREAM, uri)
            type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
        }
        activity?.startActivity(Intent.createChooser(intent, "分享文档"))
    }
    private fun getFilePath(): String {
@@ -71,9 +108,9 @@
        val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
        val uri: Uri = if (Build.VERSION.SDK_INT >= 24) {
            FileProvider.getUriForFile(
                activity,
                activity.packageName + ".fileProvider",
                File(mFilePath)
                    activity,
                    activity.packageName + ".fileProvider",
                    File(mFilePath)
            )
        } else {
            Uri.fromFile(File(mFilePath))
app/src/main/java/cn/flightfeather/thirdapp/util/download/UpDownloadUtil.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
package com.flightfeather.taizhang.common.utils.download
import android.content.Context
import cn.flightfeather.thirdapp.common.net.NetWorkProgressListener
import cn.flightfeather.thirdapp.util.file.FileUtils
import com.liulishuo.okdownload.DownloadTask
import com.liulishuo.okdownload.core.cause.EndCause.*
import com.liulishuo.okdownload.kotlin.execute1
import org.jetbrains.anko.doAsync
import java.io.File
/**
 * @author riku
 * Date: 2020/3/6
 */
object UpDownloadUtil {
    /**
     * @param onSuccess ä¸‹è½½å®ŒæˆåŽçš„æ–‡ä»¶è·¯å¾„
     */
    fun download(
        context: Context?, url: String, fileName: String,
        onSuccess: (downloadFilePath: String) -> Unit,
        onFailure: () -> Unit,
        netWorkProgressListener: NetWorkProgressListener? = null
    ) {
        context?.let {
            val parentFile = FileUtils.getCacheDir(it)
            val downloadFilePath = parentFile.path + File.separator + fileName
            val task = DownloadTask.Builder(url, parentFile)
                .setFilename(fileName)
                .setMinIntervalMillisCallbackProcess(16)
                .setPassIfAlreadyCompleted(false)
                .build()
            doAsync {
                task?.execute1(
                    connected = { task, blockCount, currentOffset, totalLength ->
                    },
                    progress = { task, currentOffset, totalLength ->
                        netWorkProgressListener?.onProgress(currentOffset, totalLength)
                    }
                ) { task, cause, realCause, model ->
                    task.tag = null
                    when (cause) {
                        COMPLETED -> {
                            onSuccess(downloadFilePath)
                        }
                        ERROR,
                        CANCELED,
                        FILE_BUSY,
                        SAME_TASK_BUSY,
                        PRE_ALLOCATE_FAILED -> {
                            onFailure()
                        }
                    }
                }
            }
        }
    }
}
app/src/main/java/cn/flightfeather/thirdapp/util/file/FileUtils.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,376 @@
package cn.flightfeather.thirdapp.util.file
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.media.MediaMetadataRetriever
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.support.v4.content.FileProvider
import cn.flightfeather.thirdapp.R
import cn.flightfeather.thirdapp.util.CommonUtils
import cn.flightfeather.thirdapp.util.DateUtil
import cn.flightfeather.thirdapp.util.file.FileUtils.GB
import cn.flightfeather.thirdapp.util.file.FileUtils.KB
import cn.flightfeather.thirdapp.util.file.FileUtils.MB
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import java.io.File
import java.io.FileOutputStream
import java.util.*
import kotlin.collections.ArrayList
import kotlin.math.round
/**
 * @author riku
 * Date: 2019/6/11
 * æ–‡ä»¶æ“ä½œå·¥å…·ç±»
 */
object FileUtils {
    const val KB = 1024L
    const val MB = 1024 * KB
    const val GB = 1024 * MB
    //文档
    private val FILE_EXTENSION_LIST = listOf(
        "xls", "xlsx", "ppt", "pptx", "doc",
        "docx", "pdf", "html", "htm", "txt",
        "rar", "zip", "7z"
    )
    //图片
    private val IMAGE_EXTENSION_LIST = listOf(
        "png", "gif", "jpg", "jpeg"
    )
    //音视频
    val VIDEO_EXTENSION_LIST = listOf(
        "mp4", "mp3", "3gp", "m4a"
    )
    private val FILE_TYPE_TITLE_MAP = mapOf(
        Pair("xls", "EXCEL"),
        Pair("xlsx", "EXCEL"),
        Pair("doc", "WORD"),
        Pair("docx", "WORD"),
        Pair("pdf", "PDF"),
        Pair("ppt", "PPT"),
        Pair("pptx", "PPT")
    )
    private const val UNKNOWN = "OTHERS"
    val ROOT_PATH: String = Environment.getExternalStorageDirectory().absolutePath
    /**
     * èŽ·å–ç¼“å­˜ç›®å½•
     */
    fun getCacheDir(context: Context? = null): File {
        return File(Environment.getExternalStorageDirectory().absolutePath, "/TaiZhang/files/")
    }
    fun getAudioDir(): File {
        return File(Environment.getExternalStorageDirectory().absolutePath, "/TaiZhang/audio/")
    }
    /**
     * åŽ‹ç¼©å›¾ç‰‡è‡³JPG格式
     */
    fun compress2JPG(context: Context, path: String): File {
        val file = File(path)
        val opts = BitmapFactory.Options()
        //将图片的长宽缩小为1/2
        opts.inSampleSize = 2
        val bm = BitmapFactory.decodeFile(file.absolutePath, opts)
        return compress2JPG(context, bm)
    }
    fun compress2JPG(context: Context, bitmap: Bitmap): File {
        val fileName = "${Date().time}.jpg"
        val outputFile =
            File(getCacheDir(context), "thumbnail${File.separator}$fileName")
        if (!outputFile.parentFile.exists()) {
            outputFile.parentFile.mkdirs()
        }
//            val opts = BitmapFactory.Options()
//            //将图片的长宽缩小为1/2
//            opts.inSampleSize = 2
//            val bm = BitmapFactory.decodeFile(file.absolutePath, opts)
        val normalSize = 1440
        val width: Int
        val height: Int
        if (bitmap.width >= bitmap.height) {
            width = normalSize
            height = normalSize * bitmap.height / bitmap.width
        } else {
            height = normalSize
            width = normalSize * bitmap.width / bitmap.height
        }
        val bmSmall = Bitmap.createScaledBitmap(bitmap, width, height, true)
        bmSmall.compress(Bitmap.CompressFormat.JPEG, 80, FileOutputStream(outputFile.absolutePath))
        bitmap.recycle()
        bmSmall.recycle()
        return outputFile
    }
    private fun getAllFile(path: String = ROOT_PATH, index: Int = 0, onFound: (fileItems: List<FileItem>) -> Unit) {
        val file = File(path)
        var files = emptyArray<File>()
        try {
            files = file.listFiles()
        } catch (e: Exception) {
            e.printStackTrace()
        }
        //获取失败
//        if (files.isEmpty()) {
//            onFound(emptyList())
//        }
        for (f in files) {
            if (f.isHidden) continue
            if (path != ROOT_PATH ||
                (f.path.contains("download", true)
                        || f.path.contains("android", true)
                        || f.path.contains("tencent", true)
                        )
            ) {
                //如果是文件目录,则继续查找
                if (f.isDirectory) {
                    getAllFile(f.path, index + 1, onFound)
                } else if (getOfficeFileTitle(getExtensionName(f.name)) != UNKNOWN) {
                    val updateTime = DateUtil.getYearToMinStr(Date(f.lastModified()))
                    onFound(
                        listOf(
                            FileItem(f.name, f.path, updateTime, f.size())
                        )
                    )
                }
            }
        }
        //判断进入的第一层文件路径的所有文件遍历完成后,返回一个特定的对象表示查询结束
        if (index == 0) {
            onFound(
                listOf(
                    FileItem("done", "done")
                )
            )
        }
    }
    /**
     * èŽ·å–æ–‡ä»¶è·¯å¾„ä¸‹çš„æ‰€æœ‰æ–‡ä»¶åˆ—è¡¨
     */
    fun getAllFiles(path: String = ROOT_PATH): Observable<List<FileItem>> = Observable.create<List<FileItem>> { emitter ->
        getAllFile(path) {
            emitter.onNext(it)
        }
        emitter.onComplete()
    }.subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
    /**
     * èŽ·å–æ–‡ä»¶è·¯å¾„ä¸‹çš„æ‰€æœ‰æ–‡ä»¶åˆ—è¡¨
     */
    fun showFileDir(path: String = ROOT_PATH): List<FileItem> {
        val fileListItems = mutableListOf<FileItem>()
        val file = File(path)
        var files = emptyArray<File>()
        try {
            files = file.listFiles()
        } catch (e: Exception) {
            e.printStackTrace()
        }
        //获取失败
        if (files.isEmpty()) {
            return emptyList()
        }
        //如果当前目录不是根目录
//        if (ROOT_PATH != path) {
//            fileListItems.add(FileItem("@1", ROOT_PATH))
//            fileListItems.add(FileItem("@2", file.parent))
//        }
        files.sortWith(compareBy({ !it.isDirectory }, { it.name }))
        //添加所有文件
        for (f in files) {
            if (!f.isHidden) {
                val updateTime = DateUtil.getYearToMinStr(Date(f.lastModified()))
                fileListItems.add(FileItem(f.name, f.path, updateTime, f.size(), f.list()?.size ?: 0))
            }
        }
        return fileListItems
    }
    /**
     * èŽ·å–æ–‡ä»¶æ‰©å±•å
     */
    fun getExtensionName(filename: String?): String {
        if (!filename.isNullOrEmpty()) {
            val dot = filename.lastIndexOf('.')
            if (dot > -1 && dot < filename.length - 1) {
                return filename.substring(dot + 1)
            }
        }
        return ""
    }
    /**
     * èŽ·å–æ–‡ä»¶å
     */
    fun getFileName(path: String?): String {
        if (!path.isNullOrEmpty()) {
            val dot = path.lastIndexOf('/')
            if (dot > -1 && dot < path.length - 1) {
                return path.substring(dot + 1)
            }
        }
        return ""
    }
    /**
     * èŽ·å–æ–‡ä»¶ç±»åž‹å¯¹åº”çš„ç®€ç§°æ ‡é¢˜
     */
    fun getOfficeFileTitle(extensionName: String): String =
        FILE_TYPE_TITLE_MAP[extensionName] ?: UNKNOWN
    fun getOfficeFileTitleByName(fileName:String):String =
        getOfficeFileTitle(getExtensionName(fileName))
    /**
     * èŽ·å–æ–‡ä»¶ç±»åž‹ä¸­æ–‡ç®€ç§°
     */
    fun getFileTypeName(path: String?): String = when (getExtensionName(path)) {
        in FILE_EXTENSION_LIST -> "文档"
        in IMAGE_EXTENSION_LIST -> "图片"
        in VIDEO_EXTENSION_LIST -> "音视频"
        else -> "其他"
    }
    fun hasEnoughMemory(file: File): Boolean {
        return file.freeSpace > 50 * MB
    }
    /**
     * èŽ·å–è§†é¢‘ç¼©ç•¥å›¾
     */
    fun getVideoBitmapObservable(context: Context, uri: String?): Observable<File> =
        Observable.create<File> { emitter ->
            val retriever = MediaMetadataRetriever()
            try {
                if (uri?.contains("http") == true) {
                    retriever.setDataSource(uri, mutableMapOf<String, String>())
                } else {
                    retriever.setDataSource(uri)
                }
                val bitmap = retriever.frameAtTime
                if (bitmap != null) {
                    val b = compress2JPG(context, bitmap)
                    emitter.onNext(b)
                }
            } catch (e: Exception) {
                emitter.onError(e)
            }
            emitter.onComplete()
        }.subscribeOn(Schedulers.io())
    fun getVideoBitmap(context: Context, uri: String?): File? {
        val retriever = MediaMetadataRetriever()
        try {
            if (uri?.contains("http") == true) {
                retriever.setDataSource(uri, mutableMapOf<String, String>())
            } else {
                retriever.setDataSource(uri)
            }
            val bitmap = retriever.frameAtTime
            if (bitmap != null) {
                compress2JPG(context, bitmap).let {
                    return it
                }
            }
        } catch (e: Exception) {
        }
        return null
    }
    fun getUri(context: Context?, path: String?): Uri? {
        return getUri(context, File(path))
    }
    fun getUri(context: Context?, file: File): Uri? {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            context?.let {
                FileProvider.getUriForFile(it, it.getString(R.string.file_provide), file)
            }
        } else {
            Uri.fromFile(file)
        }
    }
    fun parseToFileSize(length: Long): String {
        return when (length) {
            in 0..KB -> "$length B"
            in KB..MB -> "${round(length.toDouble().div(KB.toDouble()).times(100)).div(100.0)} K"
            in MB..GB -> "${round(length.toDouble().div(MB.toDouble()).times(100)).div(100.0)} M"
            else -> if (length >= GB) {
                "${round(length.toDouble().div(GB.toDouble()).times(100)).div(100.0)} G"
            } else {
                ""
            }
        }
    }
}
/**
 * æ‹“展文件列表删除
 */
fun List<File>.delete() {
    this.forEach {
        it.delete()
    }
}
/**
 * æ‹“展获取文件大小
 */
fun File.size(): String {
    return when (val bytes = this.length()) {
        in 0..KB -> "$bytes B"
        in KB..MB -> "${round(bytes.toDouble().div(KB.toDouble()).times(100)).div(100)} K"
        in MB..GB -> "${round(bytes.toDouble().div(MB.toDouble()).times(100)).div(100)} M"
        else -> if (bytes >= GB) {
            "${round(bytes.toDouble().div(GB.toDouble()).times(100)).div(100)} G"
        } else {
            ""
        }
    }
}
data class FileItem(
    val name: String,
    val path: String,
    val updateTime: String = "",
    val size: String = "",
    val listFileNum: Int = 0
)
app/src/main/java/cn/flightfeather/thirdapp/util/tbs/Tbs.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,36 @@
package cn.flightfeather.thirdapp.util.tbs
import android.content.Context
import com.tencent.smtt.sdk.QbSdk
/**
 * è…¾è®¯tbs å†…核,目前用于浏览office文档
 * @author riku
 * Date: 2019/12/31
 */
class Tbs {
    companion object {
        fun init(applicationContext: Context) {
            //搜集本地tbs内核信息并上报服务器,服务器返回结果决定使用哪个内核。
            val cb = object : QbSdk.PreInitCallback {
                override fun onViewInitFinished(arg0: Boolean) {
                    // TODO Auto-generated method stub
                    //x5內核初始化完成的回调,为true表示x5内核加载成功,否则表示x5内核加载失败,会自动切换到系统内核。
                }
                override fun onCoreInitFinished() {
                    // TODO Auto-generated method stub
                }
            }
            //x5内核初始化接口
            QbSdk.initX5Environment(applicationContext, cb)
        }
    }
}
app/src/main/java/cn/flightfeather/thirdapp/view/recyclerview/DataLoadInterface.kt
ÎļþÒÑɾ³ý
app/src/main/java/cn/flightfeather/thirdapp/view/recyclerview/DataLoadModel.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,134 @@
package cn.flightfeather.thirdapp.view.recyclerview
import android.content.Context
import cn.flightfeather.thirdapp.common.net.ResultCallBack
import org.jetbrains.anko.runOnUiThread
/**
 * @author riku
 * Date: 2020/12/24
 * åˆ—表数据加载逻辑
 */
abstract class DataLoadModel<T>(private val application: Context) : ResultCallBack<List<T>> {
    var dataList = listOf<T>()
    private var loadState = LoadState.NONE
    private var needMore = true
    private var totalPage: Int = -1
    private var currentPage = 1
    var loadStateListener: (loadState: LoadState) -> Unit = {}
    var dataLoadListener: (dataList: List<T>) -> Unit = {}
    /**
     * æ•°æ®é‡è½½
     */
    open fun refresh() {
        if (isLoading()) {
            return
        }
        currentPage = 1
        loadState = LoadState.Refresh
        onLoadState(loadState)
        loadDataByRefresh()
    }
    /**
     * åŠ è½½æ›´å¤š
     */
    open fun loadMore() {
        if (isLoading()) {
            return
        }
        currentPage++
        loadState = LoadState.LoadMore
        onLoadState(loadState)
        loadDataByLoadMore(currentPage)
    }
    /**
     * åŠ è½½å®Œæˆï¼Œåˆ·æ–°åŠ è½½çŠ¶æ€
     */
    private fun completeLoadData(isFail: Boolean = false) {
        loadState = when (loadState) {
            LoadState.Refresh -> if (!isFail) LoadState.RefreshDone else LoadState.RefreshFail
            LoadState.LoadMore -> if (!isFail) {
                if (needMore) {
                    LoadState.LoadMoreComplete
                } else {
                    LoadState.LoadMoreEnd
                }
            } else LoadState.LoadMoreFail
            LoadState.NONE -> LoadState.RefreshDone
            else -> LoadState.RefreshDone
        }
        onLoadState(loadState)
    }
    /**
     * åˆ·æ–°çŠ¶æ€åˆ¤æ–­
     */
    private fun isLoading(): Boolean =
            loadState == LoadState.Refresh || loadState == LoadState.LoadMore
    /**
     * æ•°æ®æ›´æ–°
     */
    private fun commitResult(result: List<T>?) {
        result?.let {
            dataList = it
            onDataLoad(dataList)
        }
    }
    //根据分页判断当前执行的是刷新还是加载更多
    fun isFirstData(): Boolean = currentPage == 1
    override fun onPage(current: Int, total: Int) {
        if (total > 0) {
            totalPage = total
        }
        if (current > 0) {
            currentPage = current
        }
        application.runOnUiThread {
            needMore = (currentPage < totalPage)
        }
    }
    override fun onSuccess(result: List<T>?) {
        commitResult(result)
        completeLoadData()
    }
    override fun onCacheSuccess(result: List<T>?) {
        if (isFirstData()) {
            application.runOnUiThread {
                result?.let {
                    commitResult(it)
                }
            }
        }
    }
    override fun onFailure() {
        completeLoadData(true)
        //获取新的下页信息失败时,分页数还原
        if (currentPage > 2) {
            currentPage--
        }
    }
    private fun onLoadState(loadState: LoadState) = loadStateListener(loadState)
    private fun onDataLoad(dataList: List<T>) = dataLoadListener(dataList)
    abstract fun loadDataByRefresh()
    abstract fun loadDataByLoadMore(page: Int)
}
app/src/main/java/cn/flightfeather/thirdapp/view/recyclerview/EmptyLoadMoreView.kt
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package cn.flightfeather.thirdapp.view.recyclerview
import cn.flightfeather.thirdapp.R
import com.chad.library.adapter.base.loadmore.LoadMoreView
/**
 * @author riku
 * Date: 2020/12/31
 */
class EmptyLoadMoreView : LoadMoreView() {
    override fun getLayoutId(): Int = R.layout.layout_empty_load_more
    override fun getLoadingViewId(): Int = R.id.loading
    override fun getLoadFailViewId(): Int = R.id.load_fail
    override fun getLoadEndViewId(): Int = R.id.load_end
}
app/src/main/java/cn/flightfeather/thirdapp/view/recyclerview/RecyclerViewPanel.kt
@@ -1,173 +1,164 @@
//package cn.flightfeather.thirdapp.view.recyclerview
//
//import android.annotation.SuppressLint
//import android.arch.lifecycle.LifecycleOwner
//import android.arch.lifecycle.Observer
//import android.content.Context
//import android.support.v4.content.ContextCompat
//import android.support.v4.widget.SwipeRefreshLayout
//import android.support.v7.widget.LinearLayoutManager
//import android.support.v7.widget.RecyclerView
//import android.view.LayoutInflater
//import android.view.View
//import com.chad.library.adapter.base.BaseQuickAdapter
//import com.chad.library.adapter.base.BaseViewHolder
//
///**
// * RecyclerView模块
// * @author riku
// * Date: 2019/11/22
// * reference layout is [R.layout.layout_recycler_view_refresh]
// */
//abstract class RecyclerViewPanel<T>(
//        private val viewModel: BaseViewModel<T>,
//        private val lifecycleObserver: LifecycleOwner,
//        private val rootView: View? = null
//) : RecyclerViewSetInterface<T>, SwipeRefreshLayoutSetInterface {
//
//    constructor(
//            viewModel: BaseViewModel<T>,
//            lifecycleObserver: LifecycleOwner,
//            recyclerView: RecyclerView,
//            context: Context?,
//            refreshLayout: SwipeRefreshLayout? = null
//    ) : this(viewModel, lifecycleObserver) {
//        context?.let { this.context = it }
//        tempRecyclerView = recyclerView
//        this.tempRefreshLayout = refreshLayout
//    }
//
//    private lateinit var context: Context
//    private var tempRecyclerView: RecyclerView? = null
//    private var tempRefreshLayout: SwipeRefreshLayout? = null
//
//    override var adapter: BaseRecyclerAdapter<T>? = null
//
//    private var mRecyclerView: RecyclerView? = null
//
//    private var refreshLayout: SwipeRefreshLayout? = null
//
//    init {
//        if (rootView != null) {
//            this@RecyclerViewPanel.context = rootView.context
//        }
//    }
//
//    open fun init() {
//        initViews()
//        initList()
//        initSwipeRefreshLayout()
//        initObserver()
//    }
//
//    private fun initViews() {
//        mRecyclerView = rootView?.findViewById(R.id.recycler_view) ?: tempRecyclerView
//        refreshLayout = rootView?.findViewById(R.id.refresh_layout) ?: tempRefreshLayout
//    }
//
//    open fun initObserver() {
//        viewModel.loading.observe(lifecycleObserver, Observer {
//            refreshLoadingStatus(it)
//        })
//
//        viewModel.dataList.observe(lifecycleObserver, Observer { dataList ->
//            dataList?.let {
//                if (viewModel.isFirstData()) {
//                    setNewData(it)
//                } else {
//                    addData(it)
//                }
//            }
//        })
//
//        viewModel.dataChanged.observe(lifecycleObserver, Observer {
//            if (it == true) {
//                adapter?.notifyDataSetChanged()
//            }
//        })
//    }
//
//    override fun getRecyclerView(): RecyclerView? =
//            mRecyclerView ?: rootView?.findViewById(R.id.recycler_view) ?: tempRecyclerView
//
//    override fun onRefreshDone() = stopRefresh()
//    override fun onRefreshFail() = stopRefresh()
//    override fun onLoadMoreEnd() = Unit
//    override fun onLoadMoreComplete() = Unit
//    override fun onLoadMoreFail() = Unit
//    override fun onRefreshNone() = stopRefresh()
//
//    override fun getMyLayoutManager(): RecyclerView.LayoutManager =
//            LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
//
//    override fun getItemLayoutIdMap(): Map<Int, Int> = emptyMap()
//
//    override fun getSectionLayoutId(): Int = R.layout.recycler_item_section_head
//
//    override fun getSectionDataList(): List<MySection<T>> =
//            MySection.convert2Section(viewModel.dataList.value)
//
//    override fun onItemClick(
//            adapter: BaseQuickAdapter<Any?, BaseViewHolder>,
//            view: View,
//            position: Int,
//            dataList: List<T>
//    ) = Unit
//
//    override fun onItemChildClick(
//            adapter: BaseQuickAdapter<Any?, BaseViewHolder>,
//            view: View,
//            position: Int,
//            dataList: List<T>
//    ) = Unit
//
//    override fun enableLoadMore(): Boolean = true
//
//    override fun onLoadMoreStart() {
//        if (getSwipeRefreshLayout()?.isRefreshing == true) {
//            adapter?.loadMoreComplete()
//            return
//        }
//    }
//
//    override fun onLoadMoreRequested() = viewModel.loadMore()
//
//    override fun enableUpFetch(): Boolean = false
//
//    @SuppressLint("InflateParams")
//    override fun getMyEmptyView(): View? =
//            LayoutInflater.from(context).inflate(R.layout.layout_empty_view, null)
//
//    @SuppressLint("InflateParams")
//    override fun getMyLoadingView(): View? = LayoutInflater.from(context).inflate(R.layout.layout_loading_view, null)
//
//    @SuppressLint("InflateParams")
//    override fun getMyLoadFailView(): View? = LayoutInflater.from(context).inflate(R.layout.layout_load_fail_view, null)
//
//    //******************************SwipeRefreshLayout************************************************************
//
//    override fun getSwipeRefreshLayout(): SwipeRefreshLayout? =
//            refreshLayout ?: rootView?.findViewById(R.id.refresh_layout) ?: tempRefreshLayout
//
//    override fun enableRefresh(): Boolean = true
//
//    override fun needSwipeRefresh(): Boolean = true
//
//    override fun onRefreshRequested() {
//        //第三方recyclerView的上拉加载结束后,如果下拉刷新执行,则应该重新打开监听
//        try {
//            if (!adapter?.isLoadMoreEnable!!) {
//                setLoadMore()
//            }
//        } catch (e: Exception) {
//            e.printStackTrace()
//        }
//        viewModel.refresh()
//    }
//
//    override fun getColorList(): Array<Int> = arrayOf(
//            ContextCompat.getColor(context, R.color.colorPrimary),
//            ContextCompat.getColor(context, R.color.colorPrimaryDark),
//            ContextCompat.getColor(context, R.color.colorAccent)
//    )
//}
package cn.flightfeather.thirdapp.view.recyclerview
import android.annotation.SuppressLint
import android.arch.lifecycle.LifecycleOwner
import android.arch.lifecycle.Observer
import android.content.Context
import android.support.v4.content.ContextCompat
import android.support.v4.widget.SwipeRefreshLayout
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import cn.flightfeather.thirdapp.R
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.BaseViewHolder
/**
 * RecyclerView模块
 * @author riku
 * Date: 2019/11/22
 * reference layout is [R.layout.layout_recycler_view_refresh]
 */
abstract class RecyclerViewPanel<T>(
        private val dataLoadModel: DataLoadModel<T>,
        private val rootView: View? = null
) : RecyclerViewSetInterface<T>, SwipeRefreshLayoutSetInterface {
    constructor(
            dataLoadModel: DataLoadModel<T>,
            recyclerView: RecyclerView,
            context: Context?,
            refreshLayout: SwipeRefreshLayout? = null
    ) : this(dataLoadModel) {
        context?.let { this.context = it }
        tempRecyclerView = recyclerView
        this.tempRefreshLayout = refreshLayout
    }
    private lateinit var context: Context
    private var tempRecyclerView: RecyclerView? = null
    private var tempRefreshLayout: SwipeRefreshLayout? = null
    override var adapter: BaseRecyclerAdapter<T>? = null
    private var mRecyclerView: RecyclerView? = null
    private var refreshLayout: SwipeRefreshLayout? = null
    init {
        if (rootView != null) {
            this@RecyclerViewPanel.context = rootView.context
        }
    }
    open fun init() {
        initViews()
        initList()
        initSwipeRefreshLayout()
        initObserver()
    }
    private fun initViews() {
        mRecyclerView = rootView?.findViewById(R.id.recycler_view) ?: tempRecyclerView
        refreshLayout = rootView?.findViewById(R.id.refresh_layout) ?: tempRefreshLayout
    }
    open fun initObserver() {
        dataLoadModel.loadStateListener = {
            refreshLoadingStatus(it)
        }
        dataLoadModel.dataLoadListener = {
            if (dataLoadModel.isFirstData()) {
                setNewData(it)
            } else {
                addData(it)
            }
        }
    }
    override fun getRecyclerView(): RecyclerView? =
            mRecyclerView ?: rootView?.findViewById(R.id.recycler_view) ?: tempRecyclerView
    override fun onRefreshDone() = stopRefresh()
    override fun onRefreshFail() = stopRefresh()
    override fun onLoadMoreEnd() = Unit
    override fun onLoadMoreComplete() = Unit
    override fun onLoadMoreFail() = Unit
    override fun onRefreshNone() = stopRefresh()
    override fun getMyLayoutManager(): RecyclerView.LayoutManager =
            LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
    override fun getItemLayoutIdMap(): Map<Int, Int> = emptyMap()
    override fun getSectionLayoutId(): Int = R.layout.recycler_item_section_head
    override fun getSectionDataList(): List<MySection<T>> =
            MySection.convert2Section(dataLoadModel.dataList)
    override fun onItemClick(
            adapter: BaseQuickAdapter<Any?, BaseViewHolder>,
            view: View,
            position: Int,
            dataList: List<T>
    ) = Unit
    override fun onItemChildClick(
            adapter: BaseQuickAdapter<Any?, BaseViewHolder>,
            view: View,
            position: Int,
            dataList: List<T>
    ) = Unit
    override fun enableLoadMore(): Boolean = true
    override fun onLoadMoreStart() {
        if (getSwipeRefreshLayout()?.isRefreshing == true) {
            adapter?.loadMoreComplete()
            return
        }
    }
    override fun onLoadMoreRequested() = dataLoadModel.loadMore()
    override fun enableUpFetch(): Boolean = false
    @SuppressLint("InflateParams")
    override fun getMyEmptyView(): View? =
            LayoutInflater.from(context).inflate(R.layout.layout_empty_view, null)
    @SuppressLint("InflateParams")
    override fun getMyLoadingView(): View? = LayoutInflater.from(context).inflate(R.layout.layout_loading_view, null)
    @SuppressLint("InflateParams")
    override fun getMyLoadFailView(): View? = LayoutInflater.from(context).inflate(R.layout.layout_load_fail_view, null)
    //******************************SwipeRefreshLayout************************************************************
    override fun getSwipeRefreshLayout(): SwipeRefreshLayout? =
            refreshLayout ?: rootView?.findViewById(R.id.refresh_layout) ?: tempRefreshLayout
    override fun enableRefresh(): Boolean = true
    override fun needSwipeRefresh(): Boolean = true
    override fun onRefreshRequested() {
        //第三方recyclerView的上拉加载结束后,如果下拉刷新执行,则应该重新打开监听
        try {
            if (!adapter?.isLoadMoreEnable!!) {
                setLoadMore()
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        dataLoadModel.refresh()
    }
    override fun getColorList(): Array<Int> = arrayOf(
            ContextCompat.getColor(context, R.color.colorPrimary),
            ContextCompat.getColor(context, R.color.colorPrimaryDark),
            ContextCompat.getColor(context, R.color.colorAccent)
    )
}
app/src/main/java/cn/flightfeather/thirdapp/view/recyclerview/RecyclerViewSetInterface.kt
@@ -5,6 +5,8 @@
import android.view.ViewGroup
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.BaseViewHolder
import com.chad.library.adapter.base.loadmore.LoadMoreView
import com.chad.library.adapter.base.loadmore.SimpleLoadMoreView
/**
 * @author riku
@@ -65,7 +67,7 @@
            //设置空布局
            getMyLoadingView()?.let { emptyView = it }
//            setLoadMoreView(SimpleLoadMoreView())
            getLoadMoreView()?.let { setLoadMoreView(it)}
        }
        //加载更多
        setLoadMore()
@@ -117,7 +119,7 @@
    /**
     * å°†åˆ—表数据替换成新的数据
     */
    fun setNewData(dataList: ArrayList<T>) {
    fun setNewData(dataList: List<T>) {
        val resultList = convertToSection(dataList)
        addSection(resultList)
        adapter?.setNewData(resultList)
@@ -127,14 +129,14 @@
    /**
     * åœ¨åŽŸæ•°æ®åŸºç¡€ä¸Šæ·»åŠ æ–°æ•°æ®
     */
    fun addData(dataList: ArrayList<T>) {
    fun addData(dataList: List<T>) {
        val resultList = convertToSection(dataList)
        addSection(resultList)
        adapter?.addData(resultList)
        onDataUpdated(adapter)
    }
    fun addData(pos: Int, dataList: ArrayList<T>){
    fun addData(pos: Int, dataList: List<T>){
        val resultList = convertToSection(dataList)
        addSection(resultList)
        adapter?.addData(pos, resultList)
@@ -197,10 +199,10 @@
    fun getSectionLayoutId(): Int
    //自定义是否需要添加列表分组
    fun addSection(dataList: ArrayList<MySection<T>>) = Unit
    fun addSection(dataList: MutableList<MySection<T>>) = Unit
    //将数据转换为列表能接受的固定结构
    fun convertToSection(list: ArrayList<T>): ArrayList<MySection<T>> = MySection.convert2Section(list)
    fun convertToSection(list: List<T>): MutableList<MySection<T>> = MySection.convert2Section(list)
    //数据更新结束
    fun onDataUpdated(adapter: BaseRecyclerAdapter<T>?, pos: Int? = null) = Unit
@@ -260,6 +262,9 @@
    //获取空布局
    fun getMyLoadFailView(): View? = null
    //获取加载布局
    fun getLoadMoreView(): LoadMoreView? = null
    //分割线
    fun getDivider(): RecyclerView.ItemDecoration? = null
app/src/main/java/com/ping/greendao/gen/DaoMaster.java
@@ -14,10 +14,10 @@
// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
/**
 * Master of DAO (schema version 12): knows all DAOs.
 * Master of DAO (schema version 13): knows all DAOs.
 */
public class DaoMaster extends AbstractDaoMaster {
    public static final int SCHEMA_VERSION = 12;
    public static final int SCHEMA_VERSION = 13;
    /** Creates underlying database table using DAOs. */
    public static void createAllTables(Database db, boolean ifNotExists) {
@@ -47,6 +47,7 @@
        TaskvertionDao.createTable(db, ifNotExists);
        TownDao.createTable(db, ifNotExists);
        UserinfoDao.createTable(db, ifNotExists);
        MediaFileCacheDao.createTable(db, ifNotExists);
    }
    /** Drops underlying database table using DAOs. */
@@ -77,6 +78,7 @@
        TaskvertionDao.dropTable(db, ifExists);
        TownDao.dropTable(db, ifExists);
        UserinfoDao.dropTable(db, ifExists);
        MediaFileCacheDao.dropTable(db, ifExists);
    }
    /**
@@ -121,6 +123,7 @@
        registerDaoClass(TaskvertionDao.class);
        registerDaoClass(TownDao.class);
        registerDaoClass(UserinfoDao.class);
        registerDaoClass(MediaFileCacheDao.class);
    }
    public DaoSession newSession() {
app/src/main/java/com/ping/greendao/gen/DaoSession.java
@@ -34,6 +34,7 @@
import cn.flightfeather.thirdapp.bean.entity.Taskvertion;
import cn.flightfeather.thirdapp.bean.entity.Town;
import cn.flightfeather.thirdapp.bean.entity.Userinfo;
import cn.flightfeather.thirdapp.bean.entity.MediaFileCache;
import com.ping.greendao.gen.ChangeAdviceDao;
import com.ping.greendao.gen.ChangeEffectDao;
@@ -61,6 +62,7 @@
import com.ping.greendao.gen.TaskvertionDao;
import com.ping.greendao.gen.TownDao;
import com.ping.greendao.gen.UserinfoDao;
import com.ping.greendao.gen.MediaFileCacheDao;
// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
@@ -97,6 +99,7 @@
    private final DaoConfig taskvertionDaoConfig;
    private final DaoConfig townDaoConfig;
    private final DaoConfig userinfoDaoConfig;
    private final DaoConfig mediaFileCacheDaoConfig;
    private final ChangeAdviceDao changeAdviceDao;
    private final ChangeEffectDao changeEffectDao;
@@ -124,6 +127,7 @@
    private final TaskvertionDao taskvertionDao;
    private final TownDao townDao;
    private final UserinfoDao userinfoDao;
    private final MediaFileCacheDao mediaFileCacheDao;
    public DaoSession(Database db, IdentityScopeType type, Map<Class<? extends AbstractDao<?, ?>>, DaoConfig>
            daoConfigMap) {
@@ -207,6 +211,9 @@
        userinfoDaoConfig = daoConfigMap.get(UserinfoDao.class).clone();
        userinfoDaoConfig.initIdentityScope(type);
        mediaFileCacheDaoConfig = daoConfigMap.get(MediaFileCacheDao.class).clone();
        mediaFileCacheDaoConfig.initIdentityScope(type);
        changeAdviceDao = new ChangeAdviceDao(changeAdviceDaoConfig, this);
        changeEffectDao = new ChangeEffectDao(changeEffectDaoConfig, this);
        cityDao = new CityDao(cityDaoConfig, this);
@@ -233,6 +240,7 @@
        taskvertionDao = new TaskvertionDao(taskvertionDaoConfig, this);
        townDao = new TownDao(townDaoConfig, this);
        userinfoDao = new UserinfoDao(userinfoDaoConfig, this);
        mediaFileCacheDao = new MediaFileCacheDao(mediaFileCacheDaoConfig, this);
        registerDao(ChangeAdvice.class, changeAdviceDao);
        registerDao(ChangeEffect.class, changeEffectDao);
@@ -260,6 +268,7 @@
        registerDao(Taskvertion.class, taskvertionDao);
        registerDao(Town.class, townDao);
        registerDao(Userinfo.class, userinfoDao);
        registerDao(MediaFileCache.class, mediaFileCacheDao);
    }
    
    public void clear() {
@@ -289,6 +298,7 @@
        taskvertionDaoConfig.clearIdentityScope();
        townDaoConfig.clearIdentityScope();
        userinfoDaoConfig.clearIdentityScope();
        mediaFileCacheDaoConfig.clearIdentityScope();
    }
    public ChangeAdviceDao getChangeAdviceDao() {
@@ -395,4 +405,8 @@
        return userinfoDao;
    }
    public MediaFileCacheDao getMediaFileCacheDao() {
        return mediaFileCacheDao;
    }
}
app/src/main/java/com/ping/greendao/gen/MediaFileCacheDao.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,157 @@
package com.ping.greendao.gen;
import android.database.Cursor;
import android.database.sqlite.SQLiteStatement;
import org.greenrobot.greendao.AbstractDao;
import org.greenrobot.greendao.Property;
import org.greenrobot.greendao.internal.DaoConfig;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.database.DatabaseStatement;
import cn.flightfeather.thirdapp.bean.entity.MediaFileCache;
// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
/**
 * DAO for table "MEDIA_FILE_CACHE".
*/
public class MediaFileCacheDao extends AbstractDao<MediaFileCache, Long> {
    public static final String TABLENAME = "MEDIA_FILE_CACHE";
    /**
     * Properties of entity MediaFileCache.<br/>
     * Can be used for QueryBuilder and for referencing column names.
     */
    public static class Properties {
        public final static Property Id = new Property(0, Long.class, "id", true, "_id");
        public final static Property Url = new Property(1, String.class, "url", false, "URL");
        public final static Property Path = new Property(2, String.class, "path", false, "PATH");
        public final static Property ThumbnailPath = new Property(3, String.class, "thumbnailPath", false, "THUMBNAIL_PATH");
    }
    public MediaFileCacheDao(DaoConfig config) {
        super(config);
    }
    public MediaFileCacheDao(DaoConfig config, DaoSession daoSession) {
        super(config, daoSession);
    }
    /** Creates the underlying database table. */
    public static void createTable(Database db, boolean ifNotExists) {
        String constraint = ifNotExists? "IF NOT EXISTS ": "";
        db.execSQL("CREATE TABLE " + constraint + "\"MEDIA_FILE_CACHE\" (" + //
                "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id
                "\"URL\" TEXT," + // 1: url
                "\"PATH\" TEXT," + // 2: path
                "\"THUMBNAIL_PATH\" TEXT);"); // 3: thumbnailPath
    }
    /** Drops the underlying database table. */
    public static void dropTable(Database db, boolean ifExists) {
        String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"MEDIA_FILE_CACHE\"";
        db.execSQL(sql);
    }
    @Override
    protected final void bindValues(DatabaseStatement stmt, MediaFileCache entity) {
        stmt.clearBindings();
        Long id = entity.getId();
        if (id != null) {
            stmt.bindLong(1, id);
        }
        String url = entity.getUrl();
        if (url != null) {
            stmt.bindString(2, url);
        }
        String path = entity.getPath();
        if (path != null) {
            stmt.bindString(3, path);
        }
        String thumbnailPath = entity.getThumbnailPath();
        if (thumbnailPath != null) {
            stmt.bindString(4, thumbnailPath);
        }
    }
    @Override
    protected final void bindValues(SQLiteStatement stmt, MediaFileCache entity) {
        stmt.clearBindings();
        Long id = entity.getId();
        if (id != null) {
            stmt.bindLong(1, id);
        }
        String url = entity.getUrl();
        if (url != null) {
            stmt.bindString(2, url);
        }
        String path = entity.getPath();
        if (path != null) {
            stmt.bindString(3, path);
        }
        String thumbnailPath = entity.getThumbnailPath();
        if (thumbnailPath != null) {
            stmt.bindString(4, thumbnailPath);
        }
    }
    @Override
    public Long readKey(Cursor cursor, int offset) {
        return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0);
    }
    @Override
    public MediaFileCache readEntity(Cursor cursor, int offset) {
        MediaFileCache entity = new MediaFileCache( //
            cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id
            cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // url
            cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // path
            cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3) // thumbnailPath
        );
        return entity;
    }
    @Override
    public void readEntity(Cursor cursor, MediaFileCache entity, int offset) {
        entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0));
        entity.setUrl(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1));
        entity.setPath(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2));
        entity.setThumbnailPath(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3));
     }
    @Override
    protected final Long updateKeyAfterInsert(MediaFileCache entity, long rowId) {
        entity.setId(rowId);
        return rowId;
    }
    @Override
    public Long getKey(MediaFileCache entity) {
        if(entity != null) {
            return entity.getId();
        } else {
            return null;
        }
    }
    @Override
    public boolean hasKey(MediaFileCache entity) {
        return entity.getId() != null;
    }
    @Override
    protected final boolean isEntityUpdateable() {
        return true;
    }
}
app/src/main/res/anim/left_enter_3.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="200"
        android:fromXDelta="-100%p" />
</set>
app/src/main/res/anim/left_exit_3.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="200"
        android:toXDelta="-100%p" />
</set>
app/src/main/res/anim/right_enter_2.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="200"
        android:fromXDelta="100%p" />
</set>
app/src/main/res/anim/right_exit_2.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="200"
        android:toXDelta="100%p" />
</set>
app/src/main/res/drawable/selector_bg_green_or_yellow.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/shape_green" android:state_selected="true"/>
    <item android:drawable="@drawable/shape_yellow"></item>
    <item android:drawable="@drawable/shape_yellow" android:state_selected="false"/>
</selector>
app/src/main/res/drawable/shape_bg_gradient_2.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <!-- å¡«å……的颜色 -->
    <!--<solid android:color="#6195B6"/>-->
    <!-- è®¾ç½®æŒ‰é’®çš„四个角为弧形 -->
    <!-- android:radius å¼§å½¢çš„半径 -->
    <!--<corners-->
        <!--android:radius="20dp" />-->
    <!--描边-->
    <!--<stroke-->
        <!--android:width="0dp"-->
        <!--android:color="@color/white" />-->
    <!-- padding:Button里面的文字与Button边界的间隔 -->
    <!--渐变-->
    <gradient
        android:angle="-45"
        android:startColor="#A2D2E8"
        android:centerColor="@color/white"
        android:endColor="@color/white"/>
</shape>
app/src/main/res/layout/activity_fragment_container.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
<!--    <include layout="@layout/tool_bar_layout"/>-->
    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
    </FrameLayout>
</android.support.design.widget.CoordinatorLayout>
app/src/main/res/layout/activity_night_work.xml
@@ -27,13 +27,14 @@
                android:textColor="@color/main_color_1"
                android:textStyle="bold"
                android:textSize="@dimen/textSize_18"
                android:text="最新文件"/>
                android:text="未读文件"/>
            <TextView
                android:id="@+id/txt_more"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginEnd="@dimen/dimen16"
                android:visibility="gone"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintBottom_toBottomOf="@id/txt_title"
                android:text="更多"/>
@@ -68,6 +69,7 @@
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginEnd="@dimen/dimen16"
                android:visibility="gone"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintBottom_toBottomOf="@id/txt_history"
                android:text="更多"/>
app/src/main/res/layout/activity_night_work_manage.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@color/lightGray">
    <include layout="@layout/layout_toolbar_2" />
<!--    <android.support.v4.widget.NestedScrollView-->
<!--        android:layout_width="match_parent"-->
<!--        android:layout_height="match_parent">-->
        <android.support.constraint.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingTop="@dimen/dimen4">
            <TextView
                android:id="@+id/txt_title"
                android:visibility="gone"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="@dimen/dimen16"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                android:textColor="@color/main_color_1"
                android:textStyle="bold"
                android:textSize="@dimen/textSize_notes"
                android:text="夜施文件统计"/>
            <LinearLayout
                android:id="@+id/ll_total"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:layout_marginStart="@dimen/dimen16"
                android:layout_marginEnd="@dimen/dimen4"
                android:gravity="center"
                android:background="@drawable/shape_white"
                app:layout_constraintTop_toBottomOf="@id/txt_title"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintEnd_toStartOf="@id/ll_signed">
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    style="@style/TextStyle.Category"
                    android:layout_gravity="start"
                    android:text="总签发文件"/>
                <TextView
                    android:id="@+id/txt_total_count"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    style="@style/TextStyle.Category.Item"
                    android:layout_marginTop="@dimen/dimen8"
                    android:layout_marginBottom="@dimen/dimen8"
                    android:textSize="@dimen/title_text_size_1"
                    android:text="0"/>
            </LinearLayout>
            <LinearLayout
                android:id="@+id/ll_signed"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:layout_marginStart="@dimen/dimen4"
                android:layout_marginEnd="@dimen/dimen16"
                android:gravity="center"
                android:background="@drawable/shape_white"
                app:layout_constraintTop_toBottomOf="@id/txt_title"
                app:layout_constraintStart_toEndOf="@id/ll_total"
                app:layout_constraintEnd_toEndOf="parent">
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    style="@style/TextStyle.Category"
                    android:layout_gravity="start"
                    android:text="已签收文件"/>
                <TextView
                    android:id="@+id/txt_signed_count"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    style="@style/TextStyle.Category.Item"
                    android:layout_marginTop="@dimen/dimen8"
                    android:layout_marginBottom="@dimen/dimen8"
                    android:textSize="@dimen/title_text_size_1"
                    android:text="0"/>
            </LinearLayout>
            <android.support.v7.widget.RecyclerView
                android:id="@+id/recycler_view"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_marginTop="@dimen/dimen4"
                android:layout_marginStart="@dimen/dimen16"
                android:layout_marginEnd="@dimen/dimen16"
                app:layout_constraintTop_toBottomOf="@id/ll_total"
                app:layout_constraintBottom_toBottomOf="parent"
                tools:listitem="@layout/item_night_work_3"
                tools:itemCount="6"
                app:layoutManager="android.support.v7.widget.LinearLayoutManager"
                android:orientation="vertical"/>
        </android.support.constraint.ConstraintLayout>
<!--    </android.support.v4.widget.NestedScrollView>-->
</LinearLayout>
app/src/main/res/layout/dialog_scene_list.xml
@@ -9,8 +9,6 @@
        android:id="@+id/cv_body"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginStart="@dimen/fab_margin"
        android:layout_marginEnd="@dimen/fab_margin"
        android:layout_marginTop="30dp"
        android:layout_marginBottom="30dp"
        android:padding="@dimen/dimen8"
app/src/main/res/layout/fragment_file_download.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools">
    <include layout="@layout/tool_bar_layout"/>
    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
    <ImageView
        android:id="@+id/img_file_type"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/file_ic_detail_pdf"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginTop="60dp" />
    <TextView
        android:id="@+id/txt_file_name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:textColor="@color/main_color_1"
        android:textSize="18sp"
        android:maxLines="3"
        android:ellipsize="end"
        tools:text="文件名称"
        android:textStyle="bold"
        android:gravity="center"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/img_file_type"
        android:layout_marginTop="@dimen/dimen8"
        android:layout_marginStart="80dp"
        android:layout_marginEnd="80dp"/>
    <ProgressBar
        android:id="@+id/progress_circular"
        android:layout_width="@dimen/title_icon_size_2"
        android:layout_height="@dimen/title_icon_size_2"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/txt_file_name"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintVertical_bias="0.7"
        android:progress="100"
        android:indeterminate="false"
        android:visibility="visible"
        style="?android:attr/progressBarStyle" />
    <com.mikhaellopez.circularprogressbar.CircularProgressBar
        android:id="@+id/circularProgressBar"
        android:layout_width="@dimen/title_icon_size_2"
        android:layout_height="@dimen/title_icon_size_2"
        app:cpb_background_progressbar_color="@color/gray"
        app:cpb_background_progressbar_width="4dp"
        app:cpb_progress_direction="to_right"
        app:cpb_progressbar_color="@color/colorAccent"
        app:cpb_progressbar_width="4dp"
        app:cpb_round_border="false"
        app:cpb_progress="50"
        app:cpb_progress_max="200"
        android:visibility="gone"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/txt_file_name"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintVertical_bias="0.7"/>
    <TextView
        android:id="@+id/txt_progress"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/circularProgressBar"
        android:visibility="gone"
        tools:text="25k/3M"/>
    </android.support.constraint.ConstraintLayout>
</android.support.design.widget.CoordinatorLayout>
app/src/main/res/layout/fragment_home_competent.xml
@@ -124,6 +124,7 @@
                android:layout_height="match_parent"
                android:orientation="vertical">
                <include layout="@layout/function_card1_competent" />
                <include layout="@layout/function_card5_competent" />
                <include layout="@layout/function_card4_competent" />
                <include layout="@layout/function_card2_competent" />
                <include layout="@layout/function_card3_competent" />
app/src/main/res/layout/fragment_home_pollution_scene.xml
@@ -122,6 +122,7 @@
                android:layout_height="match_parent"
                android:orientation="vertical">
                <include layout="@layout/function_card1_scene" />
                <include layout="@layout/function_card5_scene" />
                <include layout="@layout/function_card2_scene"
                    android:visibility="gone"/>
                <include layout="@layout/function_card3_scene" />
app/src/main/res/layout/fragment_office_file.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <include layout="@layout/tool_bar_layout"/>
    <FrameLayout
        android:id="@+id/tbs_reader_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
app/src/main/res/layout/function_card4_scene.xml
@@ -7,7 +7,8 @@
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:paddingStart="@dimen/dimen8"
    android:paddingEnd="@dimen/dimen8">
    android:paddingEnd="@dimen/dimen8"
    android:paddingBottom="@dimen/dimen4">
    <android.support.v7.widget.CardView
        android:id="@+id/card_change_problem"
@@ -37,6 +38,7 @@
                android:text="0"
                android:textColor="#FA4A4D"
                android:textSize="@dimen/textSize_18"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintRight_toRightOf="parent"/>
            <ImageView
                android:id="@+id/image_change_count"
@@ -45,6 +47,7 @@
                android:scaleType="centerInside"
                android:src="@drawable/ic_change"
                android:adjustViewBounds="true"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
            <TextView
                android:id="@+id/textView1"
@@ -87,6 +90,7 @@
                android:text="0"
                android:textColor="#56C4A0"
                android:textSize="@dimen/textSize_18"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintRight_toRightOf="parent"/>
            <ImageView
@@ -96,6 +100,7 @@
                android:src="@drawable/ic_changed"
                android:scaleType="centerInside"
                android:adjustViewBounds="true"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintBottom_toTopOf="@id/textView5"/>
            <TextView
                android:id="@+id/textView5"
@@ -140,6 +145,7 @@
                android:ellipsize="end"
                android:lines="2"
                android:text="您离截止日期还有"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"/>
            <TextView
                android:id="@+id/text_change_left_day"
@@ -171,7 +177,9 @@
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/ic_change_done"
                android:scaleType="centerCrop" />
                android:scaleType="centerCrop"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"/>
        </android.support.constraint.ConstraintLayout>
    </android.support.v7.widget.CardView>
@@ -181,6 +189,7 @@
        android:layout_height="30dp"
        android:textColor="@color/white"
        android:background="@drawable/shape_button_blue"
        android:visibility="gone"
        android:text="去整改"
        android:clickable="true"
        android:focusable="true"
@@ -199,6 +208,7 @@
        android:id="@+id/image_goto_change"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"
        android:src="@drawable/ic_play_arrow_white_24dp"
        app:layout_constraintRight_toRightOf="@id/text_goto_change"
        app:layout_constraintTop_toTopOf="@id/text_goto_change"
app/src/main/res/layout/function_card5_competent.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    style="@style/bigCardView"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardCornerRadius="@dimen/dimen8">
    <android.support.constraint.ConstraintLayout
        android:id="@+id/cl_night_work"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="@dimen/dimen8">
        <ImageView
            android:id="@+id/img_night_work"
            android:layout_width="@dimen/title_icon_size"
            android:layout_height="@dimen/title_icon_size"
            android:background="@drawable/ic_supervise_info"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>
        <TextView
            android:id="@+id/txt_night_work"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:text="夜间施工许可"
            android:textColor="@color/black"
            android:textSize="12sp"
            android:layout_marginStart="10dp"
            app:layout_constraintStart_toEndOf="@id/img_night_work"
            app:layout_constraintTop_toTopOf="@id/img_night_work"
            app:layout_constraintBottom_toBottomOf="@id/img_night_work"/>
        <TextView
            android:id="@+id/txt_news"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/dimen4"
            app:layout_constraintStart_toStartOf="@id/txt_night_work"
            app:layout_constraintTop_toBottomOf="@id/img_night_work"
            android:text="许可证发布统计"/>
        <TextView
            android:id="@+id/txt_more"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="点击查看 >"
            android:textColor="@color/gray"
            android:textSize="10sp"
            app:layout_constraintTop_toBottomOf="@id/txt_news"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"/>
    </android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
app/src/main/res/layout/function_card5_scene.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    style="@style/bigCardView"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardCornerRadius="@dimen/dimen8">
    <android.support.constraint.ConstraintLayout
        android:id="@+id/cl_night_work"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="@dimen/dimen8">
        <ImageView
            android:id="@+id/img_night_work"
            android:layout_width="@dimen/title_icon_size"
            android:layout_height="@dimen/title_icon_size"
            android:background="@drawable/ic_supervise_info"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>
        <TextView
            android:id="@+id/txt_night_work"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:text="夜间施工许可"
            android:textColor="@color/main_text_color"
            android:textSize="@dimen/textSize_16"
            android:layout_marginStart="10dp"
            app:layout_constraintStart_toEndOf="@id/img_night_work"
            app:layout_constraintTop_toTopOf="@id/img_night_work"
            app:layout_constraintBottom_toBottomOf="@id/img_night_work"/>
        <TextView
            android:id="@+id/txt_news"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/dimen4"
            app:layout_constraintStart_toStartOf="@id/txt_night_work"
            app:layout_constraintTop_toBottomOf="@id/img_night_work"
            android:text="暂无新许可证"/>
        <TextView
            android:id="@+id/txt_more"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="点击查看 >"
            android:textColor="@color/gray"
            android:textSize="10sp"
            app:layout_constraintTop_toBottomOf="@id/txt_news"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"/>
    </android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
app/src/main/res/layout/item_night_work.xml
@@ -1,14 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.card.MaterialCardView
<android.support.v7.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:orientation="horizontal"
    android:layout_width="220dp"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    app:cardCornerRadius="@dimen/dimen16"
    app:cardBackgroundColor="@color/white"
    android:layout_marginEnd="@dimen/dimen16"
    android:layout_marginStart="@dimen/dimen4"
    android:layout_marginEnd="@dimen/dimen8"
    android:layout_marginTop="@dimen/dimen4"
    android:layout_marginBottom="@dimen/dimen4">
    <android.support.constraint.ConstraintLayout
@@ -77,14 +79,30 @@
    </android.support.constraint.ConstraintLayout>
    <TextView
        android:id="@+id/txt_sign"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="start|bottom"
        android:background="@drawable/button_bg_enable_2"
        style="@style/TextStyle.Category.Item"
        android:textColor="@color/white"
        android:paddingStart="@dimen/dimen8"
        android:paddingEnd="@dimen/dimen8"
        android:paddingTop="@dimen/dimen2"
        android:paddingBottom="@dimen/dimen2"
        android:layout_marginStart="@dimen/dimen16"
        android:layout_marginBottom="@dimen/dimen16"
        android:text="签收"/>
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="160dp"
        android:src="@mipmap/ic_file"
        android:layout_gravity="bottom|end"
        android:layout_marginTop="150dp"
        android:layout_marginTop="120dp"
        app:layout_constraintTop_toBottomOf="@id/txt_time"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>
</android.support.design.card.MaterialCardView>
</android.support.v7.widget.CardView>
app/src/main/res/layout/item_night_work_2.xml
@@ -13,8 +13,7 @@
        android:id="@+id/img_icon"
        android:layout_width="46dp"
        android:layout_height="46dp"
        android:src="@drawable/button_bg_enable_2"
        android:tint="#1C1E33"
        android:src="@mipmap/ic_file"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
@@ -32,13 +31,14 @@
    <TextView
        android:id="@+id/txt_time"
        android:layout_width="wrap_content"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        style="@style/TextStyle.Category.Item"
        android:textColor="@color/main_color_1"
        tools:text="施工内容"
        android:layout_marginStart="@dimen/dimen16"
        app:layout_constraintStart_toEndOf="@id/img_icon"
        app:layout_constraintEnd_toStartOf="@id/txt_signed"
        app:layout_constraintTop_toBottomOf="@id/txt_1"/>
    <TextView
@@ -65,5 +65,23 @@
        app:layout_constraintBottom_toBottomOf="@id/img_icon"
        app:layout_constraintVertical_bias="1"/>
    <TextView
        android:id="@+id/txt_signed"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="start|bottom"
        android:background="@drawable/button_bg_enable_2"
        style="@style/TextStyle.Category.Item"
        android:backgroundTint="@color/lightGreen"
        android:textColor="@color/white"
        android:paddingStart="@dimen/dimen8"
        android:paddingEnd="@dimen/dimen8"
        android:paddingTop="@dimen/dimen2"
        android:paddingBottom="@dimen/dimen2"
        android:text="已签收"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>
</android.support.constraint.ConstraintLayout>
app/src/main/res/layout/item_night_work_3.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingTop="@dimen/dimen8"
    android:paddingBottom="@dimen/dimen8"
    android:layout_marginBottom="@dimen/dimen4"
    android:background="@color/white">
    <ImageView
        android:id="@+id/img_icon"
        android:visibility="visible"
        android:layout_width="46dp"
        android:layout_height="46dp"
        android:src="@mipmap/ic_file"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
    <TextView
        android:id="@+id/txt_1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        style="@style/TextStyle.Category"
        android:text="项目名称"
        app:layout_constraintStart_toEndOf="@id/img_icon"
        app:layout_constraintTop_toTopOf="parent"/>
    <TextView
        android:id="@+id/txt_content"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        tools:text="项目内容"
        style="@style/TextStyle.Category.Item"
        app:layout_constraintStart_toStartOf="@id/txt_1"
        app:layout_constraintEnd_toStartOf="@id/txt_signed"
        app:layout_constraintTop_toBottomOf="@id/txt_1"/>
    <TextView
        android:id="@+id/txt_2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        style="@style/TextStyle.Category"
        android:text="文件编号"
        android:layout_marginTop="@dimen/dimen16"
        app:layout_constraintStart_toStartOf="@id/txt_content"
        app:layout_constraintTop_toBottomOf="@id/txt_content"/>
    <TextView
        android:id="@+id/txt_night_work_num"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        style="@style/TextStyle.Category.Item"
        tools:text="夜间许可证编号"
        app:layout_constraintStart_toStartOf="@id/txt_1"
        app:layout_constraintTop_toBottomOf="@id/txt_2" />
    <TextView
        android:id="@+id/txt_3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        style="@style/TextStyle.Category"
        android:text="施工时间"
        android:layout_marginTop="@dimen/dimen16"
        app:layout_constraintStart_toStartOf="@id/txt_time"
        app:layout_constraintTop_toBottomOf="@id/txt_content"/>
    <TextView
        android:id="@+id/txt_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        style="@style/TextStyle.Category.Item"
        tools:text="2020.12.01-12.03"
        android:layout_marginStart="@dimen/dimen16"
        app:layout_constraintStart_toEndOf="@id/txt_night_work_num"
        app:layout_constraintTop_toBottomOf="@id/txt_3"/>
    <TextView
        android:id="@+id/txt_signed"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="start|bottom"
        android:background="@drawable/selector_bg_green_or_yellow"
        style="@style/TextStyle.Category.Item"
        android:textColor="@color/white"
        android:paddingStart="@dimen/dimen8"
        android:paddingEnd="@dimen/dimen8"
        android:paddingTop="@dimen/dimen2"
        android:paddingBottom="@dimen/dimen2"
        android:layout_marginEnd="@dimen/dimen4"
        android:text="@string/signed"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>
</android.support.constraint.ConstraintLayout>
app/src/main/res/layout/item_night_work_no_more.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.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:id="@+id/no_more"
    android:orientation="horizontal"
    android:layout_width="200dp"
    android:layout_height="wrap_content"
    app:cardCornerRadius="@dimen/dimen16"
    app:cardBackgroundColor="@color/white"
    android:layout_marginStart="@dimen/dimen4"
    android:layout_marginEnd="@dimen/dimen8"
    android:layout_marginTop="@dimen/dimen4"
    android:layout_marginBottom="@dimen/dimen4">
    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/transparent"
        android:layout_marginTop="50dp"
        android:padding="@dimen/dimen16"
        android:elevation="@dimen/dimen2"
        tools:ignore="UnusedAttribute">
        <TextView
            android:id="@+id/txt_1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            style="@style/TextStyle.Category"
            android:text="文件编号"
            android:visibility="gone"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>
        <TextView
            android:id="@+id/txt_night_work_num"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="到底了~"
            style="@style/TextStyle.Category.Item"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/txt_1"/>
    </android.support.constraint.ConstraintLayout>
    <TextView
        android:id="@+id/txt_sign"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="start|bottom"
        android:background="@drawable/button_bg_enable_2"
        style="@style/TextStyle.Category.Item"
        android:visibility="gone"
        android:textColor="@color/white"
        android:paddingStart="@dimen/dimen8"
        android:paddingEnd="@dimen/dimen8"
        android:paddingTop="@dimen/dimen2"
        android:paddingBottom="@dimen/dimen2"
        android:layout_marginStart="@dimen/textSize_16"
        android:layout_marginBottom="@dimen/dimen16"
        android:text="签收"/>
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="160dp"
        android:src="@mipmap/ic_file"
        android:layout_gravity="bottom|end"
        android:layout_marginTop="120dp"
        app:layout_constraintTop_toBottomOf="@id/txt_time"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>
</android.support.v7.widget.CardView>
app/src/main/res/layout/item_scene_new_task.xml
@@ -12,8 +12,8 @@
    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingLeft="16dp"
        android:paddingRight="16dp"
        android:paddingLeft="@dimen/dimen4"
        android:paddingRight="@dimen/dimen4"
        android:paddingTop="10dp"
        android:paddingBottom="10dp">
        <TextView
@@ -23,7 +23,7 @@
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            android:textSize="17sp"
            android:textSize="@dimen/textSize_16"
            android:gravity="center"
            android:minEms="1"
            tools:text="1"
@@ -38,21 +38,19 @@
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginStart="@dimen/dimen8"
            android:layout_marginEnd="@dimen/dimen8"
            android:singleLine="true"
            android:textSize="17sp"
            tools:text="任务名称"/>
            tools:text="任务名称任务名称任务名称任务名称任务名称任务名称任务名称任务名称任务名称"/>
        <TextView
            android:id="@+id/tv_item_task_list_address"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            app:layout_constraintStart_toStartOf="@id/tv_item_task_list_name"
            app:layout_constraintEnd_toStartOf="@id/tv_scene_type"
            app:layout_constraintEnd_toEndOf="@id/tv_item_task_list_name"
            app:layout_constraintTop_toBottomOf="@id/tv_item_task_list_name"
            app:layout_constraintHorizontal_bias="0"
            android:layout_marginEnd="@dimen/dimen8"
            android:singleLine="true"
            tools:text="任务地点"
            tools:text="任务地点任务地点任务地点任务地点任务地点任务地点任务地点任务地点任务地点任务地点"
            android:textSize="13sp" />
        <TextView
@@ -60,12 +58,12 @@
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            style="@style/textTag"
            app:layout_constraintStart_toEndOf="@id/tv_item_task_list_address"
            app:layout_constraintStart_toStartOf="@id/tv_item_task_list_name"
            app:layout_constraintEnd_toEndOf="@id/tv_item_task_list_name"
            app:layout_constraintTop_toBottomOf="@id/tv_item_task_list_name"
            app:layout_constraintTop_toBottomOf="@id/tv_item_task_list_address"
            app:layout_constraintHorizontal_bias="0"
            android:singleLine="true"
            tools:text="工地" />
            tools:text="工地工地工地工地工地工地工地" />
        <LinearLayout
            android:id="@+id/ll_monitor_num"
app/src/main/res/layout/item_scene_task.xml
@@ -12,8 +12,8 @@
    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingLeft="16dp"
        android:paddingRight="16dp"
        android:paddingLeft="@dimen/dimen4"
        android:paddingRight="@dimen/dimen4"
        android:paddingTop="10dp"
        android:paddingBottom="10dp">
        <TextView
@@ -23,7 +23,7 @@
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            android:textSize="17sp"
            android:textSize="@dimen/textSize_16"
            android:gravity="center"
            android:minEms="1"
            tools:text="1"
@@ -38,21 +38,19 @@
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginStart="@dimen/dimen8"
            android:layout_marginEnd="@dimen/dimen8"
            android:singleLine="true"
            android:textSize="17sp"
            tools:text="任务名称"/>
            tools:text="任务名称任务名称任务名称任务名称任务名称任务名称任务名称任务名称任务名称"/>
        <TextView
            android:id="@+id/tv_item_task_list_address"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            app:layout_constraintStart_toStartOf="@id/tv_item_task_list_name"
            app:layout_constraintEnd_toStartOf="@id/tv_scene_type"
            app:layout_constraintEnd_toEndOf="@id/tv_item_task_list_name"
            app:layout_constraintTop_toBottomOf="@id/tv_item_task_list_name"
            app:layout_constraintHorizontal_bias="0"
            android:layout_marginEnd="@dimen/dimen8"
            android:singleLine="true"
            tools:text="任务地点"
            tools:text="任务地点任务地点任务地点任务地点任务地点任务地点任务地点任务地点任务地点任务地点"
            android:textSize="13sp" />
        <TextView
@@ -60,12 +58,12 @@
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            style="@style/textTag"
            app:layout_constraintStart_toEndOf="@id/tv_item_task_list_address"
            app:layout_constraintStart_toStartOf="@id/tv_item_task_list_name"
            app:layout_constraintEnd_toEndOf="@id/tv_item_task_list_name"
            app:layout_constraintTop_toBottomOf="@id/tv_item_task_list_name"
            app:layout_constraintTop_toBottomOf="@id/tv_item_task_list_address"
            app:layout_constraintHorizontal_bias="0"
            android:singleLine="true"
            tools:text="工地" />
            tools:text="工地工地工地工地工地工地工地" />
        <TextView
app/src/main/res/layout/layout_empty_load_more.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="0dp"
    android:layout_height="0dp"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="@color/transparentGray">
    <View
        android:id="@+id/loading"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <View
        android:id="@+id/load_fail"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <View
        android:id="@+id/load_end"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</FrameLayout>
app/src/main/res/layout/layout_empty_view.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingBottom="100dp"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <ImageView
        android:id="@+id/img_no_data"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintVertical_bias="0.2"
        android:scaleType="centerInside"
        android:src="@mipmap/ic_developing"/>
    <TextView
        android:id="@+id/tv_no_data"
        app:layout_constraintTop_toBottomOf="@id/img_no_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="暂无数据"
        android:gravity="center"
        android:textColor="@color/gray"
        android:visibility="visible"/>
</android.support.constraint.ConstraintLayout>
app/src/main/res/layout/layout_load_fail_view.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <ImageView
        android:id="@+id/img_no_data"
        android:layout_width="0dp"
        android:layout_height="46dp"
        android:visibility="visible"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintVertical_bias="0.2"
        android:scaleType="fitCenter"
        android:src="@drawable/ic_announcement_black_24dp"
        android:tint="@color/secondary_text"/>
    <TextView
        android:id="@+id/tv_no_data"
        app:layout_constraintTop_toBottomOf="@id/img_no_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="加载失败, ä¸‹æ‹‰åˆ·æ–°é‡è¯•"
        android:gravity="center"
        android:textColor="@color/gray"
        android:visibility="visible"/>
</android.support.constraint.ConstraintLayout>
app/src/main/res/layout/layout_loading.xml
@@ -12,9 +12,11 @@
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical|center_horizontal"
        />
    <!--<TextView-->
        <!--android:id="@+id/tipTextView"-->
        <!--android:layout_width="wrap_content"-->
        <!--android:layout_height="wrap_content"-->
        <!--android:title="加载中..."/>-->
    <TextView
        android:id="@+id/txt_tip"
        android:visibility="gone"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical|center_horizontal"
        android:text="加载中..."/>
</LinearLayout>
app/src/main/res/layout/layout_loading_view.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <ProgressBar
        android:id="@+id/view_waiting"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintVertical_bias="0.2" />
    <TextView
        android:id="@+id/tv_no_data"
        app:layout_constraintTop_toBottomOf="@id/view_waiting"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="加载中..."
        android:gravity="center"
        android:textColor="@color/gray"
        android:visibility="visible"/>
</android.support.constraint.ConstraintLayout>
app/src/main/res/layout/layout_night_work_empty.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <android.support.v7.widget.CardView
        android:id="@+id/no_more"
        android:orientation="horizontal"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        app:cardCornerRadius="@dimen/dimen16"
        app:cardBackgroundColor="@color/white"
        android:layout_marginStart="@dimen/dimen4"
        android:layout_marginEnd="@dimen/dimen8"
        android:layout_marginTop="@dimen/dimen4"
        android:layout_marginBottom="@dimen/dimen4">
        <android.support.constraint.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/transparent"
            android:layout_marginTop="50dp"
            android:padding="@dimen/dimen16"
            android:elevation="@dimen/dimen2"
            tools:ignore="UnusedAttribute">
            <TextView
                android:id="@+id/txt_1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                style="@style/TextStyle.Category"
                android:text="文件编号"
                android:visibility="gone"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"/>
            <TextView
                android:id="@+id/txt_night_work_num"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="暂无新的许可证"
                style="@style/TextStyle.Category.Item"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@id/txt_1"/>
        </android.support.constraint.ConstraintLayout>
        <TextView
            android:id="@+id/txt_sign"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="start|bottom"
            android:background="@drawable/button_bg_enable_2"
            style="@style/TextStyle.Category.Item"
            android:visibility="gone"
            android:textColor="@color/white"
            android:paddingStart="@dimen/dimen8"
            android:paddingEnd="@dimen/dimen8"
            android:paddingTop="@dimen/dimen2"
            android:paddingBottom="@dimen/dimen2"
            android:layout_marginStart="@dimen/textSize_16"
            android:layout_marginBottom="@dimen/dimen16"
            android:text="签收"/>
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="160dp"
            android:src="@mipmap/ic_file"
            android:layout_gravity="bottom|end"
            android:layout_marginTop="120dp"
            app:layout_constraintTop_toBottomOf="@id/txt_time"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"/>
    </android.support.v7.widget.CardView>
</FrameLayout>
app/src/main/res/layout/layout_recycler_view_refresh.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/refresh_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">
    <android.support.v7.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toTopOf="parent">
    </android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>
app/src/main/res/layout/layout_toolbar_2.xml
@@ -6,7 +6,7 @@
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/toolbar"
    app:contentInsetStart="0dp"
    android:background="@color/transparent">
    android:background="@color/colorPrimary">
    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
@@ -18,7 +18,6 @@
            android:layout_height="40dp"
            android:padding="@dimen/dimen8"
            android:src="@drawable/ic_menu_back"
            android:tint="#1C1E33"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"/>
@@ -31,7 +30,7 @@
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            android:textColor="#1C1E33"
            android:textColor="@color/white"
            style="@style/ToolbarTitleStyle"
            tools:text="标题"/>
app/src/main/res/layout/recycler_item_section_head.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingTop="@dimen/dimen8"
        android:background="@color/lightGray">
    <TextView
            android:id="@+id/tv_section_head"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/app_name"
            android:background="@android:color/white"
            android:textColor="@color/gray"
            android:elevation="0.5dp">
    </TextView>
</FrameLayout>
app/src/main/res/layout/tool_bar_layout.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/app_bar_layout"
    app:elevation="1dp"
    tools:ignore="UnusedAttribute" >
    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/collapse_tool_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minHeight="@dimen/actionbarHeight"
        app:contentScrim="@color/colorPrimary"
        app:titleEnabled="false"
        app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
        <android.support.constraint.ConstraintLayout
            android:id="@+id/tool_bar_expanded_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_collapseMode="parallax"
            app:layout_collapseParallaxMultiplier="0.85">
        </android.support.constraint.ConstraintLayout>
        <android.support.v7.widget.Toolbar
            android:id="@+id/tool_bar"
            android:layout_width="match_parent"
            android:layout_height="@dimen/actionbarHeight"
            app:layout_collapseMode="pin"
            app:contentInsetStart="0dp">
            <android.support.constraint.ConstraintLayout
                android:visibility="visible"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
                <ImageView
                    android:id="@+id/img_back"
                    android:layout_width="@dimen/title_icon_size_2"
                    android:layout_height="@dimen/title_icon_size_2"
                    android:src="@drawable/ic_menu_back"
                    android:padding="@dimen/dimen8"
                    android:layout_marginStart="@dimen/dimen8"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintBottom_toBottomOf="parent"
                    android:foreground="?attr/selectableItemBackgroundBorderless"
                    tools:ignore="UnusedAttribute"/>
                <TextView
                    android:id="@+id/tv_main_title"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintBottom_toBottomOf="parent"
                    style="@style/ToolbarTitleStyle"
                    tools:text="@string/version"/>
                <ImageView
                    android:id="@+id/img_menu_1"
                    android:layout_width="@dimen/title_icon_size_2"
                    android:layout_height="@dimen/title_icon_size_2"
                    android:padding="8dp"
                    android:tint="@color/white"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toStartOf="@id/img_menu_2"
                    android:foreground="?attr/selectableItemBackground"
                    android:layout_marginEnd="@dimen/dimen8" />
                <ImageView
                    android:id="@+id/img_menu_2"
                    android:layout_width="@dimen/title_icon_size_2"
                    android:layout_height="@dimen/title_icon_size_2"
                    android:padding="8dp"
                    android:tint="@color/white"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toStartOf="@id/img_menu_3"
                    android:foreground="?attr/selectableItemBackground"
                    android:layout_marginEnd="@dimen/dimen8" />
                <ImageView
                    android:id="@+id/img_menu_3"
                    android:layout_width="@dimen/title_icon_size_2"
                    android:layout_height="@dimen/title_icon_size_2"
                    android:padding="8dp"
                    android:tint="@color/white"
                    app:layout_constraintTop_toTopOf="parent"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    android:foreground="?attr/selectableItemBackground"
                    android:layout_marginEnd="@dimen/dimen8" />
            </android.support.constraint.ConstraintLayout>
        </android.support.v7.widget.Toolbar>
    </android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
app/src/main/res/mipmap-hdpi/ic_developing.png
app/src/main/res/mipmap-mdpi/ic_developing.png
app/src/main/res/mipmap-xhdpi/file_ic_detail_excel.png
app/src/main/res/mipmap-xhdpi/file_ic_detail_pdf.png
app/src/main/res/mipmap-xhdpi/ic_developing.png
app/src/main/res/mipmap-xhdpi/ic_share.png
app/src/main/res/mipmap-xxhdpi/ic_developing.png
app/src/main/res/mipmap-xxxhdpi/ic_developing.png
app/src/main/res/values/strings.xml
@@ -14,6 +14,8 @@
    <!--任务fragment文字-->
    <string name="task">任务</string>
    <string name="file_provide">cn.flightfeather.thirdapp.fileProvider</string>
    <!--创建月任务-->
    <string name="new_month_task">创建月任务</string>
    <string name="task_name">任务名称</string>
@@ -142,5 +144,7 @@
    <string name="title_activity_new_top_task_map">NewTopTaskMapActivity</string>
    <string name="info_name">名称:</string>
    <string name="minus">- </string>
    <string name="signed">已签收</string>
    <string name="unsigned">未签收</string>
</resources>
app/src/main/res/values/styles.xml
@@ -237,12 +237,12 @@
    </style>
    <style name="TextStyle.Category">
        <item name="android:textSize">@dimen/textSize_notes</item>
        <item name="android:textSize">10sp</item>
        <item name="android:textColor">@color/main_color_3</item>
    </style>
    <style name="TextStyle.Category.Item">
        <item name="android:textSize">@dimen/textSize_16</item>
        <item name="android:textSize">@dimen/textSize_14</item>
        <item name="android:textStyle">bold</item>
        <item name="android:textColor">@color/main_color_1</item>
    </style>
app/src/test/java/cn/flightfeather/thirdapp/Test.kt
@@ -42,4 +42,11 @@
        val s = Gson().toJson(list)
        println(s)
    }
    @Test
    fun foo4() {
        val list = listOf(1, 2, 3)
        list.toMutableList().clear()
        println(list)
    }
}
build.gradle
@@ -8,6 +8,8 @@
    ext.image_picker_version = '2.2.7'
    ext.glide_version = '4.9.0'
    ext.adaper_version = '2.9.46'
    ext.file_download_version = '1.0.7'
    ext.progressbar_version = '3.0.3'
    repositories {
        jcenter()