You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
xiaomi/src/gtask/data/Task.java

454 lines
16 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* 版权所有 (c) 2010-2011MiCode 开源社区 (www.micode.net)
* 根据 Apache 许可证 2.0 版本("许可证")授权;
* 除非符合许可证的规定,否则不得使用本文件。
* 您可以从以下网址获取许可证副本:
* http://www.apache.org/licenses/LICENSE-2.0
* 除非适用法律要求或书面同意,本软件按"原样"分发,
* 没有任何明示或暗示的保证或条件。
* 详见许可证中规定的权限和限制。
* 这是一份标准的Apache许可证2.0版本的开源声明)
*/
// 定义当前类所在的包路径
package net.micode.notes.gtask.data;
// Android数据库相关类
import android.database.Cursor; // 数据库查询结果集
// Android文本处理工具
import android.text.TextUtils; // 字符串处理工具类
// Android日志工具
import android.util.Log; // 日志记录工具
// 笔记应用数据相关常量
import androidx.annotation.NonNull;
import net.micode.notes.data.Notes; // 笔记核心数据类
import net.micode.notes.data.Notes.DataColumns; // 数据表列名常量
import net.micode.notes.data.Notes.DataConstants; // 数据相关常量
import net.micode.notes.data.Notes.NoteColumns; // 笔记表列名常量
// 异常处理类
import net.micode.notes.gtask.exception.ActionFailureException; // 同步操作失败异常
// Google Task工具类
import net.micode.notes.tool.GTaskStringUtils; // Google Task字符串工具
// JSON处理相关类
import org.json.JSONArray; // JSON数组处理
import org.json.JSONException; // JSON异常处理
import org.json.JSONObject; // JSON对象处理
// Java工具类
import java.util.Objects; // 对象工具类
// Task类继承自Node基类表示Google Task中的一个任务项
public class Task extends Node {
// 日志标签
private static final String TAG = Task.class.getSimpleName();
// 任务状态字段
private boolean mCompleted; // 任务是否已完成
private String mNotes; // 任务备注/描述信息
private JSONObject mMetaInfo; // 存储元信息的JSON对象
// 任务关系字段
private Task mPriorSibling; // 前一个兄弟任务(用于排序)
private TaskList mParent; // 所属任务列表
// 默认构造函数
public Task() {
super(); // 调用父类构造函数
mCompleted = false; // 默认未完成
mNotes = null; // 默认无备注
mPriorSibling = null; // 默认无前驱任务
mParent = null; // 默认无父列表
mMetaInfo = null; // 默认无元信息
}
/**
* 生成创建任务的JSON动作
* @param actionId 动作ID
* @return 包含创建任务数据的JSON对象
*/
public JSONObject getCreateAction(int actionId) {
JSONObject js = new JSONObject();
try {
// 设置动作类型为创建
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE);
// 设置动作ID
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
// 设置任务索引位置
js.put(GTaskStringUtils.GTASK_JSON_INDEX, mParent.getChildTaskIndex(this));
// 构建任务实体数据
JSONObject entity = new JSONObject();
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // 任务名称
entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); // 创建者ID
entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE,
GTaskStringUtils.GTASK_JSON_TYPE_TASK); // 实体类型设为任务
// 如果有备注则添加
if (getNotes() != null) {
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());
}
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); // 添加实体数据
// 设置父任务列表ID
js.put(GTaskStringUtils.GTASK_JSON_PARENT_ID, mParent.getGid());
// 设置目标父类型为组
js.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT_TYPE,
GTaskStringUtils.GTASK_JSON_TYPE_GROUP);
// 设置列表ID
js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid());
// 如果有前驱任务则设置其ID
if (mPriorSibling != null) {
js.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, mPriorSibling.getGid());
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("生成任务创建JSON对象失败");
}
return js;
}
/**
* 生成更新任务的JSON动作
* @param actionId 动作ID
* @return 包含更新数据的JSON对象
*/
public JSONObject getUpdateAction(int actionId) {
JSONObject js = new JSONObject();
try {
// 设置动作类型为更新
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE);
// 设置动作ID
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
// 设置任务全局ID
js.put(GTaskStringUtils.GTASK_JSON_ID, getGid());
// 构建更新数据
JSONObject entity = new JSONObject();
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // 更新名称
// 如果有备注则更新
if (getNotes() != null) {
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());
}
// 设置删除状态
entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted());
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); // 添加更新数据
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("生成任务更新JSON对象失败");
}
return js;
}
/**
* 从远程JSON数据设置任务内容
* @param js 包含远程数据的JSON对象
*/
public void setContentByRemoteJSON(JSONObject js) {
if (js != null) {
try {
// 设置任务ID
if (js.has(GTaskStringUtils.GTASK_JSON_ID)) {
setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID));
}
// 设置最后修改时间
if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) {
setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED));
}
// 设置任务名称
if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) {
setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME));
}
// 设置任务备注
if (js.has(GTaskStringUtils.GTASK_JSON_NOTES)) {
setNotes(js.getString(GTaskStringUtils.GTASK_JSON_NOTES));
}
// 设置删除状态
if (js.has(GTaskStringUtils.GTASK_JSON_DELETED)) {
setDeleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_DELETED));
}
// 设置完成状态
if (js.has(GTaskStringUtils.GTASK_JSON_COMPLETED)) {
setCompleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_COMPLETED));
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("从JSON获取任务内容失败");
}
}
}
/**
* 从本地JSON数据设置任务内容
* @param js 包含本地数据的JSON对象
*/
public void setContentByLocalJSON(JSONObject js) {
// 检查数据有效性
if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)
|| !js.has(GTaskStringUtils.META_HEAD_DATA)) {
Log.w(TAG, "setContentByLocalJSON: 无可用数据");
}
try {
JSONObject note = Objects.requireNonNull(js).getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
// 验证类型是否为普通笔记
if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) {
Log.e(TAG, "无效的类型");
return;
}
// 从数据数组中查找笔记内容
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i);
if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) {
setName(data.getString(DataColumns.CONTENT)); // 设置任务名称
break;
}
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
}
}
/**
* 从任务内容生成本地JSON格式
* @return 包含任务数据的JSON对象
*/
public JSONObject getLocalJSONFromContent() {
String name = getName();
try {
if (mMetaInfo == null) {
// 从网页端创建的新任务
if (name == null) {
Log.w(TAG, "笔记内容为空");
return null;
}
// 构建新的JSON结构
return getJsonObject(name);
} else {
// 已同步的任务
JSONObject note = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
JSONArray dataArray = mMetaInfo.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
// 更新笔记内容
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i);
if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) {
data.put(DataColumns.CONTENT, getName());
break;
}
}
note.put(NoteColumns.TYPE, Notes.TYPE_NOTE); // 确保类型正确
return mMetaInfo; // 返回修改后的元信息
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
return null;
}
}
@NonNull
private static JSONObject getJsonObject(String name) throws JSONException {
JSONObject js = new JSONObject();
JSONObject note = new JSONObject();
JSONArray dataArray = new JSONArray();
JSONObject data = new JSONObject();
data.put(DataColumns.CONTENT, name); // 设置内容
dataArray.put(data);
js.put(GTaskStringUtils.META_HEAD_DATA, dataArray); // 添加数据数组
note.put(NoteColumns.TYPE, Notes.TYPE_NOTE); // 设置类型
js.put(GTaskStringUtils.META_HEAD_NOTE, note); // 添加笔记头
return js;
}
/**
* 设置任务元信息
* @param metaData 元数据对象
*/
public void setMetaInfo(MetaData metaData) {
if (metaData != null && metaData.getNotes() != null) {
try {
// 将元数据中的notes字符串转换为JSON对象
mMetaInfo = new JSONObject(metaData.getNotes());
} catch (JSONException e) {
Log.w(TAG, e.toString());
mMetaInfo = null;
}
}
}
/**
* 获取同步动作类型
* @param c 数据库Cursor
* @return 同步动作常量
*/
public int getSyncAction(Cursor c) {
try {
JSONObject noteInfo = null;
// 检查元信息中是否有笔记头
if (mMetaInfo != null && mMetaInfo.has(GTaskStringUtils.META_HEAD_NOTE)) {
noteInfo = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
}
if (noteInfo == null) {
Log.w(TAG, "笔记元信息似乎已被删除");
return SYNC_ACTION_UPDATE_REMOTE; // 需要从远程更新
}
if (!noteInfo.has(NoteColumns.ID)) {
Log.w(TAG, "远程笔记ID似乎已被删除");
return SYNC_ACTION_UPDATE_LOCAL; // 需要更新本地
}
// 验证笔记ID是否匹配
if (c.getLong(SqlNote.ID_COLUMN) != noteInfo.getLong(NoteColumns.ID)) {
Log.w(TAG, "笔记ID不匹配");
return SYNC_ACTION_UPDATE_LOCAL;
}
if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) {
// 本地无修改
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
// 双方都无更新
return SYNC_ACTION_NONE;
} else {
// 应用远程修改到本地
return SYNC_ACTION_UPDATE_LOCAL;
}
} else {
// 验证任务ID是否匹配
if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) {
Log.e(TAG, "任务ID不匹配");
return SYNC_ACTION_ERROR;
}
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
// 仅本地有修改
return SYNC_ACTION_UPDATE_REMOTE;
} else {
// 存在冲突
return SYNC_ACTION_UPDATE_CONFLICT;
}
}
} catch (Exception e) {
Log.e(TAG, e.toString());
e.printStackTrace();
}
return SYNC_ACTION_ERROR; // 默认返回错误
}
/*
* 检查任务是否值得保存
* @return 如果有有效数据返回true
*/
/**
* 检查当前任务对象是否包含有效数据,值得保存
* 满足以下任一条件即认为值得保存:
* 1. 存在元信息数据 或
* 2. 任务名称非空且不为纯空格 或
* 3. 任务备注非空且不为纯空格
*
* @return 如果包含有效数据返回true否则false
*/
public boolean isWorthSaving() {
return mMetaInfo != null || // 存在元信息
(getName() != null && !getName().trim().isEmpty()) || // 有有效名称
(getNotes() != null && !getNotes().trim().isEmpty()); // 有有效备注
}
/**
* 设置任务完成状态
* @param completed true表示任务已完成false表示未完成
*/
public void setCompleted(boolean completed) {
this.mCompleted = completed; // 更新完成状态字段
}
/**
* 设置任务备注内容
* @param notes 要设置的备注文本可为null表示清空备注
*/
public void setNotes(String notes) {
this.mNotes = notes; // 更新备注字段
}
/**
* 设置前驱任务(用于任务排序)
* @param priorSibling 前一个任务节点可为null表示没有前驱
*/
public void setPriorSibling(Task priorSibling) {
this.mPriorSibling = priorSibling; // 更新前驱任务引用
}
/**
* 设置所属任务列表
* @param parent 父任务列表对象不可为null
*/
public void setParent(TaskList parent) {
this.mParent = parent; // 更新父列表引用
}
/**
* 获取任务完成状态
* @return true表示任务已完成false表示未完成
*/
public boolean getCompleted() {
return this.mCompleted; // 返回当前完成状态
}
/**
* 获取任务备注内容
* @return 备注文本可能为null表示无备注
*/
public String getNotes() {
return this.mNotes; // 返回当前备注内容
}
/**
* 获取前驱任务(用于任务排序)
* @return 前一个任务节点可能为null表示没有前驱
*/
public Task getPriorSibling() {
return this.mPriorSibling; // 返回前驱任务引用
}
/**
* 获取所属任务列表
* @return 父任务列表对象
*/
public TaskList getParent() {
return this.mParent; // 返回父列表引用
}
}