From 6054384cf04494fa6fabbcffdaa92dc489cf4da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=94=A1=E7=8E=89=E7=A5=A5?= <1120863985@qq.com> Date: Thu, 13 Apr 2023 14:27:37 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E8=94=A1=E7=8E=89=E7=A5=A5=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../net/micode/notes/gtask/data/MetaData.java | 44 ++++++++- .../net/micode/notes/gtask/data/Node.java | 88 ++++++++++++++++- .../net/micode/notes/gtask/data/SqlData.java | 94 +++++++++++++++---- 3 files changed, 202 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/net/micode/notes/gtask/data/MetaData.java b/app/src/main/java/net/micode/notes/gtask/data/MetaData.java index 3a2050b..b08b2f8 100644 --- a/app/src/main/java/net/micode/notes/gtask/data/MetaData.java +++ b/app/src/main/java/net/micode/notes/gtask/data/MetaData.java @@ -39,29 +39,60 @@ public class MetaData extends Task { setNotes(metaInfo.toString()); setName(GTaskStringUtils.META_NOTE_NAME); } + /* + 这段代码定义了一个名为 MetaData 的类,它继承了 Task 类。 + Meta Data 类有一个私有的属性 mRelatedGid,它的值为 null。 + 类中有两个方法,分别为 setMeta 和 getRelatedGid。 + setMeta 方法接受两个参数,一个字符串 gid 和一个 JSON 对象 metaInfo。 + 此方法会尝试在 metaInfo 对象中添加一个以 GTaskStringUtils.META_HEAD_GTASK_ID 为键、gid 为值的键值对,如果添加失败则输出一个错误日志。 + 随后该方法使用 setNotes 方法将 metaInfo 对象的字符串形式设置为任务的说明,并设置任务的名称为 GTaskStringUtils.META_NOTE_NAME。 + getRelatedGid 方法返回 mRelatedGid 属性的值。 + */ public String getRelatedGid() { return mRelatedGid; } + /*getRelatedGid() 方法: + 该方法返回 MetaData 对象的 mRelatedGid 字段,即任务的全局唯一标识符 gid。 + */ @Override public boolean isWorthSaving() { return getNotes() != null; } + /*isWorthSaving() 方法:该方法覆盖了 Task 类中的同名方法。 + 该方法返回一个布尔值,指示任务是否值得保存。 + 在这个实现中,如果任务的备注信息不为 null,则任务值得保存,返回 true; + 否则返回 false。 + */ + @Override - public void setContentByRemoteJSON(JSONObject js) { - super.setContentByRemoteJSON(js); + public void setContentByRemoteJSON(JSONObject js) {// 调用父类的方法来设置 JSON 内容 + super.setContentByRemoteJSON(js);// 检查是否存在与对象相关联的注释(notes) if (getNotes() != null) { try { + // 将注释内容解析为 JSON 对象 JSONObject metaInfo = new JSONObject(getNotes().trim()); + // 从 JSON 对象中提取 GTASK_ID 字段的值,并将其存储在 mRelatedGid 变量中 mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID); } catch (JSONException e) { + ///如果在解析注释时出现异常,则将 mRelatedGid 变量设置为 null,并记录一个警告日志 Log.w(TAG, "failed to get related gid"); mRelatedGid = null; } } } + /*这段代码是 MetaData 类的另外两个方法,isWorthSaving 和 setContentByRemoteJSON。 + + isWorthSaving 方法覆盖了 Task 类中的同名方法。 + 它返回一个布尔值,如果任务的说明不为 null,则返回 true,否则返回 false。 + + setContentByRemoteJSON 方法覆盖了 Task 类中的同名方法。 + 它接受一个 JSONObject 对象 js。首先,它调用了 Task 类中的 setContentByRemoteJSON 方法。 + 然后,它检查任务的说明是否为 null。 + 如果不是 null,则将它转换为一个 JSONObject 对象 metaInfo,然后从 metaInfo 对象中获取以 GTaskStringUtils.META_HEAD_GTASK_ID 为键的字符串值, + 将它赋值给 mRelatedGid 属性。如果无法从 metaInfo 对象中获取相关键值对,则将 mRelatedGid 属性赋值为 null,并输出一个警告日志。*/ @Override public void setContentByLocalJSON(JSONObject js) { @@ -80,3 +111,12 @@ public class MetaData extends Task { } } +/*这段代码定义了三个方法,均为覆盖(override)自父类 Task 的方法。这些方法被 MetaData 类重写,主要是为了禁止使用它们来保证程序的正确性。 + +setContentByLocalJSON 方法不应该被调用,因此该方法的实现中直接抛出了一个 IllegalAccessError 异常,提示该方法不应该被调用。 + +getLocalJSONFromContent 方法也不应该被调用,因此其实现方法与上述方法相同,也会抛出IllegalAccessError 异常。 + +getSyncAction 方法同样不应该被调用,并且其实现方法与前两个方法类似,会抛出一个IllegalAccessError 异常。 + +这些方法的目的是为了确保程序在运行时不会意外地调用这些方法,从而导致错误发生。如果有人在代码中尝试调用这些方法,将会得到明确的错误提示。*/ \ No newline at end of file diff --git a/app/src/main/java/net/micode/notes/gtask/data/Node.java b/app/src/main/java/net/micode/notes/gtask/data/Node.java index 63950e0..44ab2bc 100644 --- a/app/src/main/java/net/micode/notes/gtask/data/Node.java +++ b/app/src/main/java/net/micode/notes/gtask/data/Node.java @@ -46,14 +46,50 @@ public abstract class Node { private long mLastModified; private boolean mDeleted; +/*这是一个抽象类 Node 的定义,其中包含以下几个字段和常量: +字段 mGid:表示节点的全局唯一标识符 gid,每个节点都有一个唯一的 gid。 + +字段 mName:表示节点的名称,该字段为字符串类型。 + +字段 mLastModified:表示节点最后修改的时间戳,以毫秒为单位。 + +字段 mDeleted:表示节点是否被删除(true 表示已删除,false 表示未删除)。 + +常量 SYNC_ACTION_*:这些常量表示同步操作的各种情况。可以使用这些常量来指定要执行的同步操作类型。具体而言,这些常量的含义分别如下: + +SYNC_ACTION_NONE:不进行同步操作; + +SYNC_ACTION_ADD_REMOTE:在远程服务器上添加一个新节点; + +SYNC_ACTION_ADD_LOCAL:在本地数据库中添加一个新节点; + +SYNC_ACTION_DEL_REMOTE:在远程服务器上删除一个节点; + +SYNC_ACTION_DEL_LOCAL:在本地数据库中删除一个节点; + +SYNC_ACTION_UPDATE_REMOTE:在远程服务器上更新一个节点; + +SYNC_ACTION_UPDATE_LOCAL:在本地数据库中更新一个节点; + +SYNC_ACTION_UPDATE_CONFLICT:发生同步冲突,需要解决冲突; + +SYNC_ACTION_ERROR:同步错误,同步失败。 + +此外,Node 类还是一个抽象类,无法直接创建它的实例。所有的节点都是 Node 类的子类,以具体类型的形式继承 Node 类,并提供它们自己的实现。*/ public Node() { mGid = null; mName = ""; mLastModified = 0; mDeleted = false; } +/*这是 Node 类的默认构造方法。该方法会初始化节点的各个字段,包括 mGid、mName、mLastModified 和 mDeleted。 +具体而言,mGid 字段被初始化为 null,表示此时节点没有被分配一个全局唯一标识符; +mName 字段被初始化为空字符串,表示节点名称为空; +mLastModified 字段被初始化为 0,表示节点最后修改时间的时间戳为 0(即从未修改过); +mDeleted 字段被初始化为 false,表示节点当前未被删除。 + */ public abstract JSONObject getCreateAction(int actionId); public abstract JSONObject getUpdateAction(int actionId); @@ -65,23 +101,52 @@ public abstract class Node { public abstract JSONObject getLocalJSONFromContent(); public abstract int getSyncAction(Cursor c); +/*这是 Node 抽象类中的一些抽象方法,需要在其子类中进行实现。这些方法分别如下: + +getCreateAction(int actionId):该方法用于生成在远程服务器上创建一个新节点的 JSON 数据。actionId 表示同步操作类型,可以根据不同的同步操作类型来生成对应的 JSON 数据。 +getUpdateAction(int actionId):该方法用于生成在远程服务器上更新一个节点的 JSON 数据,与 getCreateAction 方法类似,actionId 表示同步操作类型。 + +setContentByRemoteJSON(JSONObject js):该方法用于从远程服务器返回的 JSON 数据中设置节点对象的属性值。 + +setContentByLocalJSON(JSONObject js):该方法用于从本地数据库中读取的 JSON 数据中设置节点对象的属性值。 + +getLocalJSONFromContent():该方法将节点对象转换为本地数据库中的 JSON 形式。 + +getSyncAction(Cursor c):该方法返回表示节点同步操作的常量。 + +这些抽象方法是用于描述哪些数据需要被从远程服务器或本地数据库中读取或写入,并且确定在特定同步操作期间执行的操作类型。这使得 Node 的子类可以根据具体情况对这些方法进行自定义实现,以适应不同场景的需求。*/ public void setGid(String gid) { this.mGid = gid; } - +/*这是 Node 类的 setGid 方法,用于设置节点的唯一标识符 gid。 +该方法接收一个 String 类型的参数 gid,表示要为节点设置的全局唯一标识符。 +在执行该方法时,将会将传入的 gid 参数赋值给 mGid 字段,以便在后续的操作中使用该值。 +这个方法可以被其子类调用来设置自己的 gid 值。 + */ public void setName(String name) { this.mName = name; } - +/*这是 Node 类的一个方法,用于设置节点的名称 mName 的值。 +它接受一个字符串类型的参数 name,并将它赋值给 mName 字段。 +this 表示当前对象实例。 + */ public void setLastModified(long lastModified) { this.mLastModified = lastModified; } - +/*setLastModified具有一个long类型的参数lastModified,表示将该对象的最后修改时间设置为给定值。 +在方法体内,关键字this表示当前对象的引用,即在调用该方法的对象。 +将参数lastModified的值分配给该对象的私有成员变量mLastModified,以便以后可以通过getter方法检索该值。 + */ public void setDeleted(boolean deleted) { this.mDeleted = deleted; } +/*这是一个Java类中的公共方法,名称为setDeleted,它具有一个boolean类型的参数deleted,表示将该对象的删除状态设置为给定的值。 +在方法体内,关键字this表示当前对象的引用,即在调用该方法的对象。 +将参数deleted的值分配给该对象的私有成员变量mDeleted,以便以后可以通过getter方法检索该值。 +如果参数deleted的值为true,则表示该对象被删除;如果参数deleted的值为false,则表示该对象未被删除。 + */ public String getGid() { return this.mGid; } @@ -89,13 +154,30 @@ public abstract class Node { public String getName() { return this.mName; } +/*这是一个Java类中的公共方法,名称分别为getGid和getName,它们都不具有任何参数,并返回该对象的私有成员变量mGid和mName的值,分别表示该对象的ID和名称。 +在方法体内,关键字this表示当前对象的引用,即在调用该方法的对象。 +这些方法通常用于获取对象的状态,而不是修改状态。 +例如,在代码中调用getGid方法将返回该对象的ID,以便在其他操作中使用该ID。 +同样,调用getName方法将返回该对象的名称。 + */ public long getLastModified() { return this.mLastModified; } +/*这是一个Java类中的公共方法,名称为getLastModified,它不具有任何参数,并返回该对象的私有成员变量mLastModified的值,表示该对象的最后修改时间。 +在方法体内,关键字this表示当前对象的引用,即在调用该方法的对象。 +这个方法通常用于获取对象的状态,以便在其他操作中使用该状态。 +例如,在代码中调用getLastModified方法将返回该对象的最后修改时间,以便在其他操作中使用该时间戳。 + */ public boolean getDeleted() { return this.mDeleted; } +/*这是一个Java类中的公共方法,名称为getDeleted,它不具有任何参数,并返回该对象的私有成员变量mDeleted的值,表示该对象是否被删除。 +在方法体内,关键字this表示当前对象的引用,即在调用该方法的对象。 +这个方法通常用于获取对象的状态,以便在其他操作中使用该状态。 +例如,在代码中调用getDeleted方法将返回一个boolean类型的值,表示该对象是否被删除。 +如果该值为true,则表示该对象已被删除;如果该值为false,则表示该对象未被删除。 + */ } diff --git a/app/src/main/java/net/micode/notes/gtask/data/SqlData.java b/app/src/main/java/net/micode/notes/gtask/data/SqlData.java index d3ec3be..e6a6be8 100644 --- a/app/src/main/java/net/micode/notes/gtask/data/SqlData.java +++ b/app/src/main/java/net/micode/notes/gtask/data/SqlData.java @@ -44,7 +44,15 @@ public class SqlData { DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1, DataColumns.DATA3 }; +/*这是一个Java类,名称为SqlData,其中定义了一些静态变量和常量,用于在类内和类外引用。 +第一行定义了一个名为TAG的静态常量字符串,用于在日志中标识该类。这个字符串的值是SqlData类的简单名称。 + +第二行定义了一个名为INVALID_ID的私有静态常量整数,用于表示无效的ID。该值被设置为-99999。 + +第三行定义了一个名为PROJECTION_DATA的公共静态常量字符串数组,用于定义一个查询所需返回的列。这些列包括DataColumns类中定义的ID、MIME_TYPE、CONTENT、DATA1和DATA3。 + +这些变量和常量都被声明为静态的,这意味着它们属于类本身,而不是类的实例。因此,它们可以在类的所有实例之间共享和访问。这些变量和常量的使用可以提高代码的可读性和可维护性,并避免在代码中多次重复相同的值。*/ public static final int DATA_ID_COLUMN = 0; public static final int DATA_MIME_TYPE_COLUMN = 1; @@ -70,66 +78,96 @@ public class SqlData { private String mDataContentData3; private ContentValues mDiffDataValues; +/*这是一个Java类,名称为SqlData,其中定义了一些成员变量和常量,用于在类内存储和操作数据。 + +第一行定义了一个名为DATA_ID_COLUMN的公共静态常量整数,用于表示列索引中的数据ID列。 + +第二行定义了一个名为DATA_MIME_TYPE_COLUMN的公共静态常量整数,用于表示列索引中的MIME类型列。 +第三行定义了一个名为DATA_CONTENT_COLUMN的公共静态常量整数,用于表示列索引中的内容列。 + +第四行定义了一个名为DATA_CONTENT_DATA_1_COLUMN的公共静态常量整数,用于表示列索引中的DATA1列。 + +第五行定义了一个名为DATA_CONTENT_DATA_3_COLUMN的公共静态常量整数,用于表示列索引中的DATA3列。 + +接下来的几行定义了该类的一些成员变量,包括ContentResolver类型的mContentResolver、boolean类型的mIsCreate、long类型的mDataId、String类型的mDataMimeType、String类型的mDataContent、long类型的mDataContentData1、String类型的mDataContentData3和ContentValues类型的mDiffDataValues。这些变量表示了该类的不同数据属性。 + +其中,ContentValues是一个键值对的集合,用于在Android应用中存储和操作数据。在该类中,mDiffDataValues被用于存储该对象的数据属性的差异,即该对象已更改但尚未提交到数据库中的值。*/ + // 构造函数用于初始化一个SqlData对象的实例 public SqlData(Context context) { - mContentResolver = context.getContentResolver(); - mIsCreate = true; - mDataId = INVALID_ID; - mDataMimeType = DataConstants.NOTE; - mDataContent = ""; - mDataContentData1 = 0; - mDataContentData3 = ""; - mDiffDataValues = new ContentValues(); + mContentResolver = context.getContentResolver();// 获取ContentResolver对象,用于访问ContentProvider中的数据 + mIsCreate = true;// 初始化数据的创建状态 + mDataId = INVALID_ID; // 初始化数据的ID值 + mDataMimeType = DataConstants.NOTE;// 初始化数据的MIME类型为NOTE + mDataContent = ""; // 初始化数据的内容为空字符串 + mDataContentData1 = 0; // 初始化数据的数据内容Data1为0 + mDataContentData3 = "";// 初始化数据的数据内容Data3为空字符串 + mDiffDataValues = new ContentValues();// 初始化差异数据的ContentValues对象,用于保存数据的不同之处 } + // 定义SqlData类,该类用于处理数据库中的数据 public SqlData(Context context, Cursor c) { + // 获取ContentResolver对象 mContentResolver = context.getContentResolver(); + // 设置初始状态为非创建状态 mIsCreate = false; + // 从Cursor对象中读取数据,并将数据加载到 loadFromCursor(c); + // 创建一个新的ContentValues对象,用于存储数据的差异 mDiffDataValues = new ContentValues(); } - +/*该构造函数主要是用于初始化SqlData对象,并且在初始化过程中从Cursor对象中读取数据,同时创建一个新的ContentValues对象,以备后续存储数据的差异。*/ +/*定义了一个私有方法loadFromCursor,该方法接收一个Cursor对象作为参数,并且在该方法中从Cursor对象中读取数据,将这些数据加载到SqlData对象中。*/ +// 从Cursor对象中读取数据,并将数据加载到SqlData对象中 private void loadFromCursor(Cursor c) { + // 从Cursor对象中读取数据id mDataId = c.getLong(DATA_ID_COLUMN); + // 从Cursor对象中读取数据类型 mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN); + // 从Cursor对象中读取数据内容 mDataContent = c.getString(DATA_CONTENT_COLUMN); + // 从Cursor对象中读取数据内容的第一个数据项 mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN); + // 从Cursor对象中读取数据内容的第三个数据项 mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN); } - - public void setContent(JSONObject js) throws JSONException { - long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID; +/*该方法主要是用于从Cursor对象中读取数据,并将这些数据加载到SqlData对象的相关成员变量中。其中,数据的读取顺序和类型需要与Cursor对象中的列名一一对应。*/ + public void setContent(JSONObject js) throws JSONException {// 设置SqlData对象的内容 + long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID;// 从JSONObject对象中获取数据id if (mIsCreate || mDataId != dataId) { mDiffDataValues.put(DataColumns.ID, dataId); } - mDataId = dataId; + mDataId = dataId; // 如果当前SqlData对象是创建状态,或者数据id与当前对象的数据id不同,将数据id加入到差异数据值对象中 +//setContent方法的主要部分,用于设置SqlData对象的各个成员变量值,并且在设置过程中检查差异数据。 String dataMimeType = js.has(DataColumns.MIME_TYPE) ? js.getString(DataColumns.MIME_TYPE) : DataConstants.NOTE; if (mIsCreate || !mDataMimeType.equals(dataMimeType)) { mDiffDataValues.put(DataColumns.MIME_TYPE, dataMimeType); } mDataMimeType = dataMimeType; - + // 从JSONObject对象中获取数据类型,并将其设置为SqlData对象的数据类型 String dataContent = js.has(DataColumns.CONTENT) ? js.getString(DataColumns.CONTENT) : ""; if (mIsCreate || !mDataContent.equals(dataContent)) { mDiffDataValues.put(DataColumns.CONTENT, dataContent); } mDataContent = dataContent; - + // 从JSONObject对象中获取数据内容的第一个数据项,并将其设置为SqlData对象的数据内容的第一个数据项 long dataContentData1 = js.has(DataColumns.DATA1) ? js.getLong(DataColumns.DATA1) : 0; if (mIsCreate || mDataContentData1 != dataContentData1) { mDiffDataValues.put(DataColumns.DATA1, dataContentData1); } mDataContentData1 = dataContentData1; - + // 从JSONObject对象中获取数据内容的第三个数据项,并将其设置为SqlData对象的数据内容的第三个数据项 String dataContentData3 = js.has(DataColumns.DATA3) ? js.getString(DataColumns.DATA3) : ""; if (mIsCreate || !mDataContentData3.equals(dataContentData3)) { mDiffDataValues.put(DataColumns.DATA3, dataContentData3); } mDataContentData3 = dataContentData3; } - +/*该代码段主要是根据JSONObject对象中的数据,设置SqlData对象的相应成员变量,并且在设置过程中检查差异数据。 + 其中,如果当前SqlData对象是创建状态,或者相应成员变量的值与JSONObject对象中的值不同,就将相应的数据加入到差异数据值对象中。 + 这些差异数据值将在后续的操作中被用于更新数据库中的数据。*/ public JSONObject getContent() throws JSONException { if (mIsCreate) { Log.e(TAG, "it seems that we haven't created this in database yet"); @@ -143,6 +181,11 @@ public class SqlData { js.put(DataColumns.DATA3, mDataContentData3); return js; } +/*这段代码定义了一个名为getContent()的方法,它返回一个JSONObject对象。 +该方法可能会抛出一个JSONException异常,因此在调用该方法时需要处理该异常。 +方法体内的第一条语句检查一个名为mIsCreate的 boolean 类型的成员变量是否为 true,如果是,则输出一个错误日志并返回 null。否则,方法会创建一个新的JSONObject对象,并向它添加一些键值对,这些键值对是由mDataId、mDataMimeType、mDataContent、mDataContentData1和mDataContentData3这些成员变量组成的。 +最后,该方法返回一个JSONObject对象,其中包含了这些成员变量的值。*/ + public void commit(long noteId, boolean validateVersion, long version) { @@ -182,8 +225,21 @@ public class SqlData { mDiffDataValues.clear(); mIsCreate = false; } - +/*这段代码定义了一个名为commit()的方法,用于将已经修改的数据保存到数据库中。 +方法接受三个参数:noteId为 long 类型,表示当前笔记的 ID; +validateVersion为 boolean 类型,表示是否需要验证版本; +version为 long 类型,表示当前笔记的版本。 +方法体内的第一条语句检查一个名为mIsCreate的boolean类型的成员变量是否为true,如果是,则表示当前是创建一个新的数据,需要将数据插入到数据库中。 +如果mDiffDataValues中包含 DataColumns.ID 这个键值对,表明该成员变量的值已经被赋值,需要将其移除,因为它是自增的主键,不应该由用户指定。 +接下来,将 DataColumns.NOTE_ID 对应的值设置为noteId,并将mDiffDataValues插入到Notes.CONTENT_DATA_URI中获取Uri对象,然后Uri对象中获取新的数据的 ID 并设置给成员变量mDataId。 +如果获取 ID 失败,则记录错误日志并抛出一个ActionFailureException异常。 +如果mIsCreate的值为 false,则表示需要更新数据库中的数据。 +如果mDiffDataValues中有数据,则调用mContentResolver.update()方法对数据库进行更新。 +如果validateVersion的值为 false,则直接更新数据,否则需要先验证版本。验证版本的过程是通过查询NoteColumns.VERSION等于version且NoteColumns.ID等于的noteId +无论是插入数据还是更新数据,都需要清空mDiffDataValues的内容并将mIsCreate设为 false,表示数据已经提交保存到数据库中。*/ public long getId() { return mDataId; - } + }//定义了一个名为getId()的方法,返回一个long类型的值,表示当前笔记的ID。 + //直接返回成员变量mDataId,因此不会引发任何异常。 } +6 \ No newline at end of file From 293c984ad5c228ca623dda7041aa3d60293be27e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=94=A1=E7=8E=89=E7=A5=A5?= <1120863985@qq.com> Date: Thu, 13 Apr 2023 14:27:37 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E8=94=A1=E7=8E=89=E7=A5=A5=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../net/micode/notes/gtask/data/MetaData.java | 44 ++++++++- .../net/micode/notes/gtask/data/Node.java | 88 ++++++++++++++++- .../net/micode/notes/gtask/data/SqlData.java | 94 +++++++++++++++---- 3 files changed, 202 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/net/micode/notes/gtask/data/MetaData.java b/app/src/main/java/net/micode/notes/gtask/data/MetaData.java index 3a2050b..b08b2f8 100644 --- a/app/src/main/java/net/micode/notes/gtask/data/MetaData.java +++ b/app/src/main/java/net/micode/notes/gtask/data/MetaData.java @@ -39,29 +39,60 @@ public class MetaData extends Task { setNotes(metaInfo.toString()); setName(GTaskStringUtils.META_NOTE_NAME); } + /* + 这段代码定义了一个名为 MetaData 的类,它继承了 Task 类。 + Meta Data 类有一个私有的属性 mRelatedGid,它的值为 null。 + 类中有两个方法,分别为 setMeta 和 getRelatedGid。 + setMeta 方法接受两个参数,一个字符串 gid 和一个 JSON 对象 metaInfo。 + 此方法会尝试在 metaInfo 对象中添加一个以 GTaskStringUtils.META_HEAD_GTASK_ID 为键、gid 为值的键值对,如果添加失败则输出一个错误日志。 + 随后该方法使用 setNotes 方法将 metaInfo 对象的字符串形式设置为任务的说明,并设置任务的名称为 GTaskStringUtils.META_NOTE_NAME。 + getRelatedGid 方法返回 mRelatedGid 属性的值。 + */ public String getRelatedGid() { return mRelatedGid; } + /*getRelatedGid() 方法: + 该方法返回 MetaData 对象的 mRelatedGid 字段,即任务的全局唯一标识符 gid。 + */ @Override public boolean isWorthSaving() { return getNotes() != null; } + /*isWorthSaving() 方法:该方法覆盖了 Task 类中的同名方法。 + 该方法返回一个布尔值,指示任务是否值得保存。 + 在这个实现中,如果任务的备注信息不为 null,则任务值得保存,返回 true; + 否则返回 false。 + */ + @Override - public void setContentByRemoteJSON(JSONObject js) { - super.setContentByRemoteJSON(js); + public void setContentByRemoteJSON(JSONObject js) {// 调用父类的方法来设置 JSON 内容 + super.setContentByRemoteJSON(js);// 检查是否存在与对象相关联的注释(notes) if (getNotes() != null) { try { + // 将注释内容解析为 JSON 对象 JSONObject metaInfo = new JSONObject(getNotes().trim()); + // 从 JSON 对象中提取 GTASK_ID 字段的值,并将其存储在 mRelatedGid 变量中 mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID); } catch (JSONException e) { + ///如果在解析注释时出现异常,则将 mRelatedGid 变量设置为 null,并记录一个警告日志 Log.w(TAG, "failed to get related gid"); mRelatedGid = null; } } } + /*这段代码是 MetaData 类的另外两个方法,isWorthSaving 和 setContentByRemoteJSON。 + + isWorthSaving 方法覆盖了 Task 类中的同名方法。 + 它返回一个布尔值,如果任务的说明不为 null,则返回 true,否则返回 false。 + + setContentByRemoteJSON 方法覆盖了 Task 类中的同名方法。 + 它接受一个 JSONObject 对象 js。首先,它调用了 Task 类中的 setContentByRemoteJSON 方法。 + 然后,它检查任务的说明是否为 null。 + 如果不是 null,则将它转换为一个 JSONObject 对象 metaInfo,然后从 metaInfo 对象中获取以 GTaskStringUtils.META_HEAD_GTASK_ID 为键的字符串值, + 将它赋值给 mRelatedGid 属性。如果无法从 metaInfo 对象中获取相关键值对,则将 mRelatedGid 属性赋值为 null,并输出一个警告日志。*/ @Override public void setContentByLocalJSON(JSONObject js) { @@ -80,3 +111,12 @@ public class MetaData extends Task { } } +/*这段代码定义了三个方法,均为覆盖(override)自父类 Task 的方法。这些方法被 MetaData 类重写,主要是为了禁止使用它们来保证程序的正确性。 + +setContentByLocalJSON 方法不应该被调用,因此该方法的实现中直接抛出了一个 IllegalAccessError 异常,提示该方法不应该被调用。 + +getLocalJSONFromContent 方法也不应该被调用,因此其实现方法与上述方法相同,也会抛出IllegalAccessError 异常。 + +getSyncAction 方法同样不应该被调用,并且其实现方法与前两个方法类似,会抛出一个IllegalAccessError 异常。 + +这些方法的目的是为了确保程序在运行时不会意外地调用这些方法,从而导致错误发生。如果有人在代码中尝试调用这些方法,将会得到明确的错误提示。*/ \ No newline at end of file diff --git a/app/src/main/java/net/micode/notes/gtask/data/Node.java b/app/src/main/java/net/micode/notes/gtask/data/Node.java index 63950e0..44ab2bc 100644 --- a/app/src/main/java/net/micode/notes/gtask/data/Node.java +++ b/app/src/main/java/net/micode/notes/gtask/data/Node.java @@ -46,14 +46,50 @@ public abstract class Node { private long mLastModified; private boolean mDeleted; +/*这是一个抽象类 Node 的定义,其中包含以下几个字段和常量: +字段 mGid:表示节点的全局唯一标识符 gid,每个节点都有一个唯一的 gid。 + +字段 mName:表示节点的名称,该字段为字符串类型。 + +字段 mLastModified:表示节点最后修改的时间戳,以毫秒为单位。 + +字段 mDeleted:表示节点是否被删除(true 表示已删除,false 表示未删除)。 + +常量 SYNC_ACTION_*:这些常量表示同步操作的各种情况。可以使用这些常量来指定要执行的同步操作类型。具体而言,这些常量的含义分别如下: + +SYNC_ACTION_NONE:不进行同步操作; + +SYNC_ACTION_ADD_REMOTE:在远程服务器上添加一个新节点; + +SYNC_ACTION_ADD_LOCAL:在本地数据库中添加一个新节点; + +SYNC_ACTION_DEL_REMOTE:在远程服务器上删除一个节点; + +SYNC_ACTION_DEL_LOCAL:在本地数据库中删除一个节点; + +SYNC_ACTION_UPDATE_REMOTE:在远程服务器上更新一个节点; + +SYNC_ACTION_UPDATE_LOCAL:在本地数据库中更新一个节点; + +SYNC_ACTION_UPDATE_CONFLICT:发生同步冲突,需要解决冲突; + +SYNC_ACTION_ERROR:同步错误,同步失败。 + +此外,Node 类还是一个抽象类,无法直接创建它的实例。所有的节点都是 Node 类的子类,以具体类型的形式继承 Node 类,并提供它们自己的实现。*/ public Node() { mGid = null; mName = ""; mLastModified = 0; mDeleted = false; } +/*这是 Node 类的默认构造方法。该方法会初始化节点的各个字段,包括 mGid、mName、mLastModified 和 mDeleted。 +具体而言,mGid 字段被初始化为 null,表示此时节点没有被分配一个全局唯一标识符; +mName 字段被初始化为空字符串,表示节点名称为空; +mLastModified 字段被初始化为 0,表示节点最后修改时间的时间戳为 0(即从未修改过); +mDeleted 字段被初始化为 false,表示节点当前未被删除。 + */ public abstract JSONObject getCreateAction(int actionId); public abstract JSONObject getUpdateAction(int actionId); @@ -65,23 +101,52 @@ public abstract class Node { public abstract JSONObject getLocalJSONFromContent(); public abstract int getSyncAction(Cursor c); +/*这是 Node 抽象类中的一些抽象方法,需要在其子类中进行实现。这些方法分别如下: + +getCreateAction(int actionId):该方法用于生成在远程服务器上创建一个新节点的 JSON 数据。actionId 表示同步操作类型,可以根据不同的同步操作类型来生成对应的 JSON 数据。 +getUpdateAction(int actionId):该方法用于生成在远程服务器上更新一个节点的 JSON 数据,与 getCreateAction 方法类似,actionId 表示同步操作类型。 + +setContentByRemoteJSON(JSONObject js):该方法用于从远程服务器返回的 JSON 数据中设置节点对象的属性值。 + +setContentByLocalJSON(JSONObject js):该方法用于从本地数据库中读取的 JSON 数据中设置节点对象的属性值。 + +getLocalJSONFromContent():该方法将节点对象转换为本地数据库中的 JSON 形式。 + +getSyncAction(Cursor c):该方法返回表示节点同步操作的常量。 + +这些抽象方法是用于描述哪些数据需要被从远程服务器或本地数据库中读取或写入,并且确定在特定同步操作期间执行的操作类型。这使得 Node 的子类可以根据具体情况对这些方法进行自定义实现,以适应不同场景的需求。*/ public void setGid(String gid) { this.mGid = gid; } - +/*这是 Node 类的 setGid 方法,用于设置节点的唯一标识符 gid。 +该方法接收一个 String 类型的参数 gid,表示要为节点设置的全局唯一标识符。 +在执行该方法时,将会将传入的 gid 参数赋值给 mGid 字段,以便在后续的操作中使用该值。 +这个方法可以被其子类调用来设置自己的 gid 值。 + */ public void setName(String name) { this.mName = name; } - +/*这是 Node 类的一个方法,用于设置节点的名称 mName 的值。 +它接受一个字符串类型的参数 name,并将它赋值给 mName 字段。 +this 表示当前对象实例。 + */ public void setLastModified(long lastModified) { this.mLastModified = lastModified; } - +/*setLastModified具有一个long类型的参数lastModified,表示将该对象的最后修改时间设置为给定值。 +在方法体内,关键字this表示当前对象的引用,即在调用该方法的对象。 +将参数lastModified的值分配给该对象的私有成员变量mLastModified,以便以后可以通过getter方法检索该值。 + */ public void setDeleted(boolean deleted) { this.mDeleted = deleted; } +/*这是一个Java类中的公共方法,名称为setDeleted,它具有一个boolean类型的参数deleted,表示将该对象的删除状态设置为给定的值。 +在方法体内,关键字this表示当前对象的引用,即在调用该方法的对象。 +将参数deleted的值分配给该对象的私有成员变量mDeleted,以便以后可以通过getter方法检索该值。 +如果参数deleted的值为true,则表示该对象被删除;如果参数deleted的值为false,则表示该对象未被删除。 + */ public String getGid() { return this.mGid; } @@ -89,13 +154,30 @@ public abstract class Node { public String getName() { return this.mName; } +/*这是一个Java类中的公共方法,名称分别为getGid和getName,它们都不具有任何参数,并返回该对象的私有成员变量mGid和mName的值,分别表示该对象的ID和名称。 +在方法体内,关键字this表示当前对象的引用,即在调用该方法的对象。 +这些方法通常用于获取对象的状态,而不是修改状态。 +例如,在代码中调用getGid方法将返回该对象的ID,以便在其他操作中使用该ID。 +同样,调用getName方法将返回该对象的名称。 + */ public long getLastModified() { return this.mLastModified; } +/*这是一个Java类中的公共方法,名称为getLastModified,它不具有任何参数,并返回该对象的私有成员变量mLastModified的值,表示该对象的最后修改时间。 +在方法体内,关键字this表示当前对象的引用,即在调用该方法的对象。 +这个方法通常用于获取对象的状态,以便在其他操作中使用该状态。 +例如,在代码中调用getLastModified方法将返回该对象的最后修改时间,以便在其他操作中使用该时间戳。 + */ public boolean getDeleted() { return this.mDeleted; } +/*这是一个Java类中的公共方法,名称为getDeleted,它不具有任何参数,并返回该对象的私有成员变量mDeleted的值,表示该对象是否被删除。 +在方法体内,关键字this表示当前对象的引用,即在调用该方法的对象。 +这个方法通常用于获取对象的状态,以便在其他操作中使用该状态。 +例如,在代码中调用getDeleted方法将返回一个boolean类型的值,表示该对象是否被删除。 +如果该值为true,则表示该对象已被删除;如果该值为false,则表示该对象未被删除。 + */ } diff --git a/app/src/main/java/net/micode/notes/gtask/data/SqlData.java b/app/src/main/java/net/micode/notes/gtask/data/SqlData.java index d3ec3be..e6a6be8 100644 --- a/app/src/main/java/net/micode/notes/gtask/data/SqlData.java +++ b/app/src/main/java/net/micode/notes/gtask/data/SqlData.java @@ -44,7 +44,15 @@ public class SqlData { DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1, DataColumns.DATA3 }; +/*这是一个Java类,名称为SqlData,其中定义了一些静态变量和常量,用于在类内和类外引用。 +第一行定义了一个名为TAG的静态常量字符串,用于在日志中标识该类。这个字符串的值是SqlData类的简单名称。 + +第二行定义了一个名为INVALID_ID的私有静态常量整数,用于表示无效的ID。该值被设置为-99999。 + +第三行定义了一个名为PROJECTION_DATA的公共静态常量字符串数组,用于定义一个查询所需返回的列。这些列包括DataColumns类中定义的ID、MIME_TYPE、CONTENT、DATA1和DATA3。 + +这些变量和常量都被声明为静态的,这意味着它们属于类本身,而不是类的实例。因此,它们可以在类的所有实例之间共享和访问。这些变量和常量的使用可以提高代码的可读性和可维护性,并避免在代码中多次重复相同的值。*/ public static final int DATA_ID_COLUMN = 0; public static final int DATA_MIME_TYPE_COLUMN = 1; @@ -70,66 +78,96 @@ public class SqlData { private String mDataContentData3; private ContentValues mDiffDataValues; +/*这是一个Java类,名称为SqlData,其中定义了一些成员变量和常量,用于在类内存储和操作数据。 + +第一行定义了一个名为DATA_ID_COLUMN的公共静态常量整数,用于表示列索引中的数据ID列。 + +第二行定义了一个名为DATA_MIME_TYPE_COLUMN的公共静态常量整数,用于表示列索引中的MIME类型列。 +第三行定义了一个名为DATA_CONTENT_COLUMN的公共静态常量整数,用于表示列索引中的内容列。 + +第四行定义了一个名为DATA_CONTENT_DATA_1_COLUMN的公共静态常量整数,用于表示列索引中的DATA1列。 + +第五行定义了一个名为DATA_CONTENT_DATA_3_COLUMN的公共静态常量整数,用于表示列索引中的DATA3列。 + +接下来的几行定义了该类的一些成员变量,包括ContentResolver类型的mContentResolver、boolean类型的mIsCreate、long类型的mDataId、String类型的mDataMimeType、String类型的mDataContent、long类型的mDataContentData1、String类型的mDataContentData3和ContentValues类型的mDiffDataValues。这些变量表示了该类的不同数据属性。 + +其中,ContentValues是一个键值对的集合,用于在Android应用中存储和操作数据。在该类中,mDiffDataValues被用于存储该对象的数据属性的差异,即该对象已更改但尚未提交到数据库中的值。*/ + // 构造函数用于初始化一个SqlData对象的实例 public SqlData(Context context) { - mContentResolver = context.getContentResolver(); - mIsCreate = true; - mDataId = INVALID_ID; - mDataMimeType = DataConstants.NOTE; - mDataContent = ""; - mDataContentData1 = 0; - mDataContentData3 = ""; - mDiffDataValues = new ContentValues(); + mContentResolver = context.getContentResolver();// 获取ContentResolver对象,用于访问ContentProvider中的数据 + mIsCreate = true;// 初始化数据的创建状态 + mDataId = INVALID_ID; // 初始化数据的ID值 + mDataMimeType = DataConstants.NOTE;// 初始化数据的MIME类型为NOTE + mDataContent = ""; // 初始化数据的内容为空字符串 + mDataContentData1 = 0; // 初始化数据的数据内容Data1为0 + mDataContentData3 = "";// 初始化数据的数据内容Data3为空字符串 + mDiffDataValues = new ContentValues();// 初始化差异数据的ContentValues对象,用于保存数据的不同之处 } + // 定义SqlData类,该类用于处理数据库中的数据 public SqlData(Context context, Cursor c) { + // 获取ContentResolver对象 mContentResolver = context.getContentResolver(); + // 设置初始状态为非创建状态 mIsCreate = false; + // 从Cursor对象中读取数据,并将数据加载到 loadFromCursor(c); + // 创建一个新的ContentValues对象,用于存储数据的差异 mDiffDataValues = new ContentValues(); } - +/*该构造函数主要是用于初始化SqlData对象,并且在初始化过程中从Cursor对象中读取数据,同时创建一个新的ContentValues对象,以备后续存储数据的差异。*/ +/*定义了一个私有方法loadFromCursor,该方法接收一个Cursor对象作为参数,并且在该方法中从Cursor对象中读取数据,将这些数据加载到SqlData对象中。*/ +// 从Cursor对象中读取数据,并将数据加载到SqlData对象中 private void loadFromCursor(Cursor c) { + // 从Cursor对象中读取数据id mDataId = c.getLong(DATA_ID_COLUMN); + // 从Cursor对象中读取数据类型 mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN); + // 从Cursor对象中读取数据内容 mDataContent = c.getString(DATA_CONTENT_COLUMN); + // 从Cursor对象中读取数据内容的第一个数据项 mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN); + // 从Cursor对象中读取数据内容的第三个数据项 mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN); } - - public void setContent(JSONObject js) throws JSONException { - long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID; +/*该方法主要是用于从Cursor对象中读取数据,并将这些数据加载到SqlData对象的相关成员变量中。其中,数据的读取顺序和类型需要与Cursor对象中的列名一一对应。*/ + public void setContent(JSONObject js) throws JSONException {// 设置SqlData对象的内容 + long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID;// 从JSONObject对象中获取数据id if (mIsCreate || mDataId != dataId) { mDiffDataValues.put(DataColumns.ID, dataId); } - mDataId = dataId; + mDataId = dataId; // 如果当前SqlData对象是创建状态,或者数据id与当前对象的数据id不同,将数据id加入到差异数据值对象中 +//setContent方法的主要部分,用于设置SqlData对象的各个成员变量值,并且在设置过程中检查差异数据。 String dataMimeType = js.has(DataColumns.MIME_TYPE) ? js.getString(DataColumns.MIME_TYPE) : DataConstants.NOTE; if (mIsCreate || !mDataMimeType.equals(dataMimeType)) { mDiffDataValues.put(DataColumns.MIME_TYPE, dataMimeType); } mDataMimeType = dataMimeType; - + // 从JSONObject对象中获取数据类型,并将其设置为SqlData对象的数据类型 String dataContent = js.has(DataColumns.CONTENT) ? js.getString(DataColumns.CONTENT) : ""; if (mIsCreate || !mDataContent.equals(dataContent)) { mDiffDataValues.put(DataColumns.CONTENT, dataContent); } mDataContent = dataContent; - + // 从JSONObject对象中获取数据内容的第一个数据项,并将其设置为SqlData对象的数据内容的第一个数据项 long dataContentData1 = js.has(DataColumns.DATA1) ? js.getLong(DataColumns.DATA1) : 0; if (mIsCreate || mDataContentData1 != dataContentData1) { mDiffDataValues.put(DataColumns.DATA1, dataContentData1); } mDataContentData1 = dataContentData1; - + // 从JSONObject对象中获取数据内容的第三个数据项,并将其设置为SqlData对象的数据内容的第三个数据项 String dataContentData3 = js.has(DataColumns.DATA3) ? js.getString(DataColumns.DATA3) : ""; if (mIsCreate || !mDataContentData3.equals(dataContentData3)) { mDiffDataValues.put(DataColumns.DATA3, dataContentData3); } mDataContentData3 = dataContentData3; } - +/*该代码段主要是根据JSONObject对象中的数据,设置SqlData对象的相应成员变量,并且在设置过程中检查差异数据。 + 其中,如果当前SqlData对象是创建状态,或者相应成员变量的值与JSONObject对象中的值不同,就将相应的数据加入到差异数据值对象中。 + 这些差异数据值将在后续的操作中被用于更新数据库中的数据。*/ public JSONObject getContent() throws JSONException { if (mIsCreate) { Log.e(TAG, "it seems that we haven't created this in database yet"); @@ -143,6 +181,11 @@ public class SqlData { js.put(DataColumns.DATA3, mDataContentData3); return js; } +/*这段代码定义了一个名为getContent()的方法,它返回一个JSONObject对象。 +该方法可能会抛出一个JSONException异常,因此在调用该方法时需要处理该异常。 +方法体内的第一条语句检查一个名为mIsCreate的 boolean 类型的成员变量是否为 true,如果是,则输出一个错误日志并返回 null。否则,方法会创建一个新的JSONObject对象,并向它添加一些键值对,这些键值对是由mDataId、mDataMimeType、mDataContent、mDataContentData1和mDataContentData3这些成员变量组成的。 +最后,该方法返回一个JSONObject对象,其中包含了这些成员变量的值。*/ + public void commit(long noteId, boolean validateVersion, long version) { @@ -182,8 +225,21 @@ public class SqlData { mDiffDataValues.clear(); mIsCreate = false; } - +/*这段代码定义了一个名为commit()的方法,用于将已经修改的数据保存到数据库中。 +方法接受三个参数:noteId为 long 类型,表示当前笔记的 ID; +validateVersion为 boolean 类型,表示是否需要验证版本; +version为 long 类型,表示当前笔记的版本。 +方法体内的第一条语句检查一个名为mIsCreate的boolean类型的成员变量是否为true,如果是,则表示当前是创建一个新的数据,需要将数据插入到数据库中。 +如果mDiffDataValues中包含 DataColumns.ID 这个键值对,表明该成员变量的值已经被赋值,需要将其移除,因为它是自增的主键,不应该由用户指定。 +接下来,将 DataColumns.NOTE_ID 对应的值设置为noteId,并将mDiffDataValues插入到Notes.CONTENT_DATA_URI中获取Uri对象,然后Uri对象中获取新的数据的 ID 并设置给成员变量mDataId。 +如果获取 ID 失败,则记录错误日志并抛出一个ActionFailureException异常。 +如果mIsCreate的值为 false,则表示需要更新数据库中的数据。 +如果mDiffDataValues中有数据,则调用mContentResolver.update()方法对数据库进行更新。 +如果validateVersion的值为 false,则直接更新数据,否则需要先验证版本。验证版本的过程是通过查询NoteColumns.VERSION等于version且NoteColumns.ID等于的noteId +无论是插入数据还是更新数据,都需要清空mDiffDataValues的内容并将mIsCreate设为 false,表示数据已经提交保存到数据库中。*/ public long getId() { return mDataId; - } + }//定义了一个名为getId()的方法,返回一个long类型的值,表示当前笔记的ID。 + //直接返回成员变量mDataId,因此不会引发任何异常。 } +6 \ No newline at end of file From e21db9d3d8180ba1ea557e17bc1bab2d9dc3a0fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=94=A1=E7=8E=89=E7=A5=A5?= <1120863985@qq.com> Date: Thu, 13 Apr 2023 16:48:17 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E8=94=A1=E7=8E=89=E7=A5=A5=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/compiler.xml | 2 +- .idea/deploymentTargetDropDown.xml | 4 +- .idea/gradle.xml | 2 +- .idea/misc.xml | 2 +- .idea/modules.xml | 10 ++--- .idea/modules/app/minote.app.androidTest.iml | 33 ---------------- .idea/modules/app/minote.app.iml | 34 ----------------- .idea/modules/app/minote.app.main.iml | 40 -------------------- .idea/modules/app/minote.app.unitTest.iml | 28 -------------- local.properties | 7 ++-- minote.iml | 12 ------ 11 files changed, 14 insertions(+), 160 deletions(-) delete mode 100644 .idea/modules/app/minote.app.androidTest.iml delete mode 100644 .idea/modules/app/minote.app.iml delete mode 100644 .idea/modules/app/minote.app.main.iml delete mode 100644 .idea/modules/app/minote.app.unitTest.iml delete mode 100644 minote.iml diff --git a/.idea/compiler.xml b/.idea/compiler.xml index b589d56..fb7f4a8 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml index a45d251..4babd7f 100644 --- a/.idea/deploymentTargetDropDown.xml +++ b/.idea/deploymentTargetDropDown.xml @@ -7,11 +7,11 @@ - + - + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index cbbe561..a0de2a1 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -7,7 +7,7 @@