Compare commits

..

10 Commits

  1. 1
      app/build.gradle
  2. 114
      app/schemas/cc.niushuai.didicheck.biz.room.DiDiCheckDataBase/3.json
  3. 114
      app/schemas/cc.niushuai.didicheck.biz.room.DiDiCheckDataBase/4.json
  4. 78
      app/src/main/java/cc/niushuai/didicheck/MainActivity.java
  5. 148
      app/src/main/java/cc/niushuai/didicheck/base/activity/BaseActivity.java
  6. 139
      app/src/main/java/cc/niushuai/didicheck/base/adapter/BaseRecyclerAdapter.java
  7. 52
      app/src/main/java/cc/niushuai/didicheck/base/fragment/BaseFragment.java
  8. 95
      app/src/main/java/cc/niushuai/didicheck/base/fragment/FragmentAdapter.java
  9. 34
      app/src/main/java/cc/niushuai/didicheck/biz/dao/CheckProjectDao.java
  10. 6
      app/src/main/java/cc/niushuai/didicheck/biz/dao/CheckRecordDao.java
  11. 65
      app/src/main/java/cc/niushuai/didicheck/biz/entity/CheckProject.java
  12. 6
      app/src/main/java/cc/niushuai/didicheck/biz/room/DBManager.java
  13. 6
      app/src/main/java/cc/niushuai/didicheck/biz/room/DiDiCheckDataBase.java
  14. 283
      app/src/main/java/cc/niushuai/didicheck/ui/group/GroupItemDecoration.java
  15. 135
      app/src/main/java/cc/niushuai/didicheck/ui/group/GroupRecyclerAdapter.java
  16. 92
      app/src/main/java/cc/niushuai/didicheck/ui/group/GroupRecyclerView.java
  17. 91
      app/src/main/java/cc/niushuai/didicheck/ui/index/IndexMonthView.java
  18. 103
      app/src/main/java/cc/niushuai/didicheck/ui/index/IndexWeekView.java
  19. 4
      app/src/main/java/cc/niushuai/didicheck/ui/index/x.java
  20. 3
      app/src/main/java/cc/niushuai/didicheck/ui/main/TabsPagerAdapter.java
  21. 86
      app/src/main/java/cc/niushuai/didicheck/ui/main/home/HomeFragment.java
  22. 2
      app/src/main/java/cc/niushuai/didicheck/ui/main/home/HomeRecycleViewAdapter.java
  23. 114
      app/src/main/java/cc/niushuai/didicheck/ui/main/records/DataListFragment.java
  24. 216
      app/src/main/java/cc/niushuai/didicheck/ui/main/settings/SettingsFragment.java
  25. 9
      app/src/main/res/drawable-v21/bg_material.xml
  26. 3
      app/src/main/res/drawable-v21/bg_ripple.xml
  27. 13
      app/src/main/res/drawable/bg_material.xml
  28. 3
      app/src/main/res/drawable/bg_ripple.xml
  29. 19
      app/src/main/res/layout/fragment_data_list.xml
  30. 162
      app/src/main/res/layout/fragment_home.xml
  31. 2
      app/src/main/res/layout/item_list.xml
  32. BIN
      app/src/main/res/mipmap-hdpi/ic_ice_cream.png
  33. BIN
      app/src/main/res/mipmap-mdpi/ic_ice_cream.png
  34. BIN
      app/src/main/res/mipmap-xhdpi/ic_ice_cream.png
  35. BIN
      app/src/main/res/mipmap-xxhdpi/ic_ice_cream.png
  36. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_calendar.png
  37. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_clear.png
  38. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_colorful_logo.png
  39. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_custom.png
  40. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_flyme_logo.png
  41. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_full.png
  42. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_func.png
  43. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_ice_cream.png
  44. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_increase.png
  45. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_index_logo.png
  46. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_more.png
  47. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_multi.png
  48. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_progress.png
  49. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_range.png
  50. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_reduce.png
  51. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_simple_logo.png
  52. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_single.png
  53. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_solar_system.png
  54. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_sun.png
  55. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_tab_logo.png
  56. 14
      app/src/main/res/values/arrays.xml
  57. 15
      app/src/main/res/values/attrs.xml
  58. 8
      app/src/main/res/values/colors.xml
  59. 12
      app/src/main/res/values/strings.xml
  60. 48
      app/src/main/res/xml/root_preferences.xml
  61. BIN
      icon/冰激凌.png
  62. BIN
      keystore/key.jks

1
app/build.gradle

@ -48,6 +48,7 @@ dependencies { @@ -48,6 +48,7 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'
implementation 'androidx.recyclerview:recyclerview:1.3.2'
implementation 'androidx.preference:preference:1.2.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'

114
app/schemas/cc.niushuai.didicheck.biz.room.DiDiCheckDataBase/3.json

@ -0,0 +1,114 @@ @@ -0,0 +1,114 @@
{
"formatVersion": 1,
"database": {
"version": 3,
"identityHash": "8a123aa9c9eab77aec672727765b01ce",
"entities": [
{
"tableName": "t_check_record",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `check_type` TEXT, `name` TEXT, `check_date` INTEGER, `description` TEXT, `create_date` INTEGER, `deleted` INTEGER, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "checkType",
"columnName": "check_type",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "checkDate",
"columnName": "check_date",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "description",
"columnName": "description",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "createDate",
"columnName": "create_date",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "t_check_project",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `name` TEXT, `icon` INTEGER, `create_date` INTEGER, `deleted` INTEGER, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "icon",
"columnName": "icon",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "createDate",
"columnName": "create_date",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '8a123aa9c9eab77aec672727765b01ce')"
]
}
}

114
app/schemas/cc.niushuai.didicheck.biz.room.DiDiCheckDataBase/4.json

@ -0,0 +1,114 @@ @@ -0,0 +1,114 @@
{
"formatVersion": 1,
"database": {
"version": 4,
"identityHash": "8a123aa9c9eab77aec672727765b01ce",
"entities": [
{
"tableName": "t_check_record",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `check_type` TEXT, `name` TEXT, `check_date` INTEGER, `description` TEXT, `create_date` INTEGER, `deleted` INTEGER, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "checkType",
"columnName": "check_type",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "checkDate",
"columnName": "check_date",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "description",
"columnName": "description",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "createDate",
"columnName": "create_date",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "t_check_project",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `name` TEXT, `icon` INTEGER, `create_date` INTEGER, `deleted` INTEGER, PRIMARY KEY(`id`))",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "icon",
"columnName": "icon",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "createDate",
"columnName": "create_date",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "deleted",
"columnName": "deleted",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '8a123aa9c9eab77aec672727765b01ce')"
]
}
}

78
app/src/main/java/cc/niushuai/didicheck/MainActivity.java

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
package cc.niushuai.didicheck;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
@ -9,14 +10,23 @@ import androidx.viewpager.widget.ViewPager; @@ -9,14 +10,23 @@ import androidx.viewpager.widget.ViewPager;
import com.github.clans.fab.FloatingActionButton;
import com.github.clans.fab.FloatingActionMenu;
import java.util.ArrayList;
import java.util.List;
import cc.niushuai.didicheck.biz.entity.CheckProject;
import cc.niushuai.didicheck.biz.enums.CheckTypeEnum;
import cc.niushuai.didicheck.biz.room.DBManager;
import cc.niushuai.didicheck.databinding.ActivityMainBinding;
import cc.niushuai.didicheck.ui.main.TabsPagerAdapter;
import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;
private List<CheckProject> checkProjectList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -32,28 +42,68 @@ public class MainActivity extends AppCompatActivity { @@ -32,28 +42,68 @@ public class MainActivity extends AppCompatActivity {
ViewPager viewPager = binding.viewPager;
viewPager.setAdapter(tabsPagerAdapter);
initFloatingActionButtons(tabsPagerAdapter);
binding.didiCheckMenu.setOnMenuToggleListener(new FloatingActionMenu.OnMenuToggleListener() {
@Override
public void onMenuToggle(boolean opened) {
if (opened) {
buildFloatActionButtons(checkProjectList, getApplicationContext(), binding.didiCheckMenu, tabsPagerAdapter);
} else {
// 关闭时清除所有button
binding.didiCheckMenu.removeAllMenuButtons();
}
}
});
}
private void fetchNewestActionButtonData() {
Flowable<List<CheckProject>> listFlowable = DBManager.INSTANCE.checkProjectDao().listAll();
listFlowable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<CheckProject>>() {
@Override
public void accept(List<CheckProject> checkProjects) throws Exception {
checkProjectList = checkProjects;
}
});
}
private void initFloatingActionButtons(TabsPagerAdapter tabsPagerAdapter) {
FloatingActionMenu didiCheckMenu = binding.didiCheckMenu;
FloatingActionButton swimActionButton = new FloatingActionButton(this);
swimActionButton.showButtonInMenu(true);
swimActionButton.show(true);
swimActionButton.setLabelText("游泳");
swimActionButton.setImageDrawable(this.getResources().getDrawable(R.mipmap.fab_icon_swimming, getTheme()));
swimActionButton.setButtonSize(FloatingActionButton.SIZE_NORMAL);
swimActionButton.setColorNormal(this.getResources().getColor(R.color.white));
swimActionButton.setColorPressed(this.getResources().getColor(R.color.white));
swimActionButton.setTag("SWIM_TAG");
swimActionButton.setOnClickListener(new View.OnClickListener() {
// 移除所有
Context context = this;
// 拉取最新
fetchNewestActionButtonData();
// 构建视图
// buildFloatActionButtons(checkProjectList, this, binding.didiCheckMenu, tabsPagerAdapter);
}
private void buildFloatActionButtons(List<CheckProject> checkProjects, Context context, FloatingActionMenu didiCheckMenu, TabsPagerAdapter tabsPagerAdapter) {
for (CheckProject project : checkProjects) {
FloatingActionButton actionButton = new FloatingActionButton(context);
actionButton.showButtonInMenu(true);
actionButton.show(true);
actionButton.setTag(project.getName() + project.getId());
actionButton.setLabelText(project.getName());
actionButton.setImageDrawable(getResources().getDrawable(R.mipmap.ic_ice_cream, getTheme()));
actionButton.setButtonSize(FloatingActionButton.SIZE_NORMAL);
actionButton.setColorNormal(getResources().getColor(R.color.white));
actionButton.setColorPressed(getResources().getColor(R.color.white));
actionButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
tabsPagerAdapter.getHomeFragment().add2Top(CheckTypeEnum.QUICK_ADD, "游泳");
// 打卡完成 关闭动画
didiCheckMenu.close(true);
// 添加数据
tabsPagerAdapter.getHomeFragment().add2Top(CheckTypeEnum.QUICK_ADD, actionButton.getLabelText());
}
});
didiCheckMenu.addMenuButton(swimActionButton);
didiCheckMenu.addMenuButton(actionButton);
}
}
}

148
app/src/main/java/cc/niushuai/didicheck/base/activity/BaseActivity.java

@ -1,148 +0,0 @@ @@ -1,148 +0,0 @@
package cc.niushuai.didicheck.base.activity;
import android.annotation.SuppressLint;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 基类
* Created by huanghaibin on 2017/11/16.
*/
public abstract class BaseActivity extends AppCompatActivity {
private static boolean isMiUi = false;
protected void initWindow() {
}
protected abstract int getLayoutId();
protected abstract void initView();
protected abstract void initData();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initWindow();
setContentView(getLayoutId());
initView();
initData();
}
/**
* 设置小米黑色状态栏字体
*/
@SuppressLint("PrivateApi")
private void setMIUIStatusBarDarkMode() {
if (isMiUi) {
Class<? extends Window> clazz = getWindow().getClass();
try {
int darkModeFlag;
Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
darkModeFlag = field.getInt(layoutParams);
Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
extraFlagField.invoke(getWindow(), darkModeFlag, darkModeFlag);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/*
* 静态域获取系统版本是否基于MIUI
*/
static {
try {
@SuppressLint("PrivateApi") Class<?> sysClass = Class.forName("android.os.SystemProperties");
Method getStringMethod = sysClass.getDeclaredMethod("get", String.class);
String version = (String) getStringMethod.invoke(sysClass, "ro.miui.ui.version.name");
isMiUi = version.compareTo("V6") >= 0 && Build.VERSION.SDK_INT < 24;
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 设置魅族手机状态栏图标颜色风格
* 可以用来判断是否为Flyme用户
*
* @param window 需要设置的窗口
* @param dark 是否把状态栏字体及图标颜色设置为深色
* @return boolean 成功执行返回true
*/
@SuppressWarnings("JavaReflectionMemberAccess")
public static boolean setMeiZuDarkMode(Window window, boolean dark) {
boolean result = false;
if (Build.VERSION.SDK_INT >= 24) {
return false;
}
if (window != null) {
try {
WindowManager.LayoutParams lp = window.getAttributes();
Field darkFlag = WindowManager.LayoutParams.class
.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
Field meizuFlags = WindowManager.LayoutParams.class
.getDeclaredField("meizuFlags");
darkFlag.setAccessible(true);
meizuFlags.setAccessible(true);
int bit = darkFlag.getInt(null);
int value = meizuFlags.getInt(lp);
if (dark) {
value |= bit;
} else {
value &= ~bit;
}
meizuFlags.setInt(lp, value);
window.setAttributes(lp);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
}
return result;
}
@SuppressLint("InlinedApi")
private int getStatusBarLightMode() {
int result = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (isMiUi) {
result = 1;
} else if (setMeiZuDarkMode(getWindow(), true)) {
result = 2;
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
result = 3;
}
}
return result;
}
@SuppressLint("InlinedApi")
protected void setStatusBarDarkMode() {
int type = getStatusBarLightMode();
if (type == 1) {
setMIUIStatusBarDarkMode();
} else if (type == 2) {
setMeiZuDarkMode(getWindow(), true);
} else if (type == 3) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
}
}

139
app/src/main/java/cc/niushuai/didicheck/base/adapter/BaseRecyclerAdapter.java

@ -1,139 +0,0 @@ @@ -1,139 +0,0 @@
/*
* Copyright (C) 2016 huanghaibin_dev <huanghaibin_dev@163.com>
* WebSite https://github.com/MiracleTimes-Dev
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cc.niushuai.didicheck.base.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
/**
* 基本的适配器
*/
@SuppressWarnings("unused")
public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter {
protected LayoutInflater mInflater;
protected List<T> mItems;
private OnItemClickListener onItemClickListener;
private OnClickListener onClickListener;
public BaseRecyclerAdapter(Context context) {
this.mItems = new ArrayList<>();
mInflater = LayoutInflater.from(context);
onClickListener = new OnClickListener() {
@Override
public void onClick(int position, long itemId) {
if (onItemClickListener != null)
onItemClickListener.onItemClick(position, itemId);
}
};
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
final RecyclerView.ViewHolder holder = onCreateDefaultViewHolder(parent, viewType);
holder.itemView.setTag(holder);
holder.itemView.setOnClickListener(onClickListener);
return holder;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
onBindViewHolder(holder, mItems.get(position), position);
}
protected abstract RecyclerView.ViewHolder onCreateDefaultViewHolder(ViewGroup parent, int type);
protected abstract void onBindViewHolder(RecyclerView.ViewHolder holder, T item, int position);
@Override
public int getItemCount() {
return mItems.size();
}
void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
void addAll(List<T> items) {
if (items != null && items.size() > 0) {
mItems.addAll(items);
notifyItemRangeInserted(mItems.size(), items.size());
}
}
final void addItem(T item) {
if (item != null) {
this.mItems.add(item);
notifyItemChanged(mItems.size());
}
}
final List<T> getItems() {
return mItems;
}
final T getItem(int position) {
if (position < 0 || position >= mItems.size())
return null;
return mItems.get(position);
}
static abstract class OnClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
RecyclerView.ViewHolder holder = (RecyclerView.ViewHolder) v.getTag();
onClick(holder.getAdapterPosition(), holder.getItemId());
}
public abstract void onClick(int position, long itemId);
}
interface OnItemClickListener {
void onItemClick(int position, long itemId);
}
public final void removeItem(T item) {
if (this.mItems.contains(item)) {
int position = mItems.indexOf(item);
this.mItems.remove(item);
notifyItemRemoved(position);
}
}
protected final void removeItem(int position) {
if (this.getItemCount() > position) {
this.mItems.remove(position);
notifyItemRemoved(position);
}
}
protected final void clear(){
mItems.clear();
notifyDataSetChanged();
}
}

52
app/src/main/java/cc/niushuai/didicheck/base/fragment/BaseFragment.java

@ -1,52 +0,0 @@ @@ -1,52 +0,0 @@
package cc.niushuai.didicheck.base.fragment;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public abstract class BaseFragment extends Fragment {
protected View mRootView;
protected LayoutInflater mInflater;
protected Context mContext;
@Override
public void onAttach(Context context) {
mContext = context;
super.onAttach(context);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
if (mRootView != null) {
ViewGroup parent = (ViewGroup) mRootView.getParent();
if (parent != null)
parent.removeView(mRootView);
} else {
mRootView = inflater.inflate(getLayoutId(), container, false);
mInflater = inflater;
initView();
initData();
}
return mRootView;
}
@Override
public void onDetach() {
mContext = null;
super.onDetach();
}
protected abstract int getLayoutId();
protected abstract void initView();
protected abstract void initData();
}

95
app/src/main/java/cc/niushuai/didicheck/base/fragment/FragmentAdapter.java

@ -1,95 +0,0 @@ @@ -1,95 +0,0 @@
package cc.niushuai.didicheck.base.fragment;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.fragment.app.FragmentTransaction;
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings("unused")
public class FragmentAdapter extends FragmentPagerAdapter {
private List<Fragment> mFragment = new ArrayList<>();
private final FragmentManager mFragmentManager;
private boolean mUpdateFlag;
private Fragment mCurFragment;
private String[] mTitles;
public FragmentAdapter(FragmentManager fm) {
super(fm);
this.mFragmentManager = fm;
}
public boolean isUpdateFlag() {
return mUpdateFlag;
}
public void setUpdateFlag(boolean mUpdateFlag) {
this.mUpdateFlag = mUpdateFlag;
}
@Override
public int getItemPosition(@NonNull Object object) {
return POSITION_NONE;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
if (mUpdateFlag) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
String tag = fragment.getTag();
FragmentTransaction transaction = mFragmentManager.beginTransaction();
transaction.remove(fragment);
fragment = getItem(position);
if (!fragment.isAdded()) {
transaction.add(container.getId(), fragment, tag)
.attach(fragment)
.commitAllowingStateLoss();
}
return fragment;
}
return super.instantiateItem(container, position);
}
public void reset(List<Fragment> fragments) {
mFragment.clear();
mFragment.addAll(fragments);
}
@Override
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
super.setPrimaryItem(container, position, object);
if (object instanceof Fragment) {
mCurFragment = (Fragment) object;
}
}
public Fragment getCurFragment() {
return mCurFragment;
}
public void reset(String[] titles) {
this.mTitles = titles;
}
@Override
public Fragment getItem(int position) {
return mFragment.get(position);
}
@Override
public int getCount() {
return mFragment.size();
}
@Override
public CharSequence getPageTitle(int position) {
return mTitles[position];
}
}

34
app/src/main/java/cc/niushuai/didicheck/biz/dao/CheckProjectDao.java

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
package cc.niushuai.didicheck.biz.dao;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import java.util.List;
import cc.niushuai.didicheck.biz.entity.CheckProject;
import io.reactivex.Completable;
import io.reactivex.Flowable;
@Dao
public interface CheckProjectDao {
@Query("SELECT * FROM t_check_project")
Flowable<List<CheckProject>> testListAll();
@Query("SELECT * FROM t_check_project where deleted = 0 order by create_date desc")
Flowable<List<CheckProject>> listAll();
@Query("SELECT count(*) FROM t_check_project where deleted = 0 and name = :name")
Flowable<Integer> countByName(String name);
@Insert
Completable insertAll(CheckProject... projects);
@Delete
void delete(CheckProject project);
@Query("delete from t_check_project where id = :id")
void deleteById(Long id);
}

6
app/src/main/java/cc/niushuai/didicheck/biz/dao/CheckRecordDao.java

@ -14,14 +14,14 @@ import io.reactivex.Flowable; @@ -14,14 +14,14 @@ import io.reactivex.Flowable;
@Dao
public interface CheckRecordDao {
@Query("SELECT * FROM t_check_record")
@Query("SELECT * FROM t_check_record order by check_date desc, create_date desc")
Flowable<List<CheckRecord>> listAll();
@Query("select * from t_check_record where deleted = 0 and check_date = :date")
@Query("select * from t_check_record where deleted = 0 and check_date = :date order by check_date desc, create_date desc")
Flowable<List<CheckRecord>> queryByDate(long date);
@Query("select * from t_check_record where deleted = 0 and create_date >= :startDate and create_date <= :endDate ")
@Query("select * from t_check_record where deleted = 0 and create_date >= :startDate and create_date <= :endDate order by check_date desc, create_date desc")
Flowable<List<CheckRecord>> queryByDate(long startDate, long endDate);

65
app/src/main/java/cc/niushuai/didicheck/biz/entity/CheckProject.java

@ -0,0 +1,65 @@ @@ -0,0 +1,65 @@
package cc.niushuai.didicheck.biz.entity;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
@Entity(tableName = "t_check_project")
public class CheckProject {
@PrimaryKey
private Long id;
@ColumnInfo(name = "name")
private String name;
@ColumnInfo(name = "icon")
private Integer icon;
@ColumnInfo(name = "create_date")
private Long createDate;
@ColumnInfo(name = "deleted")
private Integer deleted;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getIcon() {
return icon;
}
public void setIcon(Integer icon) {
this.icon = icon;
}
public Long getCreateDate() {
return createDate;
}
public void setCreateDate(Long createDate) {
this.createDate = createDate;
}
public Integer getDeleted() {
return deleted;
}
public void setDeleted(Integer deleted) {
this.deleted = deleted;
}
}

6
app/src/main/java/cc/niushuai/didicheck/biz/room/DBManager.java

@ -5,6 +5,7 @@ import android.content.Context; @@ -5,6 +5,7 @@ import android.content.Context;
import androidx.room.Room;
import androidx.room.RoomDatabase;
import cc.niushuai.didicheck.biz.dao.CheckProjectDao;
import cc.niushuai.didicheck.biz.dao.CheckRecordDao;
public class DBManager {
@ -25,12 +26,13 @@ public class DBManager { @@ -25,12 +26,13 @@ public class DBManager {
public static RoomDatabase buildDatabase(Context context, Class<? extends RoomDatabase> clazz, String dbName) {
RoomDatabase.Builder<? extends RoomDatabase> databaseBuilder = Room.databaseBuilder(context, clazz, dbName);
databaseBuilder.setJournalMode(RoomDatabase.JournalMode.AUTOMATIC);
databaseBuilder.allowMainThreadQueries();
return databaseBuilder.build();
}
public DiDiCheckDataBase getDiDiCheckDataBase() {
if (null == diDiCheckDataBase) {
diDiCheckDataBase = (DiDiCheckDataBase) buildDatabase(context, DiDiCheckDataBase.class, "didi_check");
diDiCheckDataBase = (DiDiCheckDataBase) buildDatabase(context, DiDiCheckDataBase.class, "didi_check.db");
}
return diDiCheckDataBase;
}
@ -38,4 +40,6 @@ public class DBManager { @@ -38,4 +40,6 @@ public class DBManager {
public CheckRecordDao checkRecordDao() {
return getDiDiCheckDataBase().checkRecordDao();
}
public CheckProjectDao checkProjectDao() {return getDiDiCheckDataBase().checkProjectDao();}
}

6
app/src/main/java/cc/niushuai/didicheck/biz/room/DiDiCheckDataBase.java

@ -3,11 +3,15 @@ package cc.niushuai.didicheck.biz.room; @@ -3,11 +3,15 @@ package cc.niushuai.didicheck.biz.room;
import androidx.room.Database;
import androidx.room.RoomDatabase;
import cc.niushuai.didicheck.biz.dao.CheckProjectDao;
import cc.niushuai.didicheck.biz.dao.CheckRecordDao;
import cc.niushuai.didicheck.biz.entity.CheckProject;
import cc.niushuai.didicheck.biz.entity.CheckRecord;
@Database(entities = {CheckRecord.class}, version = 2)
@Database(entities = {CheckRecord.class, CheckProject.class}, version = 4)
public abstract class DiDiCheckDataBase extends RoomDatabase {
public abstract CheckRecordDao checkRecordDao();
public abstract CheckProjectDao checkProjectDao();
}

283
app/src/main/java/cc/niushuai/didicheck/ui/group/GroupItemDecoration.java

@ -1,283 +0,0 @@ @@ -1,283 +0,0 @@
package cc.niushuai.didicheck.ui.group;
import android.annotation.SuppressLint;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextUtils;
import android.view.View;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.HashMap;
import java.util.Map;
/**
* 分组浮动的ItemDecoration
* Created by haibin on 2017/5/15.
*/
@SuppressWarnings("all")
public class GroupItemDecoration<Group, Child> extends RecyclerView.ItemDecoration {
protected int mGroupHeight;
protected int mGroutBackground;
protected Paint mBackgroundPaint;
protected Paint mTextPaint;
protected float mTextBaseLine;
protected int mPaddingLeft, mPaddingRight;
protected boolean isCenter;
protected boolean isHasHeader;
protected int mChildItemOffset;
@SuppressLint("UseSparseArrays")
protected Map<Integer, Group> mGroup = new HashMap<>();
public GroupItemDecoration() {
super();
init();
}
private void init() {
mBackgroundPaint = new Paint();
mBackgroundPaint.setColor(0xFFf5f7f8);
mBackgroundPaint.setStyle(Paint.Style.FILL);
mBackgroundPaint.setAntiAlias(true);
mTextPaint = new Paint();
mTextPaint.setColor(0xFF353535);
mTextPaint.setAntiAlias(true);
}
/**
* 先于RecyclerView的Item onDraw调用
*
* @param c RecyclerView canvas
* @param parent RecyclerView
* @param state stare
*/
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
onDrawGroup(c, parent);
}
/**
* 绘制分组Group
*
* @param c Canvas
* @param parent RecyclerView
*/
protected void onDrawGroup(Canvas c, RecyclerView parent) {
int paddingLeft = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
int top, bottom;
int count = parent.getChildCount();
for (int i = 0; i < parent.getChildCount(); i++) {
View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int key = params.getViewLayoutPosition();
if (mGroup.containsKey(key)) {
top = child.getTop() - params.topMargin - mGroupHeight;
bottom = top + mGroupHeight;
c.drawRect(paddingLeft, top, right, bottom, mBackgroundPaint);
String group = mGroup.get(params.getViewLayoutPosition()).toString();
float x;
float y = top + mTextBaseLine;
if (isCenter) {
x = parent.getMeasuredWidth() / 2 - getTextX(group);
} else {
x = mPaddingLeft;
}
c.drawText(group, x, y, mTextPaint);
}
}
}
/**
* 后于RecyclerView的Item onDraw调用
*
* @param c RecyclerView canvas
* @param parent RecyclerView
* @param state stare
*/
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
onDrawOverGroup(c, parent);
}
/**
* 绘制悬浮组
*
* @param c Canvas
* @param parent RecyclerView
*/
protected void onDrawOverGroup(Canvas c, RecyclerView parent) {
int firstVisiblePosition = ((LinearLayoutManager) parent.getLayoutManager()).findFirstVisibleItemPosition();
if (firstVisiblePosition == RecyclerView.NO_POSITION) {
return;
}
Group group = getCroup(firstVisiblePosition);
if (group == null)
return;
String groupTitle = group.toString();
if (TextUtils.isEmpty(groupTitle)) {
return;
}
boolean isRestore = false;
Group nextGroup = getCroup(firstVisiblePosition + 1);
if (nextGroup != null && !group.equals(nextGroup)) {
//说明是当前组最后一个元素,但不一定碰撞了
View child = parent.findViewHolderForAdapterPosition(firstVisiblePosition).itemView;
if (child.getTop() + child.getMeasuredHeight() < mGroupHeight) {
//进一步检测碰撞
c.save();//保存画布当前的状态
isRestore = true;
c.translate(0, child.getTop() + child.getMeasuredHeight() - mGroupHeight);
}
}
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
int top = parent.getPaddingTop();
int bottom = top + mGroupHeight;
c.drawRect(left, top, right, bottom, mBackgroundPaint);
float x;
float y = top + mTextBaseLine;
if (isCenter) {
x = parent.getMeasuredWidth() / 2 - getTextX(groupTitle);
} else {
x = mPaddingLeft;
}
c.drawText(groupTitle, x, y, mTextPaint);
if (isRestore) {
//还原画布为初始状态
c.restore();
}
}
/**
* 设置item的上下左右偏移量
*
* @param outRect rect
* @param view item
* @param parent RecyclerView
* @param state stare
*/
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
getItemOffsets(outRect, view, parent, parent.getChildViewHolder(view).getAdapterPosition());
}
/**
* 设置item的上下左右偏移量不做任何处理就是默认状态
*
* @param outRect outRect
* @param view view
* @param parent RecyclerView
* @param adapterPosition position
*/
protected void getItemOffsets(Rect outRect, View view, RecyclerView parent, int adapterPosition) {
if (mGroup.containsKey(adapterPosition)) {
outRect.set(0, mGroupHeight, 0, mGroup.containsKey(adapterPosition + 1) ? 0 : mChildItemOffset);
} else {
outRect.set(0, 0, 0, mGroup.containsKey(adapterPosition + 1) ? 0 : mChildItemOffset);
}
}
/**
* 获得当前ViewPosition所在的组
*
* @param position 当前View的position
* @return 当前ViewPosition所在的组
*/
protected Group getCroup(int position) {
while (position >= 0) {
if (mGroup.containsKey(position)) {
return mGroup.get(position);
}
position--;
}
return null;
}
/**
* 通知更新分组信息
*
* @param adapter GroupRecyclerAdapter
*/
public void notifyDataSetChanged(GroupRecyclerAdapter<Group, Child> adapter) {
mGroup.clear();
if (adapter == null) return;
int key = 0;
for (int i = 0; i < adapter.getGroupCount(); i++) {
if (i == 0) {
mGroup.put(isHasHeader ? 1 : 0, adapter.getGroup(i));
key += adapter.getChildCount(i) + (isHasHeader ? 1 : 0);
;
} else {
mGroup.put(key, adapter.getGroup(i));
key += adapter.getChildCount(i);
}
}
}
public void setChildItemOffset(int childItemOffset){
this.mChildItemOffset = childItemOffset;
}
public void setBackground(int groupBackground) {
mBackgroundPaint.setColor(groupBackground);
}
public void setTextColor(int textColor) {
mTextPaint.setColor(textColor);
}
public void setTextSize(float textSize) {
mTextPaint.setTextSize(textSize);
Paint.FontMetrics metrics = mTextPaint.getFontMetrics();
mTextBaseLine = mGroupHeight / 2 - metrics.descent + (metrics.bottom - metrics.top) / 2;
}
public void setGroupHeight(int groupHeight) {
mGroupHeight = groupHeight;
Paint.FontMetrics metrics = mTextPaint.getFontMetrics();
mTextBaseLine = mGroupHeight / 2 - metrics.descent + (metrics.bottom - metrics.top) / 2;
}
public void setPadding(int mPaddingLeft, int mPaddingRight) {
this.mPaddingLeft = mPaddingLeft;
this.mPaddingRight = mPaddingRight;
}
public void setCenter(boolean isCenter) {
this.isCenter = isCenter;
}
public void setHasHeader(boolean hasHeader) {
isHasHeader = hasHeader;
}
/**
* 获取文本的x坐标起点
*
* @param str 文本
* @return x
*/
protected float getTextX(String str) {
Rect bounds = new Rect();
mTextPaint.getTextBounds(str, 0, str.length(), bounds);
return bounds.width() / 2;
}
/**
* 获取文本的长度像素
* @param str 文本
* @return px
*/
protected float getTextLenghtPx(String str) {
Rect bounds = new Rect();
mTextPaint.getTextBounds(str, 0, str.length(), bounds);
return bounds.width();
}
}

135
app/src/main/java/cc/niushuai/didicheck/ui/group/GroupRecyclerAdapter.java

@ -1,135 +0,0 @@ @@ -1,135 +0,0 @@
package cc.niushuai.didicheck.ui.group;
import android.content.Context;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import cc.niushuai.didicheck.base.adapter.BaseRecyclerAdapter;
/**
* 分组的RecyclerAdapter
* Created by haibin on 2017/5/15.
*/
@SuppressWarnings("unused")
public abstract class GroupRecyclerAdapter<Parent, Child> extends BaseRecyclerAdapter<Child> {
private LinkedHashMap<Parent, List<Child>> mGroups;
private List<Parent> mGroupTitles;
public GroupRecyclerAdapter(Context context) {
super(context);
mGroups = new LinkedHashMap<>();
mGroupTitles = new ArrayList<>();
}
/**
* 返回特定的标题
*/
Parent getGroup(int groupPosition) {
return mGroupTitles.get(groupPosition);
}
/**
* 获得分组的数量
*
* @return 组的数量
*/
int getGroupCount() {
return mGroupTitles.size();
}
/**
* 获取某一组的数量
*
* @param groupPosition groupPosition
* @return 某一组的数量
*/
int getChildCount(int groupPosition) {
if (mGroupTitles == null || mGroups.size() == 0)
return 0;
if (mGroups.get(mGroupTitles.get(groupPosition)) == null)
return 0;
return mGroups.get(mGroupTitles.get(groupPosition)).size();
}
/**
* 重置分组数据
*
* @param groups groups
* @param titles titles
*/
protected void resetGroups(LinkedHashMap<Parent, List<Child>> groups, List<Parent> titles) {
if (groups == null || titles == null) {
return;
}
mGroups.clear();
mGroupTitles.clear();
mGroups.putAll(groups);
mGroupTitles.addAll(titles);
mItems.clear();
for (Parent key : mGroups.keySet()) {
mItems.addAll(mGroups.get(key));
}
notifyDataSetChanged();
}
/**
* 清除分组数据
*/
public final void clearGroup() {
mGroupTitles.clear();
mGroups.clear();
clear();
}
/**
* 从分组移除数据
*
* @param position 下标
* @return 分组是否为空要移除分组
*/
public boolean removeGroupItem(int position) {
int group = getGroupIndex(position);
removeGroupChildren(group);
int count = getChildCount(group);
removeItem(position);
if (count <= 0) {
mGroupTitles.remove(group);
return true;
}
return false;
}
/**
* 获取所在分组
*
* @param position 下标
* @return 获取所在分组
*/
private int getGroupIndex(int position) {
int count = 0;
if (position <= count)
return 0;
int i = 0;
for (Parent parent : mGroups.keySet()) {
count += mGroups.get(parent).size();
if (position < count) {
return i;
}
i++;
}
return 0;
}
private void removeGroupChildren(int groupPosition) {
if (groupPosition >= mGroupTitles.size())
return;
List<Child> childList = mGroups.get(mGroupTitles.get(groupPosition));
if (childList != null && childList.size() != 0) {
childList.remove(childList.size() - 1);
}
}
}

92
app/src/main/java/cc/niushuai/didicheck/ui/group/GroupRecyclerView.java

@ -1,92 +0,0 @@ @@ -1,92 +0,0 @@
package cc.niushuai.didicheck.ui.group;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import cc.niushuai.didicheck.R;
/**
* 带分组浮动的RecyclerView
* Created by haibin on 2017/5/15.
*/
@SuppressWarnings("all")
public class GroupRecyclerView extends RecyclerView {
private GroupItemDecoration mItemDecoration;
private int mGroupHeight;
private int mGroutBackground, mTextColor;
private int mTextSize;
private int mPaddingLeft, mPaddingRight;
private boolean isCenter;
protected int mChildItemOffset;
private boolean isHasHeader;
private OnGroupChangeListener mListener;
public GroupRecyclerView(Context context) {
super(context);
}
public GroupRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.GroupRecyclerView);
mTextSize = array.getDimensionPixelSize(R.styleable.GroupRecyclerView_group_text_size, 16);
mGroupHeight = (int) array.getDimension(R.styleable.GroupRecyclerView_group_height, 52);
mChildItemOffset = (int) array.getDimension(R.styleable.GroupRecyclerView_group_child_offset, 20);
mTextColor = array.getColor(R.styleable.GroupRecyclerView_group_text_color, 0xFFFFFFFF);
mGroutBackground = array.getColor(R.styleable.GroupRecyclerView_group_background, 0x80000000);
isCenter = array.getBoolean(R.styleable.GroupRecyclerView_group_center, false);
isHasHeader = array.getBoolean(R.styleable.GroupRecyclerView_group_has_header, true);
mPaddingLeft = (int) array.getDimension(R.styleable.GroupRecyclerView_group_padding_left, 16);
mPaddingRight = (int) array.getDimension(R.styleable.GroupRecyclerView_group_padding_right, 16);
array.recycle();
}
@Override
public void setAdapter(Adapter adapter) {
if (adapter instanceof GroupRecyclerAdapter) {
super.setAdapter(adapter);
} else {
throw new IllegalStateException("Adapter must instanceof " +
"GroupRecyclerAdapter or extends GroupRecyclerAdapter");
}
}
@Override
public void addItemDecoration(ItemDecoration decor) {
if (decor instanceof GroupItemDecoration)
super.addItemDecoration(decor);
else
throw new IllegalStateException("ItemDecoration must instanceof " +
"GroupItemDecoration or extends GroupItemDecoration");
mItemDecoration = (GroupItemDecoration) decor;
mItemDecoration.setTextSize(mTextSize);
mItemDecoration.setBackground(mGroutBackground);
mItemDecoration.setTextColor(mTextColor);
mItemDecoration.setGroupHeight(mGroupHeight);
mItemDecoration.setPadding(mPaddingLeft, mPaddingRight);
mItemDecoration.setCenter(isCenter);
mItemDecoration.setHasHeader(isHasHeader);
mItemDecoration.setChildItemOffset(mChildItemOffset);
//mItemDecoration.notifyDataSetChanged((GroupRecyclerAdapter) getAdapter());
}
public void notifyDataSetChanged() {
mItemDecoration.notifyDataSetChanged((GroupRecyclerAdapter) getAdapter());
}
public void setOnGroupChangeListener(OnGroupChangeListener listener) {
this.mListener = listener;
}
/**
* 分组最上面改变通知
*/
public interface OnGroupChangeListener {
void onGroupChange(int groupPosition, String group);
}
}

91
app/src/main/java/cc/niushuai/didicheck/ui/index/IndexMonthView.java

@ -1,91 +0,0 @@ @@ -1,91 +0,0 @@
package cc.niushuai.didicheck.ui.index;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.MonthView;
/**
* 下标标记的日历控件
* Created by huanghaibin on 2017/11/15.
*/
public class IndexMonthView extends MonthView {
private Paint mSchemeBasicPaint = new Paint();
private int mPadding;
private int mH, mW;
public IndexMonthView(Context context) {
super(context);
mSchemeBasicPaint.setAntiAlias(true);
mSchemeBasicPaint.setStyle(Paint.Style.FILL);
mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);
mSchemeBasicPaint.setColor(0xff333333);
mSchemeBasicPaint.setFakeBoldText(true);
mPadding = dipToPx(getContext(), 4);
mH = dipToPx(getContext(), 2);
mW = dipToPx(getContext(), 8);
}
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {
mSelectedPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(x + mPadding, y + mPadding, x + mItemWidth - mPadding, y + mItemHeight - mPadding, mSelectedPaint);
return true;
}
/**
* onDrawSelected
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
* @param y 日历Card y起点坐标
*/
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {
mSchemeBasicPaint.setColor(calendar.getSchemeColor());
canvas.drawRect(x + mItemWidth / 2 - mW / 2,
y + mItemHeight - mH * 2 - mPadding,
x + mItemWidth / 2 + mW / 2,
y + mItemHeight - mH - mPadding, mSchemeBasicPaint);
}
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
int cx = x + mItemWidth / 2;
int top = y - mItemHeight / 6;
if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10,
calendar.isCurrentDay() ? mCurDayLunarTextPaint :
mCurMonthLunarTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mCurMonthLunarTextPaint);
}
}
/**
* dp转px
*
* @param context context
* @param dpValue dp
* @return px
*/
private static int dipToPx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}

103
app/src/main/java/cc/niushuai/didicheck/ui/index/IndexWeekView.java

@ -1,103 +0,0 @@ @@ -1,103 +0,0 @@
package cc.niushuai.didicheck.ui.index;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import com.haibin.calendarview.Calendar;
import com.haibin.calendarview.WeekView;
/**
* 下标周视图
* Created by huanghaibin on 2017/11/29.
*/
public class IndexWeekView extends WeekView {
private Paint mSchemeBasicPaint = new Paint();
private int mPadding;
private int mH, mW;
public IndexWeekView(Context context) {
super(context);
mSchemeBasicPaint.setAntiAlias(true);
mSchemeBasicPaint.setStyle(Paint.Style.FILL);
mSchemeBasicPaint.setTextAlign(Paint.Align.CENTER);
mSchemeBasicPaint.setColor(0xff333333);
mSchemeBasicPaint.setFakeBoldText(true);
mPadding = dipToPx(getContext(), 4);
mH = dipToPx(getContext(), 2);
mW = dipToPx(getContext(), 8);
}
@Override
protected void onPreviewHook() {
}
/**
* 如果这里和 onDrawScheme 是互斥的 return false
* return true 会先绘制 onDrawSelected再绘制onDrawSelected
*
* @param canvas canvas
* @param calendar 日历日历calendar
* @param x 日历Card x起点坐标
* @param hasScheme hasScheme 非标记的日期
*/
@Override
protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, boolean hasScheme) {
mSelectedPaint.setStyle(Paint.Style.FILL);
canvas.drawRect(x + mPadding, mPadding, x + mItemWidth - mPadding, mItemHeight - mPadding, mSelectedPaint);
return true;
}
/**
* 绘制下标标记
*
* @param canvas canvas
* @param calendar 日历calendar
* @param x 日历Card x起点坐标
*/
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawScheme(Canvas canvas, Calendar calendar, int x) {
mSchemeBasicPaint.setColor(calendar.getSchemeColor());
canvas.drawRect(x + mItemWidth / 2 - mW / 2,
mItemHeight - mH * 2 - mPadding,
x + mItemWidth / 2 + mW / 2,
mItemHeight - mH - mPadding, mSchemeBasicPaint);
}
@SuppressWarnings("IntegerDivisionInFloatingPointContext")
@Override
protected void onDrawText(Canvas canvas, Calendar calendar, int x, boolean hasScheme, boolean isSelected) {
int cx = x + mItemWidth / 2;
int top = -mItemHeight / 6;
if (hasScheme) {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mSchemeTextPaint : mCurMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10,
calendar.isCurrentDay() ? mCurDayLunarTextPaint :
mCurMonthLunarTextPaint);
} else {
canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
calendar.isCurrentDay() ? mCurDayTextPaint :
calendar.isCurrentMonth() ? mCurMonthTextPaint : mCurMonthTextPaint);
canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10,
calendar.isCurrentDay() ? mCurDayLunarTextPaint :
mCurMonthLunarTextPaint);
}
}
/**
* dp转px
*
* @param context context
* @param dpValue dp
* @return px
*/
private static int dipToPx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}

4
app/src/main/java/cc/niushuai/didicheck/ui/index/x.java

@ -1,4 +0,0 @@ @@ -1,4 +0,0 @@
package cc.niushuai.didicheck.ui.index;
public class x {
}

3
app/src/main/java/cc/niushuai/didicheck/ui/main/TabsPagerAdapter.java

@ -11,6 +11,7 @@ import androidx.fragment.app.FragmentPagerAdapter; @@ -11,6 +11,7 @@ import androidx.fragment.app.FragmentPagerAdapter;
import cc.niushuai.didicheck.R;
import cc.niushuai.didicheck.ui.main.home.HomeFragment;
import cc.niushuai.didicheck.ui.main.records.DataListFragment;
import cc.niushuai.didicheck.ui.main.settings.SettingsFragment;
/**
* A [FragmentPagerAdapter] that returns a fragment corresponding to
@ -39,7 +40,7 @@ public class TabsPagerAdapter extends FragmentPagerAdapter { @@ -39,7 +40,7 @@ public class TabsPagerAdapter extends FragmentPagerAdapter {
dataListFragment = new DataListFragment();
return dataListFragment;
} else if (position == 2) {
return new DataListFragment();
return new SettingsFragment();
}
return new HomeFragment();
}

86
app/src/main/java/cc/niushuai/didicheck/ui/main/home/HomeFragment.java

@ -6,7 +6,6 @@ import android.view.Gravity; @@ -6,7 +6,6 @@ import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
@ -63,7 +62,7 @@ public class HomeFragment extends Fragment { @@ -63,7 +62,7 @@ public class HomeFragment extends Fragment {
Log.d("Home", "onCreateView");
fragmentHomeBinding = FragmentHomeBinding.inflate(inflater, container, false);
LinearLayout rootLayout = fragmentHomeBinding.getRoot();
ConstraintLayout rootLayout = fragmentHomeBinding.getRoot();
initTextView();
@ -80,37 +79,38 @@ public class HomeFragment extends Fragment { @@ -80,37 +79,38 @@ public class HomeFragment extends Fragment {
}
private void initVerticalCalendarView() {
// CalendarView homeMainCalendar = fragmentHomeBinding.homeMainCalendar;
// homeMainCalendar.setOnCalendarSelectListener(new CalendarView.OnCalendarSelectListener() {
// @Override
// public void onCalendarOutOfRange(Calendar calendar) {
// Log.d("onCalendarOutOfRange", "" + calendar.getTimeInMillis());
// }
//
// @Override
// public void onCalendarSelect(Calendar calendar, boolean isClick) {
// Log.d("onCalendarSelect", isClick + "---" + calendar.getTimeInMillis());
// String dateStr = StrUtil.format("{}-{}-{}", calendar.getYear(), calendar.getMonth(), calendar.getDay());
// homeViewModel.setSelectDate(DateUtil.parseDate(dateStr));
//
// // 刷新数据
// refreshDataListByDate(dateStr);
// }
// });
CalendarView homeMainCalendar = fragmentHomeBinding.homeMainCalendar;
// homeMainCalendar.setSchemeDate();
homeMainCalendar.setOnCalendarSelectListener(new CalendarView.OnCalendarSelectListener() {
@Override
public void onCalendarOutOfRange(Calendar calendar) {
Log.d("onCalendarOutOfRange", "" + calendar.getTimeInMillis());
}
@Override
public void onCalendarSelect(Calendar calendar, boolean isClick) {
Log.d("onCalendarSelect", isClick + "---" + calendar.getTimeInMillis());
String dateStr = StrUtil.format("{}-{}-{}", calendar.getYear(), calendar.getMonth(), calendar.getDay());
homeViewModel.setSelectDate(DateUtil.parseDate(dateStr));
// 刷新数据
refreshDataListByDate(dateStr);
}
});
}
private void initRecyleView() {
// RecyclerView homeDataZoneRecyclerView = fragmentHomeBinding.homeDataZoneRecyclerView;
// homeDataZoneRecyclerView.addItemDecoration(new DividerItemDecoration(this.getActivity(), DividerItemDecoration.VERTICAL));
// DefaultItemAnimator itemAnimator = new DefaultItemAnimator();
// itemAnimator.setAddDuration(1000);
// itemAnimator.setRemoveDuration(1000);
// homeDataZoneRecyclerView.setItemAnimator(itemAnimator);
//
// homeRecycleViewAdapter = new HomeRecycleViewAdapter(getActivity(), Collections.emptyList());
// fragmentHomeBinding.homeDataZoneRecyclerView.setAdapter(homeRecycleViewAdapter);
// LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
// fragmentHomeBinding.homeDataZoneRecyclerView.setLayoutManager(layoutManager);
RecyclerView homeDataZoneRecyclerView = fragmentHomeBinding.homeDataZoneRecyclerView;
homeDataZoneRecyclerView.addItemDecoration(new DividerItemDecoration(this.getActivity(), DividerItemDecoration.VERTICAL));
DefaultItemAnimator itemAnimator = new DefaultItemAnimator();
itemAnimator.setAddDuration(1000);
itemAnimator.setRemoveDuration(1000);
homeDataZoneRecyclerView.setItemAnimator(itemAnimator);
homeRecycleViewAdapter = new HomeRecycleViewAdapter(getActivity(), Collections.emptyList());
fragmentHomeBinding.homeDataZoneRecyclerView.setAdapter(homeRecycleViewAdapter);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
fragmentHomeBinding.homeDataZoneRecyclerView.setLayoutManager(layoutManager);
}
private void initCalendarView() {
@ -130,13 +130,13 @@ public class HomeFragment extends Fragment { @@ -130,13 +130,13 @@ public class HomeFragment extends Fragment {
}
private void initTextView() {
// TextView homeTitleTextView = fragmentHomeBinding.homeTitleTextView;
// homeTitleTextView.setGravity(Gravity.CENTER);
// homeViewModel.getTitle().observe(getViewLifecycleOwner(), value -> homeTitleTextView.setText(value));
// homeTitleTextView.setText("未完待续...");
//
// homeViewModel.getSelectDate().observe(getViewLifecycleOwner(), value -> homeTitleTextView.setText(DateUtil.formatDate(value)));
// homeViewModel.setSelectDate(new Date());
TextView homeTitleTextView = fragmentHomeBinding.homeTitleTextView;
homeTitleTextView.setGravity(Gravity.CENTER);
homeViewModel.getTitle().observe(getViewLifecycleOwner(), value -> homeTitleTextView.setText(value));
homeTitleTextView.setText("未完待续...");
homeViewModel.getSelectDate().observe(getViewLifecycleOwner(), value -> homeTitleTextView.setText(DateUtil.formatDate(value)));
homeViewModel.setSelectDate(new Date());
}
@Override
@ -166,12 +166,12 @@ public class HomeFragment extends Fragment { @@ -166,12 +166,12 @@ public class HomeFragment extends Fragment {
@Override
public void onNext(List<CheckRecord> checkRecords) {
Log.d("onNext", "查询到 " + date + " 数据 " + checkRecords.size());
// RecyclerView recyclerView = fragmentHomeBinding.homeDataZoneRecyclerView;
// int childCount = recyclerView.getChildCount();
// if (childCount > 0) {
// recyclerView.removeAllViews();
// }
// homeRecycleViewAdapter.resetRecordList(checkRecords);
RecyclerView recyclerView = fragmentHomeBinding.homeDataZoneRecyclerView;
int childCount = recyclerView.getChildCount();
if (childCount > 0) {
recyclerView.removeAllViews();
}
homeRecycleViewAdapter.resetRecordList(checkRecords);
}
@Override

2
app/src/main/java/cc/niushuai/didicheck/ui/main/home/HomeRecycleViewAdapter.java

@ -46,7 +46,7 @@ public class HomeRecycleViewAdapter extends RecyclerView.Adapter<HomeRecycleView @@ -46,7 +46,7 @@ public class HomeRecycleViewAdapter extends RecyclerView.Adapter<HomeRecycleView
public void onBindViewHolder(@NonNull HomeRecycleViewHolder holder, int position) {
CheckRecord checkRecord = checkRecordList.get(position);
holder.titleTextView.setText(checkRecord.getName());
holder.contentTextView.setText(DateUtil.formatDateTime(new Date(checkRecord.getCreateDate())));
holder.contentTextView.setText(DateUtil.formatDate(new Date(checkRecord.getCheckDate())));
}
@Override

114
app/src/main/java/cc/niushuai/didicheck/ui/main/records/DataListFragment.java

@ -1,6 +1,120 @@ @@ -1,6 +1,120 @@
package cc.niushuai.didicheck.ui.main.records;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.reactivestreams.Subscription;
import java.util.Collections;
import java.util.List;
import cc.niushuai.didicheck.biz.entity.CheckRecord;
import cc.niushuai.didicheck.biz.room.DBManager;
import cc.niushuai.didicheck.databinding.FragmentDataListBinding;
import cc.niushuai.didicheck.ui.main.home.HomeRecycleViewAdapter;
import cc.niushuai.didicheck.util.Toasts;
import io.reactivex.Flowable;
import io.reactivex.FlowableSubscriber;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
public class DataListFragment extends Fragment {
private FragmentDataListBinding fragmentDataListBinding;
private HomeRecycleViewAdapter dataListRecycleViewAdapter;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.d("DataList", "onCreateView");
fragmentDataListBinding = FragmentDataListBinding.inflate(inflater, container, false);
ConstraintLayout rootLayout = fragmentDataListBinding.getRoot();
initRecycleView();
// 默认查所有数据
refreshAllDate();
return rootLayout;
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
if (isVisibleToUser)
refreshAllDate();
super.setUserVisibleHint(isVisibleToUser);
}
private void refreshAllDate() {
Flowable<List<CheckRecord>> flowable = DBManager.INSTANCE.checkRecordDao().listAll();
flowable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new FlowableSubscriber<List<CheckRecord>>() {
@Override
public void onSubscribe(Subscription s) {
// 3s超时
s.request(1);
}
@Override
public void onNext(List<CheckRecord> checkRecords) {
Log.d("DataListOnNext", "查询到数据 " + checkRecords.size());
RecyclerView recyclerView = fragmentDataListBinding.dataListRecyclerView;
int childCount = recyclerView.getChildCount();
if (childCount > 0) {
recyclerView.removeAllViews();
}
dataListRecycleViewAdapter.resetRecordList(checkRecords);
}
@Override
public void onError(Throwable t) {
Toasts.shortShow(getActivity(), "DataList根据时间拉取历史数据失败: ", t.getLocalizedMessage());
}
@Override
public void onComplete() {
}
});
}
private void initRecycleView() {
RecyclerView homeDataZoneRecyclerView = fragmentDataListBinding.dataListRecyclerView;
homeDataZoneRecyclerView.addItemDecoration(new DividerItemDecoration(this.getActivity(), DividerItemDecoration.VERTICAL));
DefaultItemAnimator itemAnimator = new DefaultItemAnimator();
itemAnimator.setAddDuration(1000);
itemAnimator.setRemoveDuration(1000);
homeDataZoneRecyclerView.setItemAnimator(itemAnimator);
dataListRecycleViewAdapter = new HomeRecycleViewAdapter(getActivity(), Collections.emptyList());
fragmentDataListBinding.dataListRecyclerView.setAdapter(dataListRecycleViewAdapter);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
fragmentDataListBinding.dataListRecyclerView.setLayoutManager(layoutManager);
}
@Override
public void onDestroy() {
super.onDestroy();
fragmentDataListBinding = null;
}
}

216
app/src/main/java/cc/niushuai/didicheck/ui/main/settings/SettingsFragment.java

@ -0,0 +1,216 @@ @@ -0,0 +1,216 @@
package cc.niushuai.didicheck.ui.main.settings;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.preference.EditTextPreference;
import androidx.preference.MultiSelectListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceFragmentCompat;
import java.util.HashSet;
import java.util.List;
import cc.niushuai.didicheck.R;
import cc.niushuai.didicheck.biz.entity.CheckProject;
import cc.niushuai.didicheck.biz.room.DBManager;
import cc.niushuai.didicheck.util.Toasts;
import cn.hutool.core.collection.CollUtil;
import io.reactivex.Completable;
import io.reactivex.CompletableObserver;
import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
public class SettingsFragment extends PreferenceFragmentCompat {
private static final String TAG = SettingsFragment.class.getSimpleName();
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.root_preferences, rootKey);
addNewProjectListener();
addRemoveProjectListener();
resetRemoveProject();
resetCheckProjectList();
}
private void resetCheckProjectList() {
// 重置选项卡
Flowable<List<CheckProject>> listFlowable = DBManager.INSTANCE.checkProjectDao().listAll();
listFlowable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(checkProjects -> {
Log.d("SettingsFragment", "reset... checkProject查询到" + checkProjects.size());
// 移除所有内容
removeExtraProject();
dynamicAddCheckProjects(checkProjects);
});
}
private void removeExtraProject() {
PreferenceCategory preference = findPreference(getResources().getString(R.string.check_project_category_list));
preference.removeAll();
}
private void addNewProjectListener() {
EditTextPreference addNewCheckProject = findPreference(getResources().getString(R.string.add_new_check_record));
addNewCheckProject.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) {
Log.d("SettingsFragment", newValue.toString());
CheckProject checkProject = new CheckProject();
checkProject.setId(System.currentTimeMillis());
checkProject.setName(newValue.toString());
checkProject.setDeleted(0);
checkProject.setCreateDate(System.currentTimeMillis());
Completable completable = DBManager.INSTANCE.checkProjectDao().insertAll(checkProject);
completable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onComplete() {
Log.i("SettingsFragment", "新增打卡项[" + newValue.toString() + "]成功");
Toasts.shortShow(getActivity(), "新增打卡项[{}]成功", newValue.toString());
}
@Override
public void onError(Throwable e) {
Log.e("SettingsFragment", "新增打卡项[" + newValue.toString() + "]失败", e);
Toasts.shortShow(getActivity(), "新增打卡项[{}]失败, {}", newValue.toString(), e.getMessage());
}
});
// addOneProject(checkProject);
return true;
}
});
}
private void addRemoveProjectListener() {
MultiSelectListPreference preference = findPreference(getString(R.string.remove_old_check_record));
preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(@NonNull Preference preference) {
return true;
}
});
preference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) {
// newValue 选择的数据id 要更新这些数据id的delete 为0
Log.d(TAG, "onPreferenceChange: " + newValue.toString());
HashSet<String> arr = (HashSet) newValue;
for (String id : arr) {
DBManager.INSTANCE.checkProjectDao().deleteById(Long.valueOf(id));
}
// 重置项目列表
resetCheckProjectList();
return false;
}
});
}
private void resetRemoveProject() {
// 使用ListPreference
MultiSelectListPreference preference = findPreference(getString(R.string.remove_old_check_record));
preference.setEntries(new CharSequence[0]);
preference.setEntryValues(new CharSequence[0]);
Flowable<List<CheckProject>> listFlowable = DBManager.INSTANCE.checkProjectDao().listAll();
listFlowable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<CheckProject>>() {
@Override
public void accept(List<CheckProject> checkProjects) throws Exception {
String[] entries = new String[checkProjects.size()];
String[] entryValues = new String[checkProjects.size()];
for (int i = 0; i < checkProjects.size(); i++) {
CheckProject item = checkProjects.get(i);
entries[i] = item.getName();
entryValues[i] = item.getId().toString();
}
preference.setEntries(entries);
preference.setEntryValues(entryValues);
}
});
}
private void dynamicAddCheckProjects(List<CheckProject> checkProjects) {
if (CollUtil.isEmpty(checkProjects)) {
return;
}
for (CheckProject project : checkProjects) {
addOneProject(project);
}
}
private void addOneProject(CheckProject item) {
PreferenceCategory projectCategoryList = findPreference(getResources().getString(R.string.check_project_category_list));
EditTextPreference preference = new EditTextPreference(getActivity());
preference.setKey(item.getId().toString());
preference.setTitle(item.getName());
preference.setSummary(item.getId().toString());
preference.setDefaultValue(item.getName());
preference.setEnabled(false);
preference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(@NonNull Preference preference, Object newValue) {
return false;
}
});
preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(@NonNull Preference preference) {
Log.d("SettingsFragment", "clicked " + preference.getKey());
Flowable<List<CheckProject>> listFlowable = DBManager.INSTANCE.checkProjectDao().testListAll();
listFlowable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<CheckProject>>() {
@Override
public void accept(List<CheckProject> checkProjects) throws Exception {
Log.d("SettingsFragment", "每个item的onPreferenceClick: " + checkProjects.size());
}
});
return true;
}
});
projectCategoryList.addPreference(preference);
}
}

9
app/src/main/res/drawable-v21/bg_material.xml

@ -1,9 +0,0 @@ @@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#d4d4d4" >
<item>
<shape>
<solid android:color="@color/content_background" />
</shape>
</item>
</ripple>

3
app/src/main/res/drawable-v21/bg_ripple.xml

@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#d4d4d4" />

13
app/src/main/res/drawable/bg_material.xml

@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape>
<solid android:color="#cfcfcf" />
</shape>
</item>
<item>
<shape>
<solid android:color="#00000000" />
</shape>
</item>
</selector>

3
app/src/main/res/drawable/bg_ripple.xml

@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#d4d4d4" />

19
app/src/main/res/layout/fragment_data_list.xml

@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/HomeFragmentRootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.main.records.DataListFragment">
<!--数据展示view-->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/data_list_recyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintHeight_percent="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

162
app/src/main/res/layout/fragment_home.xml

@ -1,146 +1,50 @@ @@ -1,146 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/HomeFragmentRootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:fitsSystemWindows="true"
android:orientation="vertical"
tools:context=".ui.main.home.HomeFragment"
tools:ignore="RtlHardcoded,HardcodedText,RtlSymmetry,SmallSp">
<RelativeLayout
android:id="@+id/rl_tool"
android:layout_width="match_parent"
android:layout_height="52dp"
android:background="@color/colorPrimary">
<TextView
android:id="@+id/tv_month_day"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:paddingLeft="16dp"
android:textColor="#000000"
android:textSize="26sp"
android:textStyle="bold"
tools:ignore="RtlSymmetry" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_toRightOf="@+id/tv_month_day"
android:orientation="vertical"
android:paddingLeft="6dp"
android:paddingTop="12dp"
android:paddingRight="6dp"
android:paddingBottom="12dp"
tools:ignore="RelativeOverlap">
<TextView
android:id="@+id/tv_year"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:textColor="#000000"
android:textSize="10sp" />
tools:context=".ui.main.home.HomeFragment">
<!--标题view-->
<TextView
android:id="@+id/tv_lunar"
android:layout_width="wrap_content"
android:id="@+id/home_title_textView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center"
android:textColor="#000000"
android:textSize="10sp"
tools:ignore="SmallSp" />
</LinearLayout>
<FrameLayout
android:id="@+id/fl_current"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="12dp"
android:background="@drawable/bg_ripple">
<ImageView
android:id="@+id/ib_calendar"
app:layout_constraintHeight_percent="0.05"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!--
&lt;!&ndash;日历组件view&ndash;&gt;
<CalendarView
android:id="@+id/home_main_calendar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/app_name"
android:scaleType="centerInside"
android:src="@mipmap/ic_calendar"
app:tint="#000000" />
android:layout_height="0dp"
app:layout_constraintHeight_percent="0.45"
app:layout_constraintLeft_toLeftOf="@id/home_title_textView"
app:layout_constraintTop_toBottomOf="@id/home_title_textView" />
<TextView
android:id="@+id/tv_current_day"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="2dp"
android:gravity="center"
android:text="13"
android:textColor="#000000"
android:textSize="12sp" />
</FrameLayout>
</RelativeLayout>
<com.haibin.calendarview.CalendarLayout
android:id="@+id/calendarLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
android:orientation="vertical"
app:calendar_content_view_id="@+id/recyclerView">
-->
<com.haibin.calendarview.CalendarView
android:id="@+id/calendarView"
android:id="@+id/home_main_calendar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
android:background="#fff"
app:current_month_lunar_text_color="#CFCFCF"
app:current_month_text_color="#333333"
app:day_text_size="16sp"
app:lunar_text_size="8sp"
app:min_year="2004"
app:month_view="cc.niushuai.didicheck.ui.index.IndexMonthView"
app:month_view_show_mode="mode_fix"
app:other_month_text_color="#e1e1e1"
app:scheme_text="假"
app:scheme_text_color="#333"
app:scheme_theme_color="#128c4b"
app:selected_lunar_text_color="#CFCFCF"
app:selected_text_color="#333"
app:selected_theme_color="#80cfcfcf"
app:week_background="#fff"
app:week_text_color="#111"
app:week_view="cc.niushuai.didicheck.ui.index.IndexWeekView"
app:year_view_day_text_color="#333333"
app:year_view_day_text_size="9sp"
app:year_view_month_text_color="#ff0000"
app:year_view_month_text_size="20sp"
app:year_view_scheme_color="#f17706" />
android:layout_height="0dp"
app:layout_constraintHeight_percent="0.45"
app:layout_constraintLeft_toLeftOf="@id/home_title_textView"
app:layout_constraintTop_toBottomOf="@id/home_title_textView">
</com.haibin.calendarview.CalendarView>
<cc.niushuai.didicheck.ui.group.GroupRecyclerView
android:id="@+id/recyclerView"
<!--数据展示view-->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/home_dataZone_recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/content_background"
app:group_background="@color/content_background"
app:group_center="false"
app:group_has_header="false"
app:group_height="42dp"
app:group_padding_left="16dp"
app:group_padding_right="16dp"
app:group_text_color="#555555"
app:group_text_size="14sp" />
</com.haibin.calendarview.CalendarLayout>
android:layout_height="0dp"
app:layout_constraintHeight_percent="0.5"
app:layout_constraintLeft_toLeftOf="@id/home_main_calendar"
app:layout_constraintTop_toBottomOf="@+id/home_main_calendar" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

2
app/src/main/res/layout/item_list.xml

@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@mipmap/fab_icon_swimming" />
app:srcCompat="@mipmap/ic_ice_cream" />
<TextView
android:id="@+id/item_list_title_textView"

BIN
app/src/main/res/mipmap-hdpi/ic_ice_cream.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
app/src/main/res/mipmap-mdpi/ic_ice_cream.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 854 B

BIN
app/src/main/res/mipmap-xhdpi/ic_ice_cream.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
app/src/main/res/mipmap-xxhdpi/ic_ice_cream.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_calendar.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_clear.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_colorful_logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_custom.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_flyme_logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_full.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_func.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_ice_cream.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_increase.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 832 B

BIN
app/src/main/res/mipmap-xxxhdpi/ic_index_logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_more.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_multi.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_progress.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_range.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_reduce.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 853 B

BIN
app/src/main/res/mipmap-xxxhdpi/ic_simple_logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_single.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_solar_system.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_sun.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

BIN
app/src/main/res/mipmap-xxxhdpi/ic_tab_logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

14
app/src/main/res/values/arrays.xml

@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
<resources>
<!-- Reply Preference -->
<string-array name="reply_entries">
<item>Reply</item>
<item>Reply to all</item>
</string-array>
<string-array name="reply_values">
<item>reply</item>
<item>reply_all</item>
</string-array>
<string-array name="empty_array"/>
</resources>

15
app/src/main/res/values/attrs.xml

@ -1,15 +0,0 @@ @@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="GroupRecyclerView">
<attr name="group_height" format="dimension" />
<attr name="group_child_offset" format="dimension" />
<attr name="group_background" format="color" />
<attr name="group_text_color" format="color" />
<attr name="group_text_size" format="dimension" />
<attr name="group_center" format="boolean" />
<attr name="group_padding_left" format="dimension" />
<attr name="group_padding_right" format="dimension" />
<attr name="group_has_header" format="boolean" />
</declare-styleable>
</resources>

8
app/src/main/res/values/colors.xml

@ -7,12 +7,4 @@ @@ -7,12 +7,4 @@
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="colorPrimary">#ffffff</color>
<color name="colorPrimaryDark">#ffffff</color>
<color name="colorAccent">#ffffff</color>
<color name="line_color">#e7e7e7</color>
<color name="content_background">#f2f2f2</color>
<color name="solar_background">#009988</color>
</resources>

12
app/src/main/res/values/strings.xml

@ -4,5 +4,17 @@ @@ -4,5 +4,17 @@
<string name="tab_home">Home</string>
<string name="tab_records">Records</string>
<string name="tab_settings">Settings</string>
<!-- Preference Titles -->
<string name="setting_title">设置</string>
<string name="check_project">打卡项目列表</string>
<!-- Messages Preferences -->
<string name="data_import">导入数据</string>
<string name="data_export">导出数据</string>
<string name="add_new_check_record">添加新项目</string>
<string name="remove_old_check_record">删除旧项目</string>
<string name="select_to_remove_project">选择删除项目</string>
<string name="check_project_category_list">check_project_category_list</string>
<string name="empty_string"></string>
</resources>

48
app/src/main/res/xml/root_preferences.xml

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory app:title="@string/setting_title">
<CheckBoxPreference
app:key="data_import"
android:selectAllOnFocus="true"
android:singleLine="true"
app:title="@string/data_import" />
<CheckBoxPreference
app:key="data_export"
android:selectAllOnFocus="true"
android:singleLine="true"
app:title="@string/data_export" />
<EditTextPreference
android:key="@string/add_new_check_record"
app:key="@string/add_new_check_record"
android:selectAllOnFocus="true"
android:singleLine="true"
android:title="@string/add_new_check_record"
app:defaultValue="@string/empty_string"
/>
<MultiSelectListPreference
app:key="@string/remove_old_check_record"
android:key="@string/remove_old_check_record"
android:title="@string/remove_old_check_record"
app:defaultValue="@array/empty_array"
app:dialogTitle="@string/select_to_remove_project"
/>
</PreferenceCategory>
<PreferenceCategory
app:key="check_project_category_list"
app:title="@string/check_project"
>
</PreferenceCategory>
</PreferenceScreen>

BIN
icon/冰激凌.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
keystore/key.jks

Binary file not shown.
Loading…
Cancel
Save