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.
MIUInote/src/main/java/net/micode/notes/model/WorkingNote.java

436 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.

/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.model;
import android.appwidget.AppWidgetManager;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.text.TextUtils;
import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.CallNote;
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.data.Notes.TextNote;
import net.micode.notes.tool.ResourceParser.NoteBgResources;
/**
*
* @ProjectName: xiaomibianqian
* @Package: model
* @ClassName: WorkingNote
* @Description: 创建了一个正在工作的便签类,其中有大量的参数,包括参量类、布尔值类、区分类的变量
* 另外,封装了一系列的函数,其中有返回私有变量的,与数据库进行操作的,在不同情况下操作的(如新建的便签与修改的便签)
* 主要交互的包、类NoteEditActivitiesNotesfrom dataNote NoteListActivity SqlData
* 另外有创建一些接口比如NoteSettingChangedListener在NoteEditActivities中具体实现
*
* @Author: zhoushiyu_br
* @CreateDate: 2023.12.16
* @UpdateUser: 更新者:
* @UpdateDate: 2023.12.21
* @UpdateRemark: 更新说明:
* @Version: 这次更新主要是修改了之前代码批注不够规范的问题结合上课毛教员对于问题的指出对格式进行了优化——PickupRAIN
*/
public class WorkingNote {
// Note for the working note
private String mPassword;
private Note mNote;//这个在Note里面定义了Note类的基本类型
// Note Id
private long mNoteId;
// Note content
private String mContent;
// Note mode
private int mMode;
private long mAlertDate;
private long mModifiedDate;//最后的修改日期
private int mBgColorId;//定义的颜色的ID
private int mWidgetId;//定义了一个int类型用来定位到哪一个小组件被使用
private int mWidgetType;//定义了一个int类型用来区分使用了什么类型的小组件
private long mFolderId;//用来定位便签放在哪个文件夹
private Context mContext;
public boolean PRIVATE_MODE = false;
private static final String TAG = "WorkingNote"; //定义为静态变量,保证不能再被更改。防止数据出现异常
private boolean mIsDeleted; //定义一个布尔变量,用来保存是否要被删除。通过查看用法,发现在后面保存|修改的时候要进行判断。
private NoteSettingChangedListener mNoteSettingStatusListener;//定义了一个接口具体是在NoteEditActivities中实现实现对于便签是否修改的监听
/**
* 定义一个数组保存DataColumn数组当中的一些列变量。关于DataColumn的注解我写在了定义处。
* 之所以用一个字符串数组来调用DataColumn接口是为了“方便在进行数据库操作时可以一次性指定需要查询的列”
* 这个数组只有在loadNoteData这个函数的时候进行了调用。将数据加载到
* 12.22更新我学习了getContentResolver()的用法
* 实际上getContentResolver是用来查询数据库的这里定义的Projection是所有属性的集合。数据库查询按列进行
* 在按列查询时,在数据库访问到底,只需要在数组中继续访问即可。关于函数详解我会写在函数的定义处;
*/
public static final String[] DATA_PROJECTION = new String[] {
DataColumns.ID,//在Note里面定义一个接口类型
DataColumns.CONTENT,
DataColumns.MIME_TYPE,
DataColumns.DATA1,
DataColumns.DATA2,
DataColumns.DATA3,
DataColumns.DATA4,
};
//这里的用法基本同上方,不过这些接口最后使用在数据库中
public static final String[] NOTE_PROJECTION = new String[] {
NoteColumns.PARENT_ID,
NoteColumns.ALERTED_DATE,
NoteColumns.BG_COLOR_ID,
NoteColumns.WIDGET_ID,
NoteColumns.WIDGET_TYPE,
NoteColumns.MODIFIED_DATE
};
/**
* 定义了一系列的基础值。
*/
private static final int DATA_ID_COLUMN = 0;
private static final int DATA_CONTENT_COLUMN = 1;
private static final int DATA_MIME_TYPE_COLUMN = 2;
private static final int DATA_MODE_COLUMN = 3;
private static final int NOTE_PARENT_ID_COLUMN = 0;
private static final int NOTE_ALERTED_DATE_COLUMN = 1;
private static final int NOTE_BG_COLOR_ID_COLUMN = 2;
private static final int NOTE_WIDGET_ID_COLUMN = 3;
private static final int NOTE_WIDGET_TYPE_COLUMN = 4;
private static final int NOTE_MODIFIED_DATE_COLUMN = 5;
// New note construct
//初始化一个新的操作的Note
private WorkingNote(Context context, long folderId) {
mContext = context;
mAlertDate = 0;//这里为什么是0还存疑
mModifiedDate = System.currentTimeMillis();//获取系统时间,保存给最后修改时间
mFolderId = folderId;
mNote = new Note();
mNoteId = 0;
mIsDeleted = false;
mMode = 0;
mWidgetType = Notes.TYPE_WIDGET_INVALIDE;
}
//由于传入了noteId,所以是对一个已经存在的便签进行操作。
//由于一些基本的已经定义,所以传入的变量很少。
// Existing note construct
private WorkingNote(Context context, long noteId, long folderId) {
mContext = context;
mNoteId = noteId;
mFolderId = folderId;
mIsDeleted = false;
mNote = new Note();
loadNote();
}
/**
* @author: zhoushiyu_PickupRAIN
* @methodsName: loadNote
* @description: 创建游标对数据库进行操作。首先从传入的URI中找到数据库地址对元素数组进行逐列筛选。
* @param: 虽然没传入,,但是说明一下
* ->Notes.CONTENT_NOTE_URI:数据库的地址根据URI找到相应数据库
* ->NOTE_PROJECTION :属性列表,包含了所有的表头
* ->这里就能很容易理解为什么NOTE_PROJECTION为什么只在这里调用也没有初始化。
* @return: String
* @throws: Nopes
*
*/
private void loadNote() {
//定义一个cursor游标用来操作数据。这里传入了很多量如URI、Id、和来自Projection的一系列。
Cursor cursor = mContext.getContentResolver().query(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null,
null, null);
//设置一个cursor按行提取各种信息保存到对应的变量中
if (cursor != null) {
if (cursor.moveToFirst()) {
mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN);
mBgColorId = cursor.getInt(NOTE_BG_COLOR_ID_COLUMN);
mWidgetId = cursor.getInt(NOTE_WIDGET_ID_COLUMN);
mWidgetType = cursor.getInt(NOTE_WIDGET_TYPE_COLUMN);
mAlertDate = cursor.getLong(NOTE_ALERTED_DATE_COLUMN);
mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN);
}
cursor.close();
} else {
Log.e(TAG, "No note with id:" + mNoteId);
throw new IllegalArgumentException("Unable to find note with id " + mNoteId);
}
loadNoteData();
}
//基本同上一个函数。值得注意的是这里对数据进行了筛选通过selection,还对MIME进行了判断后加载
private void loadNoteData() {
Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION,
DataColumns.NOTE_ID + "=?", new String[] {
String.valueOf(mNoteId)
}, null);
if (cursor != null) {
if (cursor.moveToFirst()) {
do {
String type = cursor.getString(DATA_MIME_TYPE_COLUMN);
if (DataConstants.NOTE.equals(type)) {
mContent = cursor.getString(DATA_CONTENT_COLUMN);
mMode = cursor.getInt(DATA_MODE_COLUMN);
mNote.setTextDataId(cursor.getLong(DATA_ID_COLUMN));
} else if (DataConstants.CALL_NOTE.equals(type)) {
mNote.setCallDataId(cursor.getLong(DATA_ID_COLUMN));
} else {
Log.d(TAG, "Wrong note type with type:" + type);
}
} while (cursor.moveToNext());
}
cursor.close();
} else {
Log.e(TAG, "No data with id:" + mNoteId);
throw new IllegalArgumentException("Unable to find note's data with id " + mNoteId);
}
}
//简单的初始化函数,一会看一下用法
public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId,
int widgetType, int defaultBgColorId) {
WorkingNote note = new WorkingNote(context, folderId);
note.setBgColorId(defaultBgColorId);
note.setWidgetId(widgetId);
note.setWidgetType(widgetType);
return note;
}
public static WorkingNote load(Context context, long id) {
return new WorkingNote(context, id, 0);
}
//这里涉及了多线程的操作。
public synchronized boolean saveNote() {
if (isWorthSaving()) {
if (!existInDatabase()) {
if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) {
Log.e(TAG, "Create new note fail with id:" + mNoteId);
return false;
}
}
//由于没有这个便签所以报错并返回false
mNote.syncNote(mContext, mNoteId);//这一行是同步信息的操作
/**
* Update widget content if there exist any widget of this note
*/
//对小组件的各种属性进行判断,来确定是否有组件,进行保存
if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID
&& mWidgetType != Notes.TYPE_WIDGET_INVALIDE
&& mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onWidgetChanged();
}
return true;
} else {
return false;
}
}
/**
* 以下定义、封装了一系列的实用函数,用于一些私有量的设置与判断
*
*/
public boolean existInDatabase() {
return mNoteId > 0;
}
private boolean isWorthSaving() {
if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent))
|| (existInDatabase() && !mNote.isLocalModified())) {
return false;
} else {
return true;
}
}
//这个变量设置是用来记录状态设定是否有发生过更改。
public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) {
mNoteSettingStatusListener = l;
}
public void setAlertDate(long date, boolean set) {
if (date != mAlertDate) {
mAlertDate = date;
mNote.setNoteValue(NoteColumns.ALERTED_DATE, String.valueOf(mAlertDate));
}
if (mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onClockAlertChanged(date, set);
}
}
public void markDeleted(boolean mark) {
mIsDeleted = mark;
if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID
&& mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onWidgetChanged();
}
}
public void setBgColorId(int id) {
if (id != mBgColorId) {
mBgColorId = id;
if (mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onBackgroundColorChanged();
}
mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id));
}
}
//在EditActivities中使用用来设定在list时的状态
public void setCheckListMode(int mode) {
if (mMode != mode) {
if (mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onCheckListModeChanged(mMode, mode);
}
mMode = mode;
mNote.setTextData(TextNote.MODE, String.valueOf(mMode));
}
}
public void setWidgetType(int type) {
if (type != mWidgetType) {
mWidgetType = type;
mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType));
}
}
public void setWidgetId(int id) {
if (id != mWidgetId) {
mWidgetId = id;
mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId));
}
}
public void setWorkingText(String text) {
if (!TextUtils.equals(mContent, text)) {
mContent = text;
mNote.setTextData(DataColumns.CONTENT, mContent);
}
}
/**
* 从这里一直向上大概的都是一些设置状态的函数。
* 原因是设置的私有量,保证数据的可靠性
* 具体使用在onOptionsItemSelected NoteEditActivities类中调用
*/
//这里的callNote我没有搞懂
public void convertToCallNote(String phoneNumber, long callDate) {
mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate));
mNote.setCallData(CallNote.PHONE_NUMBER, phoneNumber);
mNote.setNoteValue(NoteColumns.PARENT_ID, String.valueOf(Notes.ID_CALL_RECORD_FOLDER));
}
public void setPassword(String password){
// mPassword=password;
mNote.setNoteValue(NoteColumns.PASSWORD,password);
}
public boolean hasClockAlert() {
return (mAlertDate > 0 ? true : false);
}
public String getContent() {
return mContent;
}
public long getAlertDate() {
return mAlertDate;
}
public long getModifiedDate() {
return mModifiedDate;
}
public int getBgColorResId() {
return NoteBgResources.getNoteBgResource(mBgColorId);
}
public int getBgColorId() {
return mBgColorId;
}
public int getTitleBgResId() {
return NoteBgResources.getNoteTitleBgResource(mBgColorId);
}
public int getCheckListMode() {
return mMode;
}
public long getNoteId() {
return mNoteId;
}
public long getFolderId() {
return mFolderId;
}
public int getWidgetId() {
return mWidgetId;
}
public int getWidgetType() {
return mWidgetType;
}
public String getPassword() { return mPassword; }
//声明了一个接口具体都在EditActivies中进行实现。主要是一个监听listener来设置各个量的改变
public interface NoteSettingChangedListener {
/**
* Called when the background color of current note has just changed
*/
void onBackgroundColorChanged();
/**
* Called when user set clock
*/
void onClockAlertChanged(long date, boolean set);
/**
* Call when user create note from widget
*/
void onWidgetChanged();
/**
* Call when switch between check list mode and normal mode
* @param oldMode is previous mode before change
* @param newMode is new mode
*/
void onCheckListModeChanged(int oldMode, int newMode);
}
}