diff --git a/app/schemas/cc.niushuai.dididone.biz.roomx.Database/1.json b/app/schemas/cc.niushuai.dididone.biz.roomx.Database/1.json deleted file mode 100644 index 44f9b2c..0000000 --- a/app/schemas/cc.niushuai.dididone.biz.roomx.Database/1.json +++ /dev/null @@ -1,170 +0,0 @@ -{ - "formatVersion": 1, - "database": { - "version": 1, - "identityHash": "3b066031a2741d47363ad506910e0a80", - "entities": [ - { - "tableName": "t_record", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `name` TEXT, `check_date` TEXT, `project_id` INTEGER, `description` TEXT, `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": "checkDate", - "columnName": "check_date", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "projectId", - "columnName": "project_id", - "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_project", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `name` TEXT, `icon` TEXT, `icon_color` 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": "TEXT", - "notNull": false - }, - { - "fieldPath": "iconColor", - "columnName": "icon_color", - "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": [] - }, - { - "tableName": "t_icon", - "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER, `icon` TEXT, `color` TEXT, `size` INTEGER, `create_date` INTEGER, `deleted` INTEGER, PRIMARY KEY(`id`))", - "fields": [ - { - "fieldPath": "id", - "columnName": "id", - "affinity": "INTEGER", - "notNull": false - }, - { - "fieldPath": "icon", - "columnName": "icon", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "color", - "columnName": "color", - "affinity": "TEXT", - "notNull": false - }, - { - "fieldPath": "size", - "columnName": "size", - "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, '3b066031a2741d47363ad506910e0a80')" - ] - } -} \ No newline at end of file diff --git a/app/src/main/java/cc/niushuai/dididone/biz/entity/Record.java b/app/src/main/java/cc/niushuai/dididone/biz/entity/Record.java index 0383c68..3f950a3 100644 --- a/app/src/main/java/cc/niushuai/dididone/biz/entity/Record.java +++ b/app/src/main/java/cc/niushuai/dididone/biz/entity/Record.java @@ -22,7 +22,7 @@ public class Record { private String name; @ColumnInfo(name = "check_date") - private String checkDate; + private Long checkDate; @ColumnInfo(name = "project_id") private Long projectId; @@ -52,11 +52,11 @@ public class Record { this.name = name; } - public String getCheckDate() { + public Long getCheckDate() { return checkDate; } - public void setCheckDate(String checkDate) { + public void setCheckDate(Long checkDate) { this.checkDate = checkDate; } 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 1c091ed..642539f 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 @@ -1,6 +1,7 @@ package cc.niushuai.dididone.ui.calendar; -import android.graphics.Color; +import android.content.Context; +import android.icu.text.DateFormat; import android.os.Bundle; import android.util.Log; import android.view.Gravity; @@ -15,7 +16,8 @@ import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; -import com.mikepenz.fontawesome_typeface_library.FontAwesome; +import com.github.clans.fab.FloatingActionButton; +import com.github.clans.fab.FloatingActionMenu; import com.mikepenz.iconics.IconicsDrawable; import com.mikepenz.iconics.view.IconicsImageView; import com.necer.calendar.BaseCalendar; @@ -26,14 +28,29 @@ import com.necer.painter.InnerPainter; import com.necer.utils.CalendarUtil; import org.joda.time.LocalDate; +import org.reactivestreams.Subscription; import java.util.List; 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.FragmentCalendarBinding; import cc.niushuai.dididone.util.IntSnowflake; +import cc.niushuai.dididone.util.Toasts; +import cc.niushuai.dididone.util.XLog; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; +import io.reactivex.Completable; +import io.reactivex.CompletableObserver; +import io.reactivex.Flowable; +import io.reactivex.FlowableSubscriber; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; public class CalendarFragment extends Fragment { @@ -41,6 +58,8 @@ public class CalendarFragment extends Fragment { private String lastDate; + private List floatingActionProjectList; + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { CalendarViewModel calendarViewModel = @@ -59,6 +78,9 @@ public class CalendarFragment extends Fragment { private void init() { // initPointList(); + + // 构建弹出框内容 + fetchNewestActionButtonData(); } private void initPointList(List pointList) { @@ -68,13 +90,85 @@ public class CalendarFragment extends Fragment { private void setListeners() { // 日历选择变更事件 - setCalendarChangeListener(); + addCalendarChangeListener(); + // floatAction + addFloatActionMenuToggleListener(); + } + + private void addFloatActionMenuToggleListener() { + binding.didiCheckMenu.setOnMenuToggleListener(new FloatingActionMenu.OnMenuToggleListener() { + @Override + public void onMenuToggle(boolean opened) { + if (opened) { + buildFloatActionButtons(floatingActionProjectList, getContext(), binding.didiCheckMenu); + } else { + // 关闭时清除所有button + binding.didiCheckMenu.removeAllMenuButtons(); + } + } + }); + } + + private void buildFloatActionButtons(List floatingActionProjectList, Context context, FloatingActionMenu didiCheckMenu) { + for (Project project : floatingActionProjectList) { + + FloatingActionButton actionButton = new FloatingActionButton(context); + actionButton.showButtonInMenu(true); + actionButton.show(true); + actionButton.setTag(project.getName() + project.getId()); + actionButton.setLabelText(project.getName()); + actionButton.setImageDrawable(new IconicsDrawable(context).icon(project.getIcon()).color(project.getIconColor()).sizeDp(24)); + 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) { + // 打卡完成 关闭动画 + didiCheckMenu.close(true); + // 添加数据 +// tabsPagerAdapter.getHomeFragment().add2Top(CheckTypeEnum.QUICK_ADD, actionButton.getLabelText()); + Record record = new Record(); + record.setProjectId(project.getId()); + record.setName(project.getName()); + record.setCheckDate(DateUtil.parseDate(lastDate).getTime()); + + // 插入数据库 + Completable completable = DBManager.INSTANCE.recordDao().insertAll(record); + completable.subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new CompletableObserver() { + @Override + public void onSubscribe(Disposable d) { + } + + @Override + public void onComplete() { + XLog.i("[{}]打卡成功", project.getName()); + Toasts.shortShow(getActivity(), "[{}]打卡成功", project.getName()); + + // 更新视图 + add2Top(project, record); + } + + @Override + public void onError(Throwable e) { + XLog.e("[{}]打卡失败, {}", project.getName(), e); + Toasts.shortShow(getActivity(), "[{}]打卡失败, {}", project.getName(), e.getMessage()); + } + }); + } + }); + + didiCheckMenu.addMenuButton(actionButton); + } } + /** * 日历选择变更事件 */ - private void setCalendarChangeListener() { + private void addCalendarChangeListener() { binding.miui10Calendar.setOnCalendarChangedListener(new OnCalendarChangedListener() { @Override @@ -87,17 +181,57 @@ public class CalendarFragment extends Fragment { Lunar lunar = CalendarUtil.getCalendarDate(localDate).lunar; String lunarDate = lunar.chineseEra + "年" + lunar.lunarMonthStr + lunar.lunarDayStr; - // 当前选中的日期放到最上面 - add2Top(new Record(), localDate.toString(), lunarDate); - // 重置上次选中日期 lastDate = localDate.toString(); + + // 重组日期 + rebuildRecordListViewByDate(lastDate); } }); } - private void add2Top(Record record, String localDate, String lunarDate) { + private void rebuildRecordListViewByDate(String date) { + DateTime dateTime = DateUtil.parseDate(date); + // 移除所有旧内容项 + binding.cCalendarCheckInList.removeAllViews(); + // 添加新内容项 + Flowable> flowable = DBManager.INSTANCE.recordDao().queryByDate(dateTime.getTime()); + flowable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) + .subscribe(new FlowableSubscriber>() { + @Override + public void onSubscribe(Subscription s) { + // 3s超时 + s.request(1); + } + + @Override + public void onNext(List recordList) { + XLog.d("DataListOnNext 查询到数据: {}", recordList.size()); + + for (Record record : recordList) { + Project project = BizGlobal.CACHE_PROJECT.get(record.getProjectId()); + if (null == project) { + Toasts.longShow(getContext(), "ProjectId: {}不存在, 可能存在BUG", String.valueOf(record.getProjectId())); + return; + } + add2Top(project, record); + } + } + + @Override + public void onError(Throwable t) { + Toasts.shortShow(getActivity(), "DataList根据时间拉取历史数据失败: ", t.getLocalizedMessage()); + } + + @Override + public void onComplete() { + } + }); + + } + + private void add2Top(Project project, Record record) { // 外层layout 白色背景 存在边距 RelativeLayout itemLayout = new RelativeLayout(getContext()); RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, 175); @@ -113,28 +247,30 @@ public class CalendarFragment extends Fragment { 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()); - iconView.setId(IntSnowflake.next_id()); + int iconViewId = IntSnowflake.next_id(); + iconView.setId(iconViewId); iconView.setLayoutParams(iconLayout); IconicsDrawable icon = new IconicsDrawable(getContext()); - icon.icon(FontAwesome.Icon.faw_swimmer).color(Color.BLUE).sizeDp(50); + 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, 111); - TextView projectTextView = this.getTextView(IntSnowflake.next_id(), localDate, projectLayout, R.color._333333, 16, Gravity.CENTER_VERTICAL); + 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, 111); - dateLayout.addRule(RelativeLayout.BELOW, 222); - TextView dateTextView = this.getTextView(IntSnowflake.next_id(), DateUtil.now(), dateLayout, R.color._666666, 12, Gravity.TOP); + 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); - binding.cCalendarCheckInList.removeAllViews(); +// binding.cCalendarCheckInList.removeAllViews(); binding.cCalendarCheckInList.addView(itemLayout, 0); binding.cCalendarCheckInList.requestLayout(); } @@ -156,4 +292,11 @@ public class CalendarFragment extends Fragment { super.onDestroyView(); binding = null; } + + + private void fetchNewestActionButtonData() { + Flowable> listFlowable = DBManager.INSTANCE.projectDao().listAll(); + listFlowable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()) + .subscribe(projectList -> floatingActionProjectList = projectList); + } } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_calendar.xml b/app/src/main/res/layout/fragment_calendar.xml index 3b15204..e03e8ba 100644 --- a/app/src/main/res/layout/fragment_calendar.xml +++ b/app/src/main/res/layout/fragment_calendar.xml @@ -41,11 +41,57 @@ android:id="@id/c_calendar_check_in_list" android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical"> - + android:orientation="vertical"> + + \ No newline at end of file