业务逻辑主要在主界面MainFragment进行,流程图(非完整)如下:
抽象出一个对象——任务Task,创建
TaskBean类:
/**
*
* @ClassName TaskBean
* @Description a bean store task information; every time only have one running
* task
* @author kiyonlin@163.com
* @date 2014-1-6 下午1:46:12
*/
public class TaskBean {
/**
* task id in database for update or delete
*/
private int taskId;
/**
* number of task during days
*/
private int during;
/**
* number of completed days
*/
private int completed;
/**
* task content
*/
private String content;
/**
* the start date of task
*/
private String startTime;
/**
* flag if today's task is done
*/
private boolean doneToday;
/**
* flag if the task is running
*/
private boolean currentTask;
/**
*
* @Method: getStartDate
* @Description: get the start date of the task like "1月 03"
* @param @return
* @return String
* @throws
*/
@SuppressLint("SimpleDateFormat")
public String getStartDate() {
String startDate = "";
try {
SimpleDateFormat myFormatter = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
Date date = myFormatter.parse(startTime);
// long theDateMill = date.getTime() - (7 * (24 * 60 * 60 * 1000));
// Date theDate = new Date(theDateMill);
Calendar cal = Calendar.getInstance();
cal.setTime(date);
int day = cal.get(Calendar.DATE);
int month = cal.get(Calendar.MONTH) + 1;
startDate = month + "月 " + day + "日";
} catch (Exception e) {
return "";
}
return startDate;
}
/**
*
* @Method: getEndDate
* @Description: get the end date of the task like "1月 16"
* @param @return
* @return String
* @throws
*/
@SuppressLint("SimpleDateFormat")
public String getEndDate() {
String endDate = "";
try {
SimpleDateFormat myFormatter = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
Date date = myFormatter.parse(startTime);
// start date adds during days
long theDateMill = date.getTime()
+ ((during - 1) * (24 * 60 * 60 * 1000));
Date theDate = new Date(theDateMill);
Calendar cal = Calendar.getInstance();
cal.setTime(theDate);
int day = cal.get(Calendar.DATE);
int month = cal.get(Calendar.MONTH) + 1;
endDate = month + "月 " + day + "日";
} catch (Exception e) {
return "";
}
return endDate;
}
{...set and get }
}
相应数据存到本地数据库di.db3的tbl_task表(ID,持续天数,完成天数,任务内容,开始时间,今天是否签到,是否为当前任务)中,使用继承
SQLiteOpenHelper类的子类
MyDatabaseHelper来完成对数据库的操作:
public class MyDatabaseHelper extends SQLiteOpenHelper {
final String TAG = "MyDatabaseHelper";
final String CREATE_TABLE_SQL = "create table tbl_task(_id integer primary "
+ "key , during , completed, content, startTime, doneToday, currentTask)";
public MyDatabaseHelper(Context context, String name, int version) {
super(context, name, null, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
try {
// 第一次使用数据库时自动建表
db.execSQL(CREATE_TABLE_SQL);
} catch (SQLException e) {
Log.e(TAG, "SQLiteException, 创建表发生异常", e);
}
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "--------onUpdate database Called--------" + oldVersion
+ "--->" + newVersion);
}
}
对数据库的相关操作暂时有插入新任务、获取当前任务、获取任务列表、删除任务、更新签到状态。插入新任务时会将之前的任务(假如有的话)置为完成的状态,因为每次只允许有一个执行的任务。所有的方法都封装在
DailyInsistDao类中:
public class DailyInsistDao {
final static String TAG = "DailyInsistDao";
/**
*
* @Method: insertTask
* @Description: insert a new task
* @param @param dbHelper
* @param @param during the during days
* @param @param completed the completed days
* @param @param content task content
* @param @param startTime start time
* @return void
* @throws
*/
public static void insertTask(MyDatabaseHelper dbHelper, int during,
int completed, String content, String startTime, boolean doneToday) {
try {
/*
* every time only have one running task
*/
setTaskFinished(dbHelper);
boolean currentTask = true;
// 执行插入语句
dbHelper.getWritableDatabase().execSQL(
"insert into tbl_task values(? , ? , ?, ? , ?, ?, ?)",
new Object[] { null, during, completed, content, startTime,
doneToday, currentTask });
} catch (SQLException e) {
Log.e(TAG, "SQLiteException, 调用本地数据库插入操作insertTask发生异常", e);
}
}
/**
*
* @Method: getTasks
* @Description: get all tasks
* @param @param dbHelper
* @param @param npos
* @param @param ncount
* @param @return
* @return List<TaskBean>
* @throws
*/
public static List<TaskBean> getTasks(MyDatabaseHelper dbHelper, int npos,
int ncount) {
ArrayList<TaskBean> result = null;
Cursor cursor = null;
try {
// 执行查询
cursor = dbHelper.getReadableDatabase().rawQuery(
"select * from tbl_task order by _id DESC limit ?, ?",
new String[] { npos + "", ncount + "" });
result = new ArrayList<TaskBean>();
// 遍历Cursor结果集
while (cursor.moveToNext()) {
int taskId = cursor.getInt(0);
int during = cursor.getInt(1);
int completed = cursor.getInt(2);
String content = cursor.getString(3);
String startTime = cursor.getString(4);
boolean doneToday = cursor.getShort(5) == 0 ? false : true;
boolean currentTask = cursor.getShort(6) == 0 ? false : true;
// 将结果集中的数据存入ArrayList中
TaskBean otask = new TaskBean();
// 取出查询记录中的值
otask.setTaskId(taskId);
otask.setDuring(during);
otask.setCompleted(completed);
otask.setContent(content);
otask.setStartTime(startTime);
otask.setDoneToday(doneToday);
otask.setCurrentTask(currentTask);
result.add(otask);
}
} catch (SQLiteException e) {
Log.e(TAG, "SQLiteException, 调用本地数据库查询操作getTasks发生异常", e);
} finally {
if (cursor != null) {
cursor.close();
}
}
return result;
}
/**
*
* @Method: getcurrentTask
* @Description: get current task; return null if there is no running task
* @param @param dbHelper
* @param @return
* @return TaskBean
* @throws
*/
public static TaskBean getcurrentTask(MyDatabaseHelper dbHelper) {
Cursor cursor = null;
TaskBean otask = null;
try {
// 执行查询
cursor = dbHelper.getReadableDatabase().rawQuery(
"select * from tbl_task where currentTask = 1",
new String[] {});
// 遍历Cursor结果集
while (cursor.moveToNext()) {
// 取出查询记录中的值
int taskId = cursor.getInt(0);
int during = cursor.getInt(1);
int completed = cursor.getInt(2);
String content = cursor.getString(3);
String startTime = cursor.getString(4);
boolean doneToday = cursor.getShort(5) == 0 ? false : true;
boolean currentTask = cursor.getShort(6) == 0 ? false : true;
// 将结果集中的数据存入ArrayList中
otask = new TaskBean();
// 取出查询记录中的值
otask.setTaskId(taskId);
otask.setDuring(during);
otask.setCompleted(completed);
otask.setContent(content);
otask.setStartTime(startTime);
otask.setDoneToday(doneToday);
otask.setCurrentTask(currentTask);
return otask;
}
} catch (SQLException e) {
Log.e(TAG, "SQLiteException, 调用本地数据库插入操作insertVisitRecord发生异常", e);
} finally {
if (cursor != null) {
cursor.close();
}
}
return otask;
}
/**
*
* @Method: updateDoneState
* @Description: set everyday's done state; if done today, the completed day
* should increase
* @param @param dbHelper
* @param @param doneToday
* @return void
* @throws
*/
public static void updateDoneState(MyDatabaseHelper dbHelper, int taskId,
boolean doneToday) {
try {
String sql;
if (doneToday) {
sql = "update tbl_task set doneToday = ? "
+ ", completed = (completed + 1) " + "where _id = ?";
} else {
sql = "update tbl_task set doneToday = ? where _id = ?";
}
// 执行更新语句
dbHelper.getWritableDatabase().execSQL(sql,
new Object[] { doneToday, taskId });
Log.i(TAG, "updateDoneState success");
} catch (SQLException e) {
Log.e(TAG, "SQLiteException, 调用本地数据库插入操作updateDoneState发生异常", e);
}
}
/**
*
* @Method: setTaskFinished
* @Description: set the task to the passed one which had finished
* @param @param dbHelper
* @param @param currentTask
* @return void
* @throws
*/
private static void setTaskFinished(MyDatabaseHelper dbHelper) {
try {
// 执行更新语句
dbHelper.getWritableDatabase()
.execSQL(
"update tbl_task set currentTask = 0 where currentTask = 1");
} catch (SQLException e) {
Log.e(TAG, "SQLiteException, 调用本地数据库插入操作setTaskFinished发生异常", e);
}
}
/**
*
* @Method: deleteTask
* @Description: delete a task
* @param @param dbHelper
* @param @param taskId
* @return void
* @throws
*/
public static void deleteTask(MyDatabaseHelper dbHelper, int taskId) {
try {
// 执行更新语句
dbHelper.getWritableDatabase().execSQL(
"delete from tbl_task where _id = ?",
new Object[] { taskId });
} catch (SQLException e) {
Log.e(TAG, "SQLiteException, 调用本地数据库插入操作deleteTask发生异常", e);
}
}
}
程序开启后就会进入主界面,然后根据上述的业务逻辑进行判断如何显示界面。IOS版本中,点击“DoneToday”按钮后,会有动画效果,按钮先旋转再垂直下落至消失,然后显示剩余天数。这个效果后期再考虑。更新后的
MainFragment如下:
@EFragment(R.layout.frag_main)
public class MainFragment extends BaseFragment {
private MyDatabaseHelper dbHelper;
@ViewById
LinearLayout ll_new_round, ll_running_round, ll_frag_main_root;
@ViewById
TextView tv_done, tv_title, tv_remain;
@ViewById
Button btn_done_today, btn_new_round;
@StringRes
String str_remain_format, str_last_day, str_failed, str_finished;
@ColorRes
int main_bg, record_title_bg;
private TaskBean task;
@AfterViews
void initView() {
dbHelper = new MyDatabaseHelper(this.getActivity(), "di.db3", 1);
task = DailyInsistDao.getcurrentTask(dbHelper);
if (task == null) {
/*
* if there is no task, show New Round button
*/
ll_new_round.setVisibility(View.VISIBLE);
btn_new_round.setTextColor(main_bg);
ll_running_round.setVisibility(View.GONE);
} else {
ll_running_round.setVisibility(View.VISIBLE);
ll_new_round.setVisibility(View.GONE);
if (isTaskFailed(task.getCompleted(), task.getStartTime())) {
/*
* show failed title and new round button
*/
tv_remain.setText(str_failed);
ll_new_round.setVisibility(View.VISIBLE);
btn_new_round.setTextColor(main_bg);
} else {
/*
* show completed days, title
*/
tv_done.setText(task.getCompleted() + "");
tv_title.setText(task.getContent());
if (task.isDoneToday()) {
/*
* show remain days; hide done today button
*/
btn_done_today.setVisibility(View.GONE);
tv_remain.setVisibility(View.VISIBLE);
int remainDays = task.getDuring() - task.getCompleted();
showRemainDays(remainDays);
} else {
/*
* show done today button; hide remain days
*/
tv_remain.setVisibility(View.GONE);
btn_done_today.setVisibility(View.VISIBLE);
}
}
}
}
/**
*
* @Method: isTaskFailed
* @Description: check if the task is failed
* @param @param completed the completed days
* @param @param startTime time when the task started
* @param @return
* @return boolean
* @throws
*/
private boolean isTaskFailed(int completed, String startTime) {
/*
* get the days between now and the start time. if the value larger than
* completed days, then task failed
*/
int interval = Util.daysBetweenTwoDate(startTime.substring(0, 10), Util
.currentTime().substring(0, 10));
return interval > completed;
}
@AfterInject
void run() {
}
private static final int RC_NEW_ROUND = 0;
@Click
void btn_new_round() {
/*
* receive result in DailyInsistActivity
*/
Intent intent = new Intent(this.getActivity(), NewTaskActivity_.class);
this.getActivity().startActivityForResult(intent, RC_NEW_ROUND);
}
@Click
void btn_done_today() {
/*
* increase completed days by 1; show remain days
*/
// dismiss done today button by animate in the future
btn_done_today.setVisibility(View.GONE);
tv_done.setText("" + (task.getCompleted() + 1));
tv_remain.setVisibility(View.VISIBLE);
int remainDays = task.getDuring() - task.getCompleted() - 1;
showRemainDays(remainDays);
DailyInsistDao.updateDoneState(dbHelper, task.getTaskId(), true);
}
private void showRemainDays(int remainDays) {
switch (remainDays) {
case 0:
/*
* show finished layout
*/
tv_remain.setText(str_finished);
ll_frag_main_root.setBackgroundColor(record_title_bg);
ll_new_round.setVisibility(View.VISIBLE);
btn_new_round.setTextColor(record_title_bg);
break;
case 1:
tv_remain.setText(str_last_day);
int line = tv_remain.getLineCount();
while (line > 1) {
float textSize = tv_remain.getTextSize() - 1;
tv_remain.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
line = tv_remain.getLineCount();
}
break;
default:
tv_remain.setText(String.format(str_remain_format, remainDays));
break;
}
}
@Override
public void show() {
}
@UiThread
void showShortToastMsg(String msg) {
Toast.makeText(getActivity(), msg, Toast.LENGTH_SHORT).show();
}
@UiThread
void showLongToastMsg(String msg) {
Toast.makeText(getActivity(), msg, Toast.LENGTH_LONG).show();
}
}
新建任务是在另一个activity中(
NewTaskActivity)进行,这个activity也比较简单,获取到新任务的持续时间和内容后,插入到数据库中即可。有一点需要注意的是,选择任务周期需要对字体大小进行设置,只有一个参数的setTextSize (float size)方法,默认使用的单位是SP,而从资源文件获得的字体大小单位已经从SP转化为PX,所以使用该方法会使得字体比预计的要大。正确的方法是指定字体大小单位,使用setTextSize (int unit, float size)方法。另外,切换任务周期的时候可以加上动画,使得字体渐影放大(缩小)。具体代码如下:
@SuppressWarnings("deprecation")
@NoTitle
@EActivity(R.layout.new_task)
public class NewTaskActivity extends Activity {
/*
* default is 14 days
*/
private int during = 14;
@ViewById
TextView tv_7, tv_14, tv_21;
@ViewById
EditText et_todo;
@Click
void btn_ok() {
String whatToDo = et_todo.getText().toString();
if (TextUtils.isEmpty(whatToDo)) {
showAlertDialog();
} else {
MyDatabaseHelper dbHelper = new MyDatabaseHelper(this, "di.db3", 1);
DailyInsistDao.insertTask(dbHelper, during, 0, whatToDo,
Util.currentTime(), false);
setResult(RESULT_OK);
finish();
}
}
@Click
void btn_cancel() {
finish();
}
@DimensionRes
/*
* the obtained text size's unit is px
*/
float text_title, selected_days;
@ColorRes
int setting_text_light, main_text;
@Click
void tv_7() {
/*
* setTextSize(float size) use the default unit of sp
*/
tv_7.setTextColor(main_text);
tv_7.setTextSize(TypedValue.COMPLEX_UNIT_PX, selected_days);
tv_14.setTextColor(setting_text_light);
tv_14.setTextSize(TypedValue.COMPLEX_UNIT_PX, text_title);
tv_21.setTextColor(setting_text_light);
tv_21.setTextSize(TypedValue.COMPLEX_UNIT_PX, text_title);
during = 7;
}
@Click
void tv_14() {
tv_7.setTextColor(setting_text_light);
tv_7.setTextSize(TypedValue.COMPLEX_UNIT_PX, text_title);
tv_14.setTextColor(main_text);
tv_14.setTextSize(TypedValue.COMPLEX_UNIT_PX, selected_days);
tv_21.setTextColor(setting_text_light);
tv_21.setTextSize(TypedValue.COMPLEX_UNIT_PX, text_title);
during = 14;
}
@Click
void tv_21() {
tv_7.setTextColor(setting_text_light);
tv_7.setTextSize(TypedValue.COMPLEX_UNIT_PX, text_title);
tv_14.setTextColor(setting_text_light);
tv_14.setTextSize(TypedValue.COMPLEX_UNIT_PX, text_title);
tv_21.setTextColor(main_text);
tv_21.setTextSize(TypedValue.COMPLEX_UNIT_PX, selected_days);
during = 21;
}
private void showAlertDialog() {
new AlertDialog.Builder(this)
.setMessage("You should tell us what to do")
.setPositiveButton("OK", null).create().show();
}
}
相应的布局文件
new_task.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/main_bg"
android:orientation="vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="30dp" >
<TextView
style="@style/title_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/str_do" />
<EditText
android:id="@+id/et_todo"
android:layout_width="match_parent"
android:layout_height="36dp"
android:layout_margin="10dp"
android:background="@color/main_text"
android:ellipsize="end"
android:hint="@string/str_something"
android:singleLine="true"
android:textSize="@dimen/text_title" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp" >
<TextView
style="@style/title_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:text="@string/str_for" />
<TextView
android:id="@+id/tv_14"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:clickable="true"
android:text="@string/str_14"
android:textColor="@color/main_text"
android:textSize="@dimen/selected_days" />
<TextView
android:id="@+id/tv_7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="@+id/tv_14"
android:layout_centerVertical="true"
android:layout_marginRight="70dp"
android:clickable="true"
android:text="@string/str_7"
android:textColor="@color/setting_text_light"
android:textSize="@dimen/text_title" />
<TextView
android:id="@+id/tv_21"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/tv_14"
android:layout_centerVertical="true"
android:layout_marginLeft="55dp"
android:clickable="true"
android:text="@string/str_21"
android:textColor="@color/setting_text_light"
android:textSize="@dimen/text_title" />
<TextView
style="@style/title_text_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:text="@string/str_days" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp" >
<Button
android:id="@+id/btn_cancel"
style="@style/btn_small_style"
android:layout_width="128dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:background="@drawable/white_button"
android:text="@string/str_cancel" />
<Button
android:id="@+id/btn_ok"
style="@style/btn_small_style"
android:layout_width="128dp"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:background="@drawable/white_button"
android:text="@string/str_ok" />
</RelativeLayout>
</LinearLayout>
部分运行效果图:
目前为止源码: