From 849bab918757bd07b6bec26b4894f03f0278fd75 Mon Sep 17 00:00:00 2001 From: niushuai233 Date: Thu, 18 Apr 2024 17:40:04 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20:link:=20=E5=88=97=E8=A1=A8=E8=A7=86?= =?UTF-8?q?=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cc/niushuai/dididone/biz/BizGlobal.java | 80 +++++++++++++++ .../niushuai/dididone/biz/dao/RecordDao.java | 8 +- .../ui/calendar/CalendarFragment.java | 49 +-------- .../statistic/charts/BaseChartFragment.java | 23 +++++ .../ui/statistic/charts/ListFragment.java | 99 +++++++++++++++++++ .../main/res/layout/fragment_stat_list.xml | 68 +++++++++++-- 6 files changed, 269 insertions(+), 58 deletions(-) diff --git a/app/src/main/java/cc/niushuai/dididone/biz/BizGlobal.java b/app/src/main/java/cc/niushuai/dididone/biz/BizGlobal.java index 7ba1f36..5c45d9f 100644 --- a/app/src/main/java/cc/niushuai/dididone/biz/BizGlobal.java +++ b/app/src/main/java/cc/niushuai/dididone/biz/BizGlobal.java @@ -1,15 +1,30 @@ package cc.niushuai.dididone.biz; +import android.content.Context; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.mikepenz.iconics.IconicsDrawable; +import com.mikepenz.iconics.view.IconicsImageView; + import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; +import cc.niushuai.dididone.R; import cc.niushuai.dididone.biz.entity.Project; +import cc.niushuai.dididone.biz.entity.Record; import cc.niushuai.dididone.biz.roomx.DBManager; import cc.niushuai.dididone.biz.vo.ProjectCount; +import cc.niushuai.dididone.util.IntSnowflake; import cc.niushuai.dididone.util.XLog; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateUtil; import io.reactivex.Flowable; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; @@ -30,6 +45,10 @@ public class BizGlobal { public static void buildCache() { + if (!CACHE_PROJECT.isEmpty()) { + return; + } + // 打卡项缓存 buildProjectCache(); @@ -72,4 +91,65 @@ public class BizGlobal { public static Map getAvailableProjectMap() { return CACHE_PROJECT.values().stream().filter(item -> item.getDeleted().equals(0)).collect(Collectors.toMap(Project::getId, Function.identity())); } + + public static List getAvailableProjectList() { + return CACHE_PROJECT.values() + .stream() + .filter(item -> item.getDeleted().equals(0)) + .sorted((e1, e2) -> e2.getCreateDate().compareTo(e1.getCreateDate())) + .collect(Collectors.toList()); + } + + public static RelativeLayout getItemLayout(Context context, Project project, Record record) { + // 外层layout 白色背景 存在边距 + RelativeLayout itemLayout = new RelativeLayout(context); + RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, 175); + layoutParams.setMargins(25, 20, 25, 15); + + itemLayout.setId(IntSnowflake.next_id()); + itemLayout.setLayoutParams(layoutParams); + itemLayout.setPadding(15, 15, 15, 5); + itemLayout.setBackgroundResource(R.drawable.bg_miui10); +// itemLayout.setOrientation(LinearLayout.VERTICAL); + + // projectIcon layout + RelativeLayout.LayoutParams iconLayout = new RelativeLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + iconLayout.setMargins(10, 5, 0, 0); + IconicsImageView iconView = new IconicsImageView(context); + int iconViewId = IntSnowflake.next_id(); + iconView.setId(iconViewId); + iconView.setLayoutParams(iconLayout); + IconicsDrawable icon = new IconicsDrawable(context); + icon.icon(project.getIcon()).color(project.getIconColor()).sizeDp(50); + iconView.setIcon(icon); + + itemLayout.addView(iconView); + + RelativeLayout.LayoutParams projectLayout = new RelativeLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); + projectLayout.setMargins(20, 5, 0, 0); + projectLayout.addRule(RelativeLayout.RIGHT_OF, iconViewId); + int projectNameViewId = IntSnowflake.next_id(); + TextView projectTextView = getTextView(context, projectNameViewId, record.getName(), projectLayout, R.color._333333, 16, Gravity.CENTER_VERTICAL); + itemLayout.addView(projectTextView); + + RelativeLayout.LayoutParams dateLayout = new RelativeLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); + dateLayout.setMargins(20, 25, 0, 0); + dateLayout.addRule(RelativeLayout.RIGHT_OF, iconViewId); + dateLayout.addRule(RelativeLayout.BELOW, projectNameViewId); + TextView dateTextView = getTextView(context, IntSnowflake.next_id(), DateUtil.date(record.getCreateDate()).toString(DatePattern.NORM_DATETIME_PATTERN), dateLayout, R.color._666666, 12, Gravity.TOP); + itemLayout.addView(dateTextView); + return itemLayout; + } + + private static TextView getTextView(Context context, int id, String text, ViewGroup.LayoutParams textLayoutParams, int textColor, int textSize, int gravity) { + TextView textView = new TextView(context); + + textView.setId(id); + textView.setLayoutParams(textLayoutParams); + textView.setText(text); + textView.setTextColor(context.getResources().getColor(textColor)); + textView.setTextSize(textSize); + textView.setGravity(gravity); + return textView; + } } diff --git a/app/src/main/java/cc/niushuai/dididone/biz/dao/RecordDao.java b/app/src/main/java/cc/niushuai/dididone/biz/dao/RecordDao.java index e4a4adc..77052b9 100644 --- a/app/src/main/java/cc/niushuai/dididone/biz/dao/RecordDao.java +++ b/app/src/main/java/cc/niushuai/dididone/biz/dao/RecordDao.java @@ -4,7 +4,9 @@ import androidx.room.Dao; import androidx.room.Delete; import androidx.room.Insert; import androidx.room.Query; +import androidx.room.RoomWarnings; +import java.util.Iterator; import java.util.List; import cc.niushuai.dididone.biz.entity.Record; @@ -39,6 +41,10 @@ public interface RecordDao { @Query("select b.id, b.name, count(a.id) as count from t_record a left join t_project b on b.id = a.project_id and b.deleted = 0 where a.deleted = 0 group by b.id, b.name") Flowable> groupCountProject(); - @Query("select check_date from t_record where deleted = 0 and create_date >= :startTime and create_date <= :endTime order by check_date asc") + @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH) + @Query("select check_date from t_record where deleted = 0 and check_date >= :startTime and check_date <= :endTime order by check_date asc") Flowable> queryPointByDate(long startTime, long endTime); + + @Query("select * from t_record where deleted = 0 and project_id = :projectId and check_date >= :startDate and check_date <= :endDate order by check_date desc") + Flowable> queryByProjectAndDate(Long projectId, long startDate, long endDate); } diff --git a/app/src/main/java/cc/niushuai/dididone/ui/calendar/CalendarFragment.java b/app/src/main/java/cc/niushuai/dididone/ui/calendar/CalendarFragment.java index 0d65970..4bedb42 100644 --- a/app/src/main/java/cc/niushuai/dididone/ui/calendar/CalendarFragment.java +++ b/app/src/main/java/cc/niushuai/dididone/ui/calendar/CalendarFragment.java @@ -305,43 +305,7 @@ public class CalendarFragment extends Fragment { } private void add2Top(Project project, Record record) { - // 外层layout 白色背景 存在边距 - RelativeLayout itemLayout = new RelativeLayout(getContext()); - RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, 175); - layoutParams.setMargins(25, 20, 25, 15); - - itemLayout.setId(IntSnowflake.next_id()); - itemLayout.setLayoutParams(layoutParams); - itemLayout.setPadding(15, 15, 15, 5); - itemLayout.setBackgroundResource(R.drawable.bg_miui10); -// itemLayout.setOrientation(LinearLayout.VERTICAL); - - // projectIcon layout - RelativeLayout.LayoutParams iconLayout = new RelativeLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); - iconLayout.setMargins(10, 5, 0, 0); - IconicsImageView iconView = new IconicsImageView(getContext()); - int iconViewId = IntSnowflake.next_id(); - iconView.setId(iconViewId); - iconView.setLayoutParams(iconLayout); - IconicsDrawable icon = new IconicsDrawable(getContext()); - icon.icon(project.getIcon()).color(project.getIconColor()).sizeDp(50); - iconView.setIcon(icon); - - itemLayout.addView(iconView); - - RelativeLayout.LayoutParams projectLayout = new RelativeLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); - projectLayout.setMargins(20, 5, 0, 0); - projectLayout.addRule(RelativeLayout.RIGHT_OF, iconViewId); - int projectNameViewId = IntSnowflake.next_id(); - TextView projectTextView = this.getTextView(projectNameViewId, record.getName(), projectLayout, R.color._333333, 16, Gravity.CENTER_VERTICAL); - itemLayout.addView(projectTextView); - - RelativeLayout.LayoutParams dateLayout = new RelativeLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); - dateLayout.setMargins(20, 25, 0, 0); - dateLayout.addRule(RelativeLayout.RIGHT_OF, iconViewId); - dateLayout.addRule(RelativeLayout.BELOW, projectNameViewId); - TextView dateTextView = this.getTextView(IntSnowflake.next_id(), DateUtil.date(record.getCreateDate()).toString(DatePattern.NORM_DATETIME_PATTERN), dateLayout, R.color._666666, 12, Gravity.TOP); - itemLayout.addView(dateTextView); + RelativeLayout itemLayout = BizGlobal.getItemLayout(getContext(), project, record); itemLayout.setOnLongClickListener(new View.OnLongClickListener() { @Override @@ -378,17 +342,6 @@ public class CalendarFragment extends Fragment { DBManager.INSTANCE.recordDao().deleteById(record.getId()); } - private TextView getTextView(int id, String text, ViewGroup.LayoutParams textLayoutParams, int textColor, int textSize, int gravity) { - TextView textView = new TextView(getContext()); - - textView.setId(id); - textView.setLayoutParams(textLayoutParams); - textView.setText(text); - textView.setTextColor(getResources().getColor(textColor)); - textView.setTextSize(textSize); - textView.setGravity(gravity); - return textView; - } @Override public void onDestroyView() { diff --git a/app/src/main/java/cc/niushuai/dididone/ui/statistic/charts/BaseChartFragment.java b/app/src/main/java/cc/niushuai/dididone/ui/statistic/charts/BaseChartFragment.java index 9178f9a..adc112e 100644 --- a/app/src/main/java/cc/niushuai/dididone/ui/statistic/charts/BaseChartFragment.java +++ b/app/src/main/java/cc/niushuai/dididone/ui/statistic/charts/BaseChartFragment.java @@ -1,11 +1,25 @@ package cc.niushuai.dididone.ui.statistic.charts; +import java.util.Iterator; +import java.util.List; + +import cc.niushuai.dididone.biz.BizGlobal; +import cc.niushuai.dididone.biz.entity.Project; +import cc.niushuai.dididone.biz.entity.Record; +import cc.niushuai.dididone.biz.roomx.DBManager; import cc.niushuai.dididone.ui.base.BaseFragment; +import cc.niushuai.dididone.util.XLog; +import cn.hutool.core.date.DateUtil; +import io.reactivex.Flowable; +import io.reactivex.Single; +import io.reactivex.android.schedulers.AndroidSchedulers; public class BaseChartFragment extends BaseFragment { private String mTitle; + private List recordList; + public BaseChartFragment(String mTitle) { this.mTitle = mTitle; } @@ -13,4 +27,13 @@ public class BaseChartFragment extends BaseFragment { public String getTitle() { return mTitle; } + + public List getRecordList() { + return recordList; + } + + protected long dateStr2mills(String date) { + return DateUtil.parseDate(date).getTime(); + } + } diff --git a/app/src/main/java/cc/niushuai/dididone/ui/statistic/charts/ListFragment.java b/app/src/main/java/cc/niushuai/dididone/ui/statistic/charts/ListFragment.java index 41c350d..cecbea6 100644 --- a/app/src/main/java/cc/niushuai/dididone/ui/statistic/charts/ListFragment.java +++ b/app/src/main/java/cc/niushuai/dididone/ui/statistic/charts/ListFragment.java @@ -4,14 +4,33 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.RelativeLayout; +import android.widget.Spinner; +import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import java.util.List; +import java.util.stream.Collectors; + import cc.niushuai.dididone.R; +import cc.niushuai.dididone.biz.BizGlobal; +import cc.niushuai.dididone.biz.entity.Project; +import cc.niushuai.dididone.biz.entity.Record; +import cc.niushuai.dididone.biz.roomx.DBManager; +import cc.niushuai.dididone.databinding.FragmentStatListBinding; +import cc.niushuai.dididone.util.XLog; +import cn.hutool.core.date.DateUtil; +import io.reactivex.Flowable; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.schedulers.Schedulers; public class ListFragment extends BaseChartFragment { + private FragmentStatListBinding binding; public ListFragment() { super("列表视图"); @@ -21,7 +40,87 @@ public class ListFragment extends BaseChartFragment { @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_stat_list, container, false); + binding = FragmentStatListBinding.bind(view); return view; } + @Override + public void init() { + + // 初始化初始日期 + initDate(binding.statListStartDate, binding.statListEndDate); + // 初始化spinner + initSpinner(binding.statListSpinnerProject); + } + + private void initDate(TextView startDate, TextView endDate) { + String today = DateUtil.date().toDateStr(); + startDate.setText(today); + endDate.setText(today); + } + + private void initSpinner(Spinner spinner) { + + List items = BizGlobal.getAvailableProjectList().stream().map(item -> item.getName()).collect(Collectors.toList()); + spinner.setAdapter(new ArrayAdapter<>(getContext(), androidx.appcompat.R.layout.support_simple_spinner_dropdown_item, items)); + + spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + + onConditionChange(position, binding.statListStartDate.getText(), binding.statListEndDate.getText()); + } + + @Override + public void onNothingSelected(AdapterView parent) { + } + }); + spinner.setSelection(0); + } + + private void onConditionChange(int position, CharSequence startDate, CharSequence endDate) { + Flowable> listFlowable = DBManager.INSTANCE.recordDao().queryByProjectAndDate( + BizGlobal.getAvailableProjectList().get(position).getId(), + dateStr2mills(startDate.toString()), + dateStr2mills(endDate.toString())); + + listFlowable.subscribeOn(Schedulers.io()).subscribe(recordList -> { + XLog.d("recordList: {}", recordList.size()); + recordList.forEach(item -> XLog.d("{} at {}", item.getName(), DateUtil.date(item.getCheckDate()).toDateStr())); + + onRecordDataList(recordList); + }); + } + + private void onRecordDataList(List recordList) { + // 更新视图 + for (int i = recordList.size() - 1; i >= 0; i--) { + // 查出来的数据是倒叙的 + Record record = recordList.get(i); + getActivity().runOnUiThread(() -> { + binding.statListCheckInList.removeAllViews(); + add2Top(BizGlobal.CACHE_PROJECT.get(record.getProjectId()), record); + }); + } + } + + private void add2Top(Project project, Record record) { + + RelativeLayout itemLayout = BizGlobal.getItemLayout(getContext(), project, record); + + binding.statListCheckInList.addView(itemLayout, 0); + binding.statListSpinnerProject.requestLayout(); + } + + @Override + public void setListeners() { + + binding.statListStartDate.setOnClickListener(v -> { + + }); + + binding.statListEndDate.setOnClickListener(v -> { + + }); + } } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_stat_list.xml b/app/src/main/res/layout/fragment_stat_list.xml index cbcdf3d..9ddf6a7 100644 --- a/app/src/main/res/layout/fragment_stat_list.xml +++ b/app/src/main/res/layout/fragment_stat_list.xml @@ -1,12 +1,62 @@ - - + android:layout_height="match_parent" + android:orientation="vertical" + > + + + + + + + + + + + + + + + + + + \ No newline at end of file