Compare commits
No commits in common. 'master' and 'cyh_branch' have entirely different histories.
master
...
cyh_branch
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 92 KiB |
@ -1,253 +0,0 @@
|
||||
/*
|
||||
* 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.content.ContentProviderOperation;
|
||||
import android.content.ContentProviderResult;
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.OperationApplicationException;
|
||||
import android.net.Uri;
|
||||
import android.os.RemoteException;
|
||||
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.NoteColumns;
|
||||
import net.micode.notes.data.Notes.TextNote;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
||||
public class Note {
|
||||
private ContentValues mNoteDiffValues;
|
||||
private NoteData mNoteData;
|
||||
private static final String TAG = "Note";
|
||||
/**
|
||||
* Create a new note id for adding a new note to databases
|
||||
*/
|
||||
public static synchronized long getNewNoteId(Context context, long folderId) {
|
||||
// Create a new note in the database
|
||||
ContentValues values = new ContentValues();
|
||||
long createdTime = System.currentTimeMillis();
|
||||
values.put(NoteColumns.CREATED_DATE, createdTime);
|
||||
values.put(NoteColumns.MODIFIED_DATE, createdTime);
|
||||
values.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
|
||||
values.put(NoteColumns.LOCAL_MODIFIED, 1);
|
||||
values.put(NoteColumns.PARENT_ID, folderId);
|
||||
Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);
|
||||
|
||||
long noteId = 0;
|
||||
try {
|
||||
noteId = Long.valueOf(uri.getPathSegments().get(1));
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e(TAG, "Get note id error :" + e.toString());
|
||||
noteId = 0;
|
||||
}
|
||||
if (noteId == -1) {
|
||||
throw new IllegalStateException("Wrong note id:" + noteId);
|
||||
}
|
||||
return noteId;
|
||||
}
|
||||
|
||||
public Note() {
|
||||
mNoteDiffValues = new ContentValues();
|
||||
mNoteData = new NoteData();
|
||||
}
|
||||
|
||||
public void setNoteValue(String key, String value) {
|
||||
mNoteDiffValues.put(key, value);
|
||||
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
|
||||
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public void setTextData(String key, String value) {
|
||||
mNoteData.setTextData(key, value);
|
||||
}
|
||||
|
||||
public void setTextDataId(long id) {
|
||||
mNoteData.setTextDataId(id);
|
||||
}
|
||||
|
||||
public long getTextDataId() {
|
||||
return mNoteData.mTextDataId;
|
||||
}
|
||||
|
||||
public void setCallDataId(long id) {
|
||||
mNoteData.setCallDataId(id);
|
||||
}
|
||||
|
||||
public void setCallData(String key, String value) {
|
||||
mNoteData.setCallData(key, value);
|
||||
}
|
||||
|
||||
public boolean isLocalModified() {
|
||||
return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
|
||||
}
|
||||
|
||||
public boolean syncNote(Context context, long noteId) {
|
||||
if (noteId <= 0) {
|
||||
throw new IllegalArgumentException("Wrong note id:" + noteId);
|
||||
}
|
||||
|
||||
if (!isLocalModified()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* In theory, once data changed, the note should be updated on {@link NoteColumns#LOCAL_MODIFIED} and
|
||||
* {@link NoteColumns#MODIFIED_DATE}. For data safety, though update note fails, we also update the
|
||||
* note data info
|
||||
*/
|
||||
if (context.getContentResolver().update(
|
||||
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null,
|
||||
null) == 0) {
|
||||
Log.e(TAG, "Update note error, should not happen");
|
||||
// Do not return, fall through
|
||||
}
|
||||
mNoteDiffValues.clear();
|
||||
|
||||
if (mNoteData.isLocalModified()
|
||||
&& (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private class NoteData {
|
||||
private long mTextDataId;
|
||||
|
||||
private ContentValues mTextDataValues;
|
||||
|
||||
private long mCallDataId;
|
||||
|
||||
private ContentValues mCallDataValues;
|
||||
|
||||
private static final String TAG = "NoteData";
|
||||
|
||||
public NoteData() {
|
||||
mTextDataValues = new ContentValues();
|
||||
mCallDataValues = new ContentValues();
|
||||
mTextDataId = 0;
|
||||
mCallDataId = 0;
|
||||
}
|
||||
|
||||
boolean isLocalModified() {
|
||||
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
|
||||
}
|
||||
|
||||
void setTextDataId(long id) {
|
||||
if(id <= 0) {
|
||||
throw new IllegalArgumentException("Text data id should larger than 0");
|
||||
}
|
||||
mTextDataId = id;
|
||||
}
|
||||
|
||||
void setCallDataId(long id) {
|
||||
if (id <= 0) {
|
||||
throw new IllegalArgumentException("Call data id should larger than 0");
|
||||
}
|
||||
mCallDataId = id;
|
||||
}
|
||||
|
||||
void setCallData(String key, String value) {
|
||||
mCallDataValues.put(key, value);
|
||||
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
|
||||
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
void setTextData(String key, String value) {
|
||||
mTextDataValues.put(key, value);
|
||||
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
|
||||
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
|
||||
}
|
||||
|
||||
Uri pushIntoContentResolver(Context context, long noteId) {
|
||||
/**
|
||||
* Check for safety
|
||||
*/
|
||||
if (noteId <= 0) {
|
||||
throw new IllegalArgumentException("Wrong note id:" + noteId);
|
||||
}
|
||||
|
||||
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
|
||||
ContentProviderOperation.Builder builder = null;
|
||||
|
||||
if(mTextDataValues.size() > 0) {
|
||||
mTextDataValues.put(DataColumns.NOTE_ID, noteId);
|
||||
if (mTextDataId == 0) {
|
||||
mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE);
|
||||
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
|
||||
mTextDataValues);
|
||||
try {
|
||||
setTextDataId(Long.valueOf(uri.getPathSegments().get(1)));
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e(TAG, "Insert new text data fail with noteId" + noteId);
|
||||
mTextDataValues.clear();
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
|
||||
Notes.CONTENT_DATA_URI, mTextDataId));
|
||||
builder.withValues(mTextDataValues);
|
||||
operationList.add(builder.build());
|
||||
}
|
||||
mTextDataValues.clear();
|
||||
}
|
||||
|
||||
if(mCallDataValues.size() > 0) {
|
||||
mCallDataValues.put(DataColumns.NOTE_ID, noteId);
|
||||
if (mCallDataId == 0) {
|
||||
mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE);
|
||||
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
|
||||
mCallDataValues);
|
||||
try {
|
||||
setCallDataId(Long.valueOf(uri.getPathSegments().get(1)));
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e(TAG, "Insert new call data fail with noteId" + noteId);
|
||||
mCallDataValues.clear();
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
|
||||
Notes.CONTENT_DATA_URI, mCallDataId));
|
||||
builder.withValues(mCallDataValues);
|
||||
operationList.add(builder.build());
|
||||
}
|
||||
mCallDataValues.clear();
|
||||
}
|
||||
|
||||
if (operationList.size() > 0) {
|
||||
try {
|
||||
ContentProviderResult[] results = context.getContentResolver().applyBatch(
|
||||
Notes.AUTHORITY, operationList);
|
||||
return (results == null || results.length == 0 || results[0] == null) ? null
|
||||
: ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
|
||||
return null;
|
||||
} catch (OperationApplicationException e) {
|
||||
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,368 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
|
||||
public class WorkingNote {
|
||||
// Note for the working note
|
||||
private Note mNote;
|
||||
// Note Id
|
||||
private long mNoteId;
|
||||
// Note content
|
||||
private String mContent;
|
||||
// Note mode
|
||||
private int mMode;
|
||||
|
||||
private long mAlertDate;
|
||||
|
||||
private long mModifiedDate;
|
||||
|
||||
private int mBgColorId;
|
||||
|
||||
private int mWidgetId;
|
||||
|
||||
private int mWidgetType;
|
||||
|
||||
private long mFolderId;
|
||||
|
||||
private Context mContext;
|
||||
|
||||
private static final String TAG = "WorkingNote";
|
||||
|
||||
private boolean mIsDeleted;
|
||||
|
||||
private NoteSettingChangedListener mNoteSettingStatusListener;
|
||||
|
||||
public static final String[] DATA_PROJECTION = new String[] {
|
||||
DataColumns.ID,
|
||||
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
|
||||
private WorkingNote(Context context, long folderId) {
|
||||
mContext = context;
|
||||
mAlertDate = 0;
|
||||
mModifiedDate = System.currentTimeMillis();
|
||||
mFolderId = folderId;
|
||||
mNote = new Note();
|
||||
mNoteId = 0;
|
||||
mIsDeleted = false;
|
||||
mMode = 0;
|
||||
mWidgetType = Notes.TYPE_WIDGET_INVALIDE;
|
||||
}
|
||||
|
||||
// Existing note construct
|
||||
private WorkingNote(Context context, long noteId, long folderId) {
|
||||
mContext = context;
|
||||
mNoteId = noteId;
|
||||
mFolderId = folderId;
|
||||
mIsDeleted = false;
|
||||
mNote = new Note();
|
||||
loadNote();
|
||||
}
|
||||
|
||||
private void loadNote() {
|
||||
Cursor cursor = mContext.getContentResolver().query(
|
||||
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null,
|
||||
null, null);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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 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 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);
|
||||
}
|
||||
}
|
||||
@ -1,79 +0,0 @@
|
||||
// Apache许可证协议
|
||||
|
||||
package net.micode.notes.ui;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.text.format.DateFormat;
|
||||
import android.text.format.DateUtils;
|
||||
|
||||
import net.micode.notes.R;
|
||||
import net.micode.notes.ui.DateTimePicker.OnDateTimeChangedListener;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
public class DateTimePickerDialog extends AlertDialog implements OnClickListener {
|
||||
|
||||
private Calendar mDate = Calendar.getInstance();
|
||||
private boolean mIs24HourView;
|
||||
private OnDateTimeSetListener mOnDateTimeSetListener;
|
||||
private DateTimePicker mDateTimePicker;
|
||||
|
||||
public interface OnDateTimeSetListener {
|
||||
void OnDateTimeSet(AlertDialog dialog, long date);
|
||||
}
|
||||
// 实现了一个 OnDateTimeSetListener 接口,该接口定义了一个 OnDateTimeSet() 方法,用于在用户选择日期时间后通知调用者。
|
||||
|
||||
public DateTimePickerDialog(Context context, long date) {
|
||||
super(context);
|
||||
mDateTimePicker = new DateTimePicker(context);
|
||||
setView(mDateTimePicker);
|
||||
mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() {
|
||||
public void onDateTimeChanged(DateTimePicker view, int year, int month,
|
||||
int dayOfMonth, int hourOfDay, int minute) {
|
||||
mDate.set(Calendar.YEAR, year);
|
||||
mDate.set(Calendar.MONTH, month);
|
||||
mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
|
||||
mDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
|
||||
mDate.set(Calendar.MINUTE, minute);
|
||||
updateTitle(mDate.getTimeInMillis());
|
||||
}
|
||||
});
|
||||
// 包含了一个 DateTimePicker 控件,用于让用户选择日期和时间。通过 mDateTimePicker.setOnDateTimeChangedListener() 方法,当用户选择日期和时间时,将更新 mDate 的值,并使用 updateTitle() 方法更新对话框的标题。
|
||||
mDate.setTimeInMillis(date);
|
||||
mDate.set(Calendar.SECOND, 0);
|
||||
mDateTimePicker.setCurrentDate(mDate.getTimeInMillis());
|
||||
setButton(context.getString(R.string.datetime_dialog_ok), this);
|
||||
setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null);
|
||||
set24HourView(DateFormat.is24HourFormat(this.getContext()));
|
||||
updateTitle(mDate.getTimeInMillis());
|
||||
}
|
||||
|
||||
public void set24HourView(boolean is24HourView) {
|
||||
mIs24HourView = is24HourView;
|
||||
}
|
||||
//set24HourView() 方法,用于设置日期时间选择器是否为 24 小时格式。默认情况下,该值将由系统的设置决定。
|
||||
|
||||
public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) {
|
||||
mOnDateTimeSetListener = callBack;
|
||||
}
|
||||
|
||||
private void updateTitle(long date) {
|
||||
int flag =
|
||||
DateUtils.FORMAT_SHOW_YEAR |
|
||||
DateUtils.FORMAT_SHOW_DATE |
|
||||
DateUtils.FORMAT_SHOW_TIME;
|
||||
flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_24HOUR;
|
||||
setTitle(DateUtils.formatDateTime(this.getContext(), date, flag));
|
||||
}
|
||||
|
||||
public void onClick(DialogInterface arg0, int arg1) {
|
||||
if (mOnDateTimeSetListener != null) {
|
||||
mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis());
|
||||
}
|
||||
}
|
||||
// 重写了 onClick() 方法,以便在用户点击“确定”按钮后,将用户选择的日期时间作为参数传递到 OnDateTimeSet() 方法中,从而通知调用者。
|
||||
|
||||
}
|
||||
@ -1,200 +0,0 @@
|
||||
// Apache许可证协议
|
||||
|
||||
package net.micode.notes.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.text.Layout;
|
||||
import android.text.Selection;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.URLSpan;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MenuItem.OnMenuItemClickListener;
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.EditText;
|
||||
|
||||
import net.micode.notes.R;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class NoteEditText extends EditText {
|
||||
private static final String TAG = "NoteEditText";
|
||||
private int mIndex;
|
||||
private int mSelectionStartBeforeDelete;
|
||||
|
||||
private static final String SCHEME_TEL = "tel:" ;
|
||||
private static final String SCHEME_HTTP = "http:" ;
|
||||
private static final String SCHEME_EMAIL = "mailto:" ;
|
||||
|
||||
private static final Map<String, Integer> sSchemaActionResMap = new HashMap<String, Integer>();
|
||||
static {
|
||||
sSchemaActionResMap.put(SCHEME_TEL, R.string.note_link_tel);
|
||||
sSchemaActionResMap.put(SCHEME_HTTP, R.string.note_link_web);
|
||||
sSchemaActionResMap.put(SCHEME_EMAIL, R.string.note_link_email);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call by the {@link NoteEditActivity} to delete or add edit text
|
||||
*/
|
||||
public interface OnTextViewChangeListener {
|
||||
/**
|
||||
* Delete current edit text when {@link KeyEvent#KEYCODE_DEL} happens
|
||||
* and the text is null
|
||||
*/
|
||||
void onEditTextDelete(int index, String text);
|
||||
|
||||
/**
|
||||
* Add edit text after current edit text when {@link KeyEvent#KEYCODE_ENTER}
|
||||
* happen
|
||||
*/
|
||||
void onEditTextEnter(int index, String text);
|
||||
|
||||
/**
|
||||
* Hide or show item option when text change
|
||||
*/
|
||||
void onTextChange(int index, boolean hasText);
|
||||
}
|
||||
|
||||
private OnTextViewChangeListener mOnTextViewChangeListener;
|
||||
|
||||
public NoteEditText(Context context) {
|
||||
super(context, null);
|
||||
mIndex = 0;
|
||||
}
|
||||
|
||||
public void setIndex(int index) {
|
||||
mIndex = index;
|
||||
}//用于设置控件在父容器中的位置索引
|
||||
|
||||
public void setOnTextViewChangeListener(OnTextViewChangeListener listener) {
|
||||
mOnTextViewChangeListener = listener;
|
||||
}//用于设置文本变化的监听器
|
||||
|
||||
public NoteEditText(Context context, AttributeSet attrs) {
|
||||
super(context, attrs, android.R.attr.editTextStyle);
|
||||
}
|
||||
|
||||
public NoteEditText(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
|
||||
int x = (int) event.getX();
|
||||
int y = (int) event.getY();
|
||||
x -= getTotalPaddingLeft();
|
||||
y -= getTotalPaddingTop();
|
||||
x += getScrollX();
|
||||
y += getScrollY();
|
||||
|
||||
Layout layout = getLayout();
|
||||
int line = layout.getLineForVertical(y);
|
||||
int off = layout.getOffsetForHorizontal(line, x);
|
||||
Selection.setSelection(getText(), off);
|
||||
break;
|
||||
}//实现了点击控件后,将光标移动到点击位置的功能
|
||||
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_ENTER:
|
||||
if (mOnTextViewChangeListener != null) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case KeyEvent.KEYCODE_DEL:
|
||||
mSelectionStartBeforeDelete = getSelectionStart();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||
switch(keyCode) {
|
||||
case KeyEvent.KEYCODE_DEL:
|
||||
if (mOnTextViewChangeListener != null) {
|
||||
if (0 == mSelectionStartBeforeDelete && mIndex != 0) {
|
||||
mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString());
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "OnTextViewChangeListener was not seted");
|
||||
}
|
||||
break;
|
||||
case KeyEvent.KEYCODE_ENTER:
|
||||
if (mOnTextViewChangeListener != null) {
|
||||
int selectionStart = getSelectionStart();
|
||||
String text = getText().subSequence(selectionStart, length()).toString();
|
||||
setText(getText().subSequence(0, selectionStart));
|
||||
mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, text);
|
||||
} else {
|
||||
Log.d(TAG, "OnTextViewChangeListener was not seted");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
// onKeyDown和onKeyUp方法实现了按下和松开键盘按键时的响应。
|
||||
|
||||
@Override
|
||||
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
|
||||
if (mOnTextViewChangeListener != null) {
|
||||
mOnTextViewChangeListener.onTextChange(mIndex, focused || !TextUtils.isEmpty(getText()));
|
||||
}
|
||||
super.onFocusChanged(focused, direction, previouslyFocusedRect);
|
||||
}//控件获得或失去焦点时触发,将焦点状态通知给监听器。
|
||||
|
||||
@Override
|
||||
protected void onCreateContextMenu(ContextMenu menu) {
|
||||
if (getText() instanceof Spanned) {
|
||||
int selStart = getSelectionStart();
|
||||
int selEnd = getSelectionEnd();
|
||||
|
||||
int min = Math.min(selStart, selEnd);
|
||||
int max = Math.max(selStart, selEnd);
|
||||
|
||||
final URLSpan[] urls = ((Spanned) getText()).getSpans(min, max, URLSpan.class);
|
||||
if (urls.length == 1) {
|
||||
int defaultResId = 0;
|
||||
for(String schema: sSchemaActionResMap.keySet()) {
|
||||
if(urls[0].getURL().indexOf(schema) >= 0) {
|
||||
defaultResId = sSchemaActionResMap.get(schema);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultResId == 0) {
|
||||
defaultResId = R.string.note_link_other;
|
||||
}
|
||||
|
||||
menu.add(0, 0, 0, defaultResId).setOnMenuItemClickListener(
|
||||
new OnMenuItemClickListener() {
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
// goto a new intent
|
||||
urls[0].onClick(NoteEditText.this);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
super.onCreateContextMenu(menu);
|
||||
}
|
||||
// 创建上下文菜单,当用户长按控件中的链接时,根据链接的协议类型创建不同的菜单项,点击菜单项后跳转到相应的链接。
|
||||
}
|
||||
@ -1,210 +0,0 @@
|
||||
// Apache许可证协议
|
||||
|
||||
package net.micode.notes.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import net.micode.notes.data.Contact;
|
||||
import net.micode.notes.data.Notes;
|
||||
import net.micode.notes.data.Notes.NoteColumns;
|
||||
import net.micode.notes.tool.DataUtils;
|
||||
|
||||
|
||||
public class NoteItemData {
|
||||
static final String [] PROJECTION = new String [] {
|
||||
NoteColumns.ID,
|
||||
NoteColumns.ALERTED_DATE,
|
||||
NoteColumns.BG_COLOR_ID,
|
||||
NoteColumns.CREATED_DATE,
|
||||
NoteColumns.HAS_ATTACHMENT,
|
||||
NoteColumns.MODIFIED_DATE,
|
||||
NoteColumns.NOTES_COUNT,
|
||||
NoteColumns.PARENT_ID,
|
||||
NoteColumns.SNIPPET,
|
||||
NoteColumns.TYPE,
|
||||
NoteColumns.WIDGET_ID,
|
||||
NoteColumns.WIDGET_TYPE,
|
||||
};
|
||||
|
||||
private static final int ID_COLUMN = 0;
|
||||
private static final int ALERTED_DATE_COLUMN = 1;
|
||||
private static final int BG_COLOR_ID_COLUMN = 2;
|
||||
private static final int CREATED_DATE_COLUMN = 3;
|
||||
private static final int HAS_ATTACHMENT_COLUMN = 4;
|
||||
private static final int MODIFIED_DATE_COLUMN = 5;
|
||||
private static final int NOTES_COUNT_COLUMN = 6;
|
||||
private static final int PARENT_ID_COLUMN = 7;
|
||||
private static final int SNIPPET_COLUMN = 8;
|
||||
private static final int TYPE_COLUMN = 9;
|
||||
private static final int WIDGET_ID_COLUMN = 10;
|
||||
private static final int WIDGET_TYPE_COLUMN = 11;
|
||||
|
||||
private long mId;
|
||||
private long mAlertDate;
|
||||
private int mBgColorId;
|
||||
private long mCreatedDate;
|
||||
private boolean mHasAttachment;
|
||||
private long mModifiedDate;
|
||||
private int mNotesCount;
|
||||
private long mParentId;
|
||||
private String mSnippet;
|
||||
private int mType;
|
||||
private int mWidgetId;
|
||||
private int mWidgetType;
|
||||
private String mName;
|
||||
private String mPhoneNumber;
|
||||
|
||||
private boolean mIsLastItem;
|
||||
private boolean mIsFirstItem;
|
||||
private boolean mIsOnlyOneItem;
|
||||
private boolean mIsOneNoteFollowingFolder;
|
||||
private boolean mIsMultiNotesFollowingFolder;
|
||||
|
||||
public NoteItemData(Context context, Cursor cursor) {
|
||||
mId = cursor.getLong(ID_COLUMN);
|
||||
mAlertDate = cursor.getLong(ALERTED_DATE_COLUMN);
|
||||
mBgColorId = cursor.getInt(BG_COLOR_ID_COLUMN);
|
||||
mCreatedDate = cursor.getLong(CREATED_DATE_COLUMN);
|
||||
mHasAttachment = cursor.getInt(HAS_ATTACHMENT_COLUMN) > 0;
|
||||
mModifiedDate = cursor.getLong(MODIFIED_DATE_COLUMN);
|
||||
mNotesCount = cursor.getInt(NOTES_COUNT_COLUMN);
|
||||
mParentId = cursor.getLong(PARENT_ID_COLUMN);
|
||||
mSnippet = cursor.getString(SNIPPET_COLUMN);
|
||||
mSnippet = mSnippet.replace(NoteEditActivity.TAG_CHECKED, "").replace(
|
||||
NoteEditActivity.TAG_UNCHECKED, "");
|
||||
mType = cursor.getInt(TYPE_COLUMN);
|
||||
mWidgetId = cursor.getInt(WIDGET_ID_COLUMN);
|
||||
mWidgetType = cursor.getInt(WIDGET_TYPE_COLUMN);
|
||||
|
||||
mPhoneNumber = "";
|
||||
if (mParentId == Notes.ID_CALL_RECORD_FOLDER) {
|
||||
mPhoneNumber = DataUtils.getCallNumberByNoteId(context.getContentResolver(), mId);
|
||||
if (!TextUtils.isEmpty(mPhoneNumber)) {
|
||||
mName = Contact.getContact(context, mPhoneNumber);
|
||||
if (mName == null) {
|
||||
mName = mPhoneNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mName == null) {
|
||||
mName = "";
|
||||
}
|
||||
checkPosition(cursor);
|
||||
}
|
||||
|
||||
private void checkPosition(Cursor cursor) {
|
||||
mIsLastItem = cursor.isLast();
|
||||
mIsFirstItem = cursor.isFirst();
|
||||
mIsOnlyOneItem = (cursor.getCount() == 1);
|
||||
mIsMultiNotesFollowingFolder = false;
|
||||
mIsOneNoteFollowingFolder = false;
|
||||
|
||||
if (mType == Notes.TYPE_NOTE && !mIsFirstItem) {
|
||||
int position = cursor.getPosition();
|
||||
if (cursor.moveToPrevious()) {
|
||||
if (cursor.getInt(TYPE_COLUMN) == Notes.TYPE_FOLDER
|
||||
|| cursor.getInt(TYPE_COLUMN) == Notes.TYPE_SYSTEM) {
|
||||
if (cursor.getCount() > (position + 1)) {
|
||||
mIsMultiNotesFollowingFolder = true;
|
||||
} else {
|
||||
mIsOneNoteFollowingFolder = true;
|
||||
}
|
||||
}
|
||||
if (!cursor.moveToNext()) {
|
||||
throw new IllegalStateException("cursor move to previous but can't move back");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isOneFollowingFolder() {
|
||||
return mIsOneNoteFollowingFolder;
|
||||
}
|
||||
|
||||
public boolean isMultiFollowingFolder() {
|
||||
return mIsMultiNotesFollowingFolder;
|
||||
}
|
||||
|
||||
public boolean isLast() {
|
||||
return mIsLastItem;
|
||||
}
|
||||
|
||||
public String getCallName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
public boolean isFirst() {
|
||||
return mIsFirstItem;
|
||||
}
|
||||
|
||||
public boolean isSingle() {
|
||||
return mIsOnlyOneItem;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public long getAlertDate() {
|
||||
return mAlertDate;
|
||||
}
|
||||
|
||||
public long getCreatedDate() {
|
||||
return mCreatedDate;
|
||||
}
|
||||
|
||||
public boolean hasAttachment() {
|
||||
return mHasAttachment;
|
||||
}
|
||||
|
||||
public long getModifiedDate() {
|
||||
return mModifiedDate;
|
||||
}
|
||||
|
||||
public int getBgColorId() {
|
||||
return mBgColorId;
|
||||
}
|
||||
|
||||
public long getParentId() {
|
||||
return mParentId;
|
||||
}
|
||||
|
||||
public int getNotesCount() {
|
||||
return mNotesCount;
|
||||
}
|
||||
|
||||
public long getFolderId () {
|
||||
return mParentId;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
public int getWidgetType() {
|
||||
return mWidgetType;
|
||||
}
|
||||
|
||||
public int getWidgetId() {
|
||||
return mWidgetId;
|
||||
}
|
||||
|
||||
public String getSnippet() {
|
||||
return mSnippet;
|
||||
}
|
||||
|
||||
public boolean hasAlert() {
|
||||
return (mAlertDate > 0);
|
||||
}
|
||||
|
||||
public boolean isCallRecord() {
|
||||
return (mParentId == Notes.ID_CALL_RECORD_FOLDER && !TextUtils.isEmpty(mPhoneNumber));
|
||||
}
|
||||
|
||||
public static int getNoteType(Cursor cursor) {
|
||||
return cursor.getInt(TYPE_COLUMN);
|
||||
}
|
||||
}
|
||||
@ -1,171 +0,0 @@
|
||||
// Apache许可证协议
|
||||
|
||||
package net.micode.notes.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CursorAdapter;
|
||||
|
||||
import net.micode.notes.data.Notes;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
||||
|
||||
public class NotesListAdapter extends CursorAdapter {
|
||||
private static final String TAG = "NotesListAdapter";
|
||||
private Context mContext;
|
||||
private HashMap<Integer, Boolean> mSelectedIndex;
|
||||
private int mNotesCount;
|
||||
private boolean mChoiceMode;
|
||||
|
||||
public static class AppWidgetAttribute {
|
||||
public int widgetId;
|
||||
public int widgetType;
|
||||
};
|
||||
|
||||
public NotesListAdapter(Context context) {
|
||||
super(context, null);
|
||||
mSelectedIndex = new HashMap<>();
|
||||
mContext = context;
|
||||
mNotesCount = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
return new NotesListItem(context);
|
||||
}//创建一个新的笔记列表项视图,即 NotesListItem。
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
if (view instanceof NotesListItem) {
|
||||
NoteItemData itemData = new NoteItemData(context, cursor);
|
||||
((NotesListItem) view).bind(context, itemData, mChoiceMode,
|
||||
isSelectedItem(cursor.getPosition()));
|
||||
}
|
||||
}//将笔记数据绑定到给定的笔记列表项视图中。
|
||||
|
||||
public void setCheckedItem(final int position, final boolean checked) {
|
||||
mSelectedIndex.put(position, checked);
|
||||
notifyDataSetChanged();
|
||||
}//设置给定位置的笔记是否被选中,并通知适配器数据已更改。
|
||||
|
||||
public boolean isInChoiceMode() {
|
||||
return mChoiceMode;
|
||||
}//返回是否处于选择笔记的模式。
|
||||
|
||||
public void setChoiceMode(boolean mode) {
|
||||
mSelectedIndex.clear();
|
||||
mChoiceMode = mode;
|
||||
}//设置选择笔记的模式,并清空 mSelectedIndex。
|
||||
|
||||
public void selectAll(boolean checked) {
|
||||
Cursor cursor = getCursor();
|
||||
for (int i = 0; i < getCount(); i++) {
|
||||
if (cursor.moveToPosition(i)) {
|
||||
if (NoteItemData.getNoteType(cursor) == Notes.TYPE_NOTE) {
|
||||
setCheckedItem(i, checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}//选择所有笔记。
|
||||
|
||||
public HashSet<Long> getSelectedItemIds() {
|
||||
HashSet<Long> itemSet = new HashSet<Long>();
|
||||
for (Integer position : mSelectedIndex.keySet()) {
|
||||
if (mSelectedIndex.get(position) == true) {
|
||||
Long id = getItemId(position);
|
||||
if (id == Notes.ID_ROOT_FOLDER) {
|
||||
Log.d(TAG, "Wrong item id, should not happen");
|
||||
} else {
|
||||
itemSet.add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return itemSet;
|
||||
}//返回选定的笔记的 ID。
|
||||
|
||||
|
||||
public HashSet<AppWidgetAttribute> getSelectedWidget() {
|
||||
HashSet<AppWidgetAttribute> itemSet = new HashSet<>();
|
||||
for (Integer position : mSelectedIndex.keySet()) {
|
||||
if (Boolean.TRUE.equals(mSelectedIndex.get(position))) {
|
||||
Cursor c = (Cursor) getItem(position);
|
||||
if (c != null) {
|
||||
AppWidgetAttribute widget = new AppWidgetAttribute();
|
||||
NoteItemData item = new NoteItemData(mContext, c);
|
||||
widget.widgetId = item.getWidgetId();
|
||||
widget.widgetType = item.getWidgetType();
|
||||
itemSet.add(widget);
|
||||
/**
|
||||
* Don't close cursor here, only the adapter could close it
|
||||
*/
|
||||
} else {
|
||||
Log.e(TAG, "Invalid cursor");
|
||||
return new HashSet<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
return itemSet;
|
||||
}//返回选定的小部件信息。
|
||||
|
||||
public int getSelectedCount() {
|
||||
Collection<Boolean> values = mSelectedIndex.values();
|
||||
if (null == values) {
|
||||
return 0;
|
||||
}
|
||||
Iterator<Boolean> iter = values.iterator();
|
||||
int count = 0;
|
||||
while (iter.hasNext()) {
|
||||
if (iter.next()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}//返回选定笔记的数量。
|
||||
|
||||
public boolean isAllSelected() {
|
||||
int checkedCount = getSelectedCount();
|
||||
return (checkedCount != 0 && checkedCount == mNotesCount);
|
||||
}//返回是否已经选择了所有笔记。
|
||||
|
||||
public boolean isSelectedItem(final int position) {
|
||||
if (null == mSelectedIndex.get(position)) {
|
||||
return false;
|
||||
}
|
||||
return mSelectedIndex.get(position);
|
||||
}//返回给定位置的笔记是否被选中。
|
||||
|
||||
@Override
|
||||
protected void onContentChanged() {
|
||||
super.onContentChanged();
|
||||
calcNotesCount();
|
||||
}//当笔记数据发生变化时,重新计算笔记数量。
|
||||
|
||||
@Override
|
||||
public void changeCursor(Cursor cursor) {
|
||||
super.changeCursor(cursor);
|
||||
calcNotesCount();
|
||||
}//更改笔记数据游标时,重新计算笔记数量。
|
||||
|
||||
private void calcNotesCount() {
|
||||
mNotesCount = 0;
|
||||
for (int i = 0; i < getCount(); i++) {
|
||||
Cursor c = (Cursor) getItem(i);
|
||||
if (c != null) {
|
||||
if (NoteItemData.getNoteType(c) == Notes.TYPE_NOTE) {
|
||||
mNotesCount++;
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Invalid cursor");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}//计算笔记数量。
|
||||
}
|
||||
@ -1,103 +0,0 @@
|
||||
/*
|
||||
* 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.gtask.data;
|
||||
|
||||
import android.database.Cursor;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
public abstract class Node { // 定义表征同步状态的常量
|
||||
public static final int SYNC_ACTION_NONE = 0;// 本地和云端都无可更新内容(即本地和云端内容一致)
|
||||
|
||||
public static final int SYNC_ACTION_ADD_REMOTE = 1; // 需要在远程云端增加内容
|
||||
|
||||
public static final int SYNC_ACTION_ADD_LOCAL = 2; // 需要在本地增加内容
|
||||
|
||||
public static final int SYNC_ACTION_DEL_REMOTE = 3; // 需要在远程云端删除内容
|
||||
|
||||
public static final int SYNC_ACTION_DEL_LOCAL = 4; // 需要在本地删除内容
|
||||
|
||||
public static final int SYNC_ACTION_UPDATE_REMOTE = 5; // 需要将本地内容更新到远程云端
|
||||
|
||||
public static final int SYNC_ACTION_UPDATE_LOCAL = 6; // 需要将远程云端内容更新到本地
|
||||
|
||||
public static final int SYNC_ACTION_UPDATE_CONFLICT = 7; // 同步出现冲突
|
||||
|
||||
public static final int SYNC_ACTION_ERROR = 8; // 同步出现错误
|
||||
|
||||
// 以下均为定义
|
||||
private String mGid;
|
||||
|
||||
private String mName;
|
||||
|
||||
private long mLastModified;//记录最后一次修改时间
|
||||
|
||||
private boolean mDeleted;//表征是否被删除
|
||||
|
||||
public Node() {
|
||||
mGid = null;
|
||||
mName = "";
|
||||
mLastModified = 0;
|
||||
mDeleted = false;
|
||||
}
|
||||
|
||||
public abstract JSONObject getCreateAction(int actionId);
|
||||
|
||||
public abstract JSONObject getUpdateAction(int actionId);
|
||||
|
||||
public abstract void setContentByRemoteJSON(JSONObject js);
|
||||
|
||||
public abstract void setContentByLocalJSON(JSONObject js);
|
||||
|
||||
public abstract JSONObject getLocalJSONFromContent();
|
||||
|
||||
public abstract int getSyncAction(Cursor c);
|
||||
|
||||
|
||||
public void setGid(String gid) {
|
||||
this.mGid = gid;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.mName = name;
|
||||
}
|
||||
|
||||
public void setLastModified(long lastModified) {
|
||||
this.mLastModified = lastModified;
|
||||
}
|
||||
|
||||
public void setDeleted(boolean deleted) {
|
||||
this.mDeleted = deleted;
|
||||
}
|
||||
|
||||
public String getGid() {
|
||||
return this.mGid;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.mName;
|
||||
}
|
||||
|
||||
public long getLastModified() {
|
||||
return this.mLastModified;
|
||||
}
|
||||
|
||||
public boolean getDeleted() {
|
||||
return this.mDeleted;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,351 +0,0 @@
|
||||
/*
|
||||
* 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.gtask.data;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
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;
|
||||
import net.micode.notes.tool.GTaskStringUtils;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
||||
public class Task extends Node {
|
||||
private static final String TAG = Task.class.getSimpleName();
|
||||
|
||||
private boolean mCompleted; //判断是否完成
|
||||
|
||||
private String mNotes;
|
||||
|
||||
private JSONObject mMetaInfo; //将在实例中存储数据类型
|
||||
|
||||
private Task mPriorSibling;// 对应的优先兄弟Task的指针
|
||||
|
||||
private TaskList mParent; //所在的任务列表的指针
|
||||
|
||||
public Task() {
|
||||
super();
|
||||
mCompleted = false;
|
||||
mNotes = null;
|
||||
mPriorSibling = null; //TaskList中当前Task前面的Task的指针
|
||||
mParent = null; //当前Task所在的TaskList
|
||||
mMetaInfo = null;
|
||||
}
|
||||
|
||||
public JSONObject getCreateAction(int actionId) {
|
||||
JSONObject js = new JSONObject();
|
||||
|
||||
try {
|
||||
// action_type
|
||||
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
|
||||
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE);
|
||||
|
||||
// action_id
|
||||
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
|
||||
|
||||
// index
|
||||
js.put(GTaskStringUtils.GTASK_JSON_INDEX, mParent.getChildTaskIndex(this));
|
||||
|
||||
// entity_delta
|
||||
JSONObject entity = new JSONObject();
|
||||
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
|
||||
entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null");
|
||||
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);
|
||||
|
||||
// parent_id
|
||||
js.put(GTaskStringUtils.GTASK_JSON_PARENT_ID, mParent.getGid());
|
||||
|
||||
// dest_parent_type
|
||||
js.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT_TYPE,
|
||||
GTaskStringUtils.GTASK_JSON_TYPE_GROUP);
|
||||
|
||||
// list_id
|
||||
js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid());
|
||||
|
||||
// prior_sibling_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("fail to generate task-create jsonobject");
|
||||
}
|
||||
|
||||
return js;
|
||||
}
|
||||
|
||||
public JSONObject getUpdateAction(int actionId) {
|
||||
JSONObject js = new JSONObject();
|
||||
|
||||
try {
|
||||
// action_type
|
||||
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
|
||||
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE);
|
||||
|
||||
// action_id
|
||||
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
|
||||
|
||||
// id
|
||||
js.put(GTaskStringUtils.GTASK_JSON_ID, getGid());
|
||||
|
||||
// entity_delta
|
||||
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("fail to generate task-update jsonobject");
|
||||
}
|
||||
|
||||
return js;
|
||||
}
|
||||
|
||||
public void setContentByRemoteJSON(JSONObject js) {
|
||||
if (js != null) {
|
||||
try {
|
||||
// id
|
||||
if (js.has(GTaskStringUtils.GTASK_JSON_ID)) {
|
||||
setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID));
|
||||
}
|
||||
|
||||
// last_modified
|
||||
if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) {
|
||||
setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED));
|
||||
}
|
||||
|
||||
// name
|
||||
if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) {
|
||||
setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME));
|
||||
}
|
||||
|
||||
// notes
|
||||
if (js.has(GTaskStringUtils.GTASK_JSON_NOTES)) {
|
||||
setNotes(js.getString(GTaskStringUtils.GTASK_JSON_NOTES));
|
||||
}
|
||||
|
||||
// deleted
|
||||
if (js.has(GTaskStringUtils.GTASK_JSON_DELETED)) {
|
||||
setDeleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_DELETED));
|
||||
}
|
||||
|
||||
// completed
|
||||
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("fail to get task content from jsonobject");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setContentByLocalJSON(JSONObject js) {
|
||||
if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)
|
||||
|| !js.has(GTaskStringUtils.META_HEAD_DATA)) {
|
||||
Log.w(TAG, "setContentByLocalJSON: nothing is avaiable");
|
||||
}
|
||||
|
||||
try {
|
||||
JSONObject note = 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, "invalid type");
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
public JSONObject getLocalJSONFromContent() {
|
||||
String name = getName();
|
||||
try {
|
||||
if (mMetaInfo == null) {
|
||||
// new task created from web
|
||||
if (name == null) {
|
||||
Log.w(TAG, "the note seems to be an empty one");
|
||||
return null;
|
||||
}
|
||||
|
||||
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;
|
||||
} else {
|
||||
// synced task
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public void setMetaInfo(MetaData metaData) {
|
||||
if (metaData != null && metaData.getNotes() != null) {
|
||||
try {
|
||||
mMetaInfo = new JSONObject(metaData.getNotes());
|
||||
} catch (JSONException e) {
|
||||
Log.w(TAG, e.toString());
|
||||
mMetaInfo = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, "it seems that note meta has been deleted");
|
||||
return SYNC_ACTION_UPDATE_REMOTE;
|
||||
}
|
||||
|
||||
if (!noteInfo.has(NoteColumns.ID)) {
|
||||
Log.w(TAG, "remote note id seems to be deleted");
|
||||
return SYNC_ACTION_UPDATE_LOCAL;
|
||||
}
|
||||
|
||||
// validate the note id now
|
||||
if (c.getLong(SqlNote.ID_COLUMN) != noteInfo.getLong(NoteColumns.ID)) {
|
||||
Log.w(TAG, "note id doesn't match");
|
||||
return SYNC_ACTION_UPDATE_LOCAL;
|
||||
}
|
||||
|
||||
if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) {
|
||||
// there is no local update
|
||||
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
|
||||
// no update both side
|
||||
return SYNC_ACTION_NONE;
|
||||
} else {
|
||||
// apply remote to local
|
||||
return SYNC_ACTION_UPDATE_LOCAL;
|
||||
}
|
||||
} else {
|
||||
// validate gtask id
|
||||
if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) {
|
||||
Log.e(TAG, "gtask id doesn't match");
|
||||
return SYNC_ACTION_ERROR;
|
||||
}
|
||||
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
|
||||
// local modification only
|
||||
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;
|
||||
}
|
||||
|
||||
public boolean isWorthSaving() {
|
||||
return mMetaInfo != null || (getName() != null && getName().trim().length() > 0)
|
||||
|| (getNotes() != null && getNotes().trim().length() > 0);
|
||||
}
|
||||
|
||||
public void setCompleted(boolean completed) {
|
||||
this.mCompleted = completed;
|
||||
}
|
||||
|
||||
public void setNotes(String notes) {
|
||||
this.mNotes = notes;
|
||||
}
|
||||
|
||||
public void setPriorSibling(Task priorSibling) {
|
||||
this.mPriorSibling = priorSibling;
|
||||
}
|
||||
|
||||
public void setParent(TaskList parent) {
|
||||
this.mParent = parent;
|
||||
}
|
||||
|
||||
public boolean getCompleted() {
|
||||
return this.mCompleted;
|
||||
}
|
||||
|
||||
public String getNotes() {
|
||||
return this.mNotes;
|
||||
}
|
||||
|
||||
public Task getPriorSibling() {
|
||||
return this.mPriorSibling;
|
||||
}
|
||||
|
||||
public TaskList getParent() {
|
||||
return this.mParent;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
// Apache许可证协议
|
||||
package net.micode.notes.widget;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.Context;
|
||||
|
||||
import net.micode.notes.R;
|
||||
import net.micode.notes.data.Notes;
|
||||
import net.micode.notes.tool.ResourceParser;
|
||||
|
||||
|
||||
public class NoteWidgetProvider_2x extends NoteWidgetProvider { // 2x2大小的窗口小部件
|
||||
@Override // 重写窗口小部件中的更新函数
|
||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
||||
super.update(context, appWidgetManager, appWidgetIds);
|
||||
}
|
||||
|
||||
@Override // 重写窗口小部件中的获取布局ID函数
|
||||
protected int getLayoutId() {
|
||||
return R.layout.widget_2x;
|
||||
}
|
||||
|
||||
@Override // 重写窗口小部件中的获取资源ID函数
|
||||
protected int getBgResourceId(int bgId) {
|
||||
return ResourceParser.WidgetBgResources.getWidget2xBgResource(bgId);
|
||||
}
|
||||
|
||||
@Override // 重写窗口小部件中的获取宽度类型函数
|
||||
protected int getWidgetType() {
|
||||
return Notes.TYPE_WIDGET_2X;
|
||||
}
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
// Apache许可证协议
|
||||
package net.micode.notes.widget;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.Context;
|
||||
|
||||
import net.micode.notes.R;
|
||||
import net.micode.notes.data.Notes;
|
||||
import net.micode.notes.tool.ResourceParser;
|
||||
|
||||
public class NoteWidgetProvider_3x extends NoteWidgetProvider{ // 3x3大小的窗口小部件
|
||||
|
||||
@Override
|
||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
||||
super.update(context, appWidgetManager, appWidgetIds);
|
||||
}
|
||||
|
||||
@Override // 重写窗口小部件中的获取布局ID函数
|
||||
protected int getLayoutId() {
|
||||
return R.layout.widget_3x;
|
||||
}
|
||||
|
||||
@Override // 重写窗口小部件中的获取资源ID函数
|
||||
protected int getBgResourceId(int bgId) {
|
||||
return ResourceParser.WidgetBgResources.getWidget3xBgResource(bgId);
|
||||
}
|
||||
|
||||
@Override // 重写窗口小部件中的获取宽度类型函数
|
||||
protected int getWidgetType() {
|
||||
return Notes.TYPE_WIDGET_3X;
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
// Apache许可证协议
|
||||
|
||||
package net.micode.notes.widget;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.Context;
|
||||
|
||||
import net.micode.notes.R;
|
||||
import net.micode.notes.data.Notes;
|
||||
import net.micode.notes.tool.ResourceParser;
|
||||
|
||||
|
||||
public class NoteWidgetProvider_4x extends NoteWidgetProvider { // 4x4大小的窗口小部件
|
||||
@Override // 重写窗口小部件中的更新函数
|
||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
||||
super.update(context, appWidgetManager, appWidgetIds);
|
||||
}
|
||||
|
||||
@Override // 重写窗口小部件中的获取布局ID函数
|
||||
protected int getLayoutId() {
|
||||
return R.layout.widget_4x;
|
||||
}
|
||||
|
||||
@Override // 重写窗口小部件中的获取资源ID函数
|
||||
protected int getBgResourceId(int bgId) {
|
||||
return ResourceParser.WidgetBgResources.getWidget4xBgResource(bgId);
|
||||
}
|
||||
|
||||
@Override // 重写窗口小部件中的获取宽度类型函数
|
||||
protected int getWidgetType() {
|
||||
return Notes.TYPE_WIDGET_4X;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
Subproject commit f5c6e4fa225a126a4123a72484291e177f870b5f
|
||||
@ -1,139 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:versionCode="1"
|
||||
android:versionName="0.1">
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="16"
|
||||
tools:ignore="GradleOverrides" />
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.USE_CREDENTIALS" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
|
||||
<application
|
||||
android:icon="@drawable/icon_app"
|
||||
android:label="@string/app_name">
|
||||
<!-- 添加欢迎界面-->
|
||||
<activity
|
||||
android:name=".ui.WelcomeActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:exported="true"
|
||||
android:label="@string/title_activity_welcome"
|
||||
android:theme="@style/Theme.Notes.Fullscreen">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".ui.NotesListActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:exported="false"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/NoteTheme"
|
||||
android:uiOptions="splitActionBarWhenNarrow"
|
||||
android:windowSoftInputMode="adjustPan">
|
||||
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".ui.NoteEditActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/NoteTheme">
|
||||
<intent-filter
|
||||
android:scheme="http"
|
||||
tools:ignore="AppLinkUrlError">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:mimeType="vnd.android.cursor.item/text_note" />
|
||||
<data android:mimeType="vnd.android.cursor.item/call_note" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.INSERT_OR_EDIT" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:mimeType="vnd.android.cursor.item/text_note" />
|
||||
<data android:mimeType="vnd.android.cursor.item/call_note" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEARCH" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.app.searchable"
|
||||
android:resource="@xml/searchable" />
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:name=".data.NotesProvider"
|
||||
android:authorities="micode_notes"
|
||||
android:exported="false"
|
||||
android:multiprocess="true" />
|
||||
|
||||
<receiver
|
||||
android:name=".widget.NoteWidgetProvider_2x"
|
||||
android:exported="true"
|
||||
android:label="@string/app_widget2x2">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
|
||||
<action android:name="android.intent.action.PRIVACY_MODE_CHANGED" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/widget_2x_info" />
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".widget.NoteWidgetProvider_4x"
|
||||
android:exported="true"
|
||||
android:label="@string/app_widget4x4">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
|
||||
<action android:name="android.intent.action.PRIVACY_MODE_CHANGED" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/widget_4x_info" />
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".ui.AlarmInitReceiver"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".ui.AlarmReceiver"
|
||||
android:process=":remote" />
|
||||
|
||||
<activity
|
||||
android:name=".ui.AlarmAlertActivity"
|
||||
android:launchMode="singleInstance"
|
||||
android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar" />
|
||||
|
||||
<meta-data
|
||||
android:name="android.app.default_searchable"
|
||||
android:value=".ui.NoteEditActivity" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@ -1,59 +0,0 @@
|
||||
// Apache许可证协议
|
||||
|
||||
package net.micode.notes.data;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.provider.ContactsContract.CommonDataKinds.Phone;
|
||||
import android.provider.ContactsContract.Data;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class Contact {
|
||||
private static HashMap<String, String> sContactCache;
|
||||
private static final String TAG = "Contact";
|
||||
|
||||
private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER
|
||||
+ ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'"
|
||||
+ " AND " + Data.RAW_CONTACT_ID + " IN "
|
||||
+ "(SELECT raw_contact_id "
|
||||
+ " FROM phone_lookup"
|
||||
+ " WHERE min_match = '+')";
|
||||
|
||||
public static String getContact(Context context, String phoneNumber) {
|
||||
if(sContactCache == null) {
|
||||
sContactCache = new HashMap<>();
|
||||
}
|
||||
|
||||
if(sContactCache.containsKey(phoneNumber)) {
|
||||
return sContactCache.get(phoneNumber);
|
||||
}
|
||||
|
||||
String selection = CALLER_ID_SELECTION.replace("+",
|
||||
PhoneNumberUtils.toCallerIDMinMatch(phoneNumber));
|
||||
Cursor cursor = context.getContentResolver().query(
|
||||
Data.CONTENT_URI,
|
||||
new String [] { Phone.DISPLAY_NAME },
|
||||
selection,
|
||||
new String[] { phoneNumber },
|
||||
null);
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
try {
|
||||
String name = cursor.getString(0);
|
||||
sContactCache.put(phoneNumber, name);
|
||||
return name;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
Log.e(TAG, " Cursor get string error " + e);
|
||||
return null;
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "No contact matched with number:" + phoneNumber);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,348 +0,0 @@
|
||||
// Apache许可证协议
|
||||
|
||||
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;
|
||||
|
||||
|
||||
public class WorkingNote {
|
||||
// Note for the working note
|
||||
private Note mNote;
|
||||
// Note Id
|
||||
private long mNoteId;
|
||||
// Note content
|
||||
private String mContent;
|
||||
// Note mode
|
||||
private int mMode;
|
||||
|
||||
private long mAlertDate;
|
||||
|
||||
private long mModifiedDate;
|
||||
|
||||
private int mBgColorId;
|
||||
|
||||
private int mWidgetId;
|
||||
|
||||
private int mWidgetType;
|
||||
|
||||
private long mFolderId;
|
||||
|
||||
private Context mContext;
|
||||
|
||||
private static final String TAG = "WorkingNote";
|
||||
|
||||
private boolean mIsDeleted;
|
||||
|
||||
private NoteSettingChangedListener mNoteSettingStatusListener;
|
||||
|
||||
public static final String[] DATA_PROJECTION = new String[] {
|
||||
DataColumns.ID,
|
||||
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
|
||||
private WorkingNote(Context context, long folderId) {
|
||||
mContext = context;
|
||||
mAlertDate = 0;
|
||||
mModifiedDate = System.currentTimeMillis();
|
||||
mFolderId = folderId;
|
||||
mNote = new Note();
|
||||
mNoteId = 0;
|
||||
mIsDeleted = false;
|
||||
mMode = 0;
|
||||
mWidgetType = Notes.TYPE_WIDGET_INVALID;
|
||||
}
|
||||
|
||||
// Existing note construct
|
||||
private WorkingNote(Context context, long noteId, long folderId) {
|
||||
mContext = context;
|
||||
mNoteId = noteId;
|
||||
mFolderId = folderId;
|
||||
mIsDeleted = false;
|
||||
mNote = new Note();
|
||||
loadNote();
|
||||
}
|
||||
|
||||
private void loadNote() {
|
||||
Cursor cursor = mContext.getContentResolver().query(
|
||||
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null,
|
||||
null, null);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 单例类 用于保存当前正在编辑的note
|
||||
*/
|
||||
public synchronized boolean saveNote() {
|
||||
if (isWorthSaving()) {
|
||||
if (!existInDatabase() && ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0)) {
|
||||
Log.e(TAG, "Create new note fail with id:" + mNoteId);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// 如果有widget则更新widget
|
||||
if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID
|
||||
&& mWidgetType != Notes.TYPE_WIDGET_INVALID
|
||||
&& mNoteSettingStatusListener != null) {
|
||||
mNoteSettingStatusListener.onWidgetChanged();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean existInDatabase() {
|
||||
return mNoteId > 0;
|
||||
}
|
||||
|
||||
private boolean isWorthSaving() {
|
||||
return !mIsDeleted && (existInDatabase() || !TextUtils.isEmpty(mContent))
|
||||
&& (!existInDatabase() || mNote.isLocalModified());
|
||||
}
|
||||
|
||||
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_INVALID && 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));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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 boolean hasClockAlert() {
|
||||
return (mAlertDate > 0);
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
@ -1,79 +0,0 @@
|
||||
// Apache许可证协议
|
||||
|
||||
package net.micode.notes.ui;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.text.format.DateFormat;
|
||||
import android.text.format.DateUtils;
|
||||
|
||||
import net.micode.notes.R;
|
||||
import net.micode.notes.ui.DateTimePicker.OnDateTimeChangedListener;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
public class DateTimePickerDialog extends AlertDialog implements OnClickListener {
|
||||
|
||||
private Calendar mDate = Calendar.getInstance();
|
||||
private boolean mIs24HourView;
|
||||
private OnDateTimeSetListener mOnDateTimeSetListener;
|
||||
private DateTimePicker mDateTimePicker;
|
||||
|
||||
public interface OnDateTimeSetListener {
|
||||
void OnDateTimeSet(AlertDialog dialog, long date);
|
||||
}
|
||||
// 实现了一个 OnDateTimeSetListener 接口,该接口定义了一个 OnDateTimeSet() 方法,用于在用户选择日期时间后通知调用者。
|
||||
|
||||
public DateTimePickerDialog(Context context, long date) {
|
||||
super(context);
|
||||
mDateTimePicker = new DateTimePicker(context);
|
||||
setView(mDateTimePicker);
|
||||
mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() {
|
||||
public void onDateTimeChanged(DateTimePicker view, int year, int month,
|
||||
int dayOfMonth, int hourOfDay, int minute) {
|
||||
mDate.set(Calendar.YEAR, year);
|
||||
mDate.set(Calendar.MONTH, month);
|
||||
mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
|
||||
mDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
|
||||
mDate.set(Calendar.MINUTE, minute);
|
||||
updateTitle(mDate.getTimeInMillis());
|
||||
}
|
||||
});
|
||||
// 包含了一个 DateTimePicker 控件,用于让用户选择日期和时间。通过 mDateTimePicker.setOnDateTimeChangedListener() 方法,当用户选择日期和时间时,将更新 mDate 的值,并使用 updateTitle() 方法更新对话框的标题。
|
||||
mDate.setTimeInMillis(date);
|
||||
mDate.set(Calendar.SECOND, 0);
|
||||
mDateTimePicker.setCurrentDate(mDate.getTimeInMillis());
|
||||
setButton(context.getString(R.string.datetime_dialog_ok), this);
|
||||
setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null);
|
||||
set24HourView(DateFormat.is24HourFormat(this.getContext()));
|
||||
updateTitle(mDate.getTimeInMillis());
|
||||
}
|
||||
|
||||
public void set24HourView(boolean is24HourView) {
|
||||
mIs24HourView = is24HourView;
|
||||
}
|
||||
//set24HourView() 方法,用于设置日期时间选择器是否为 24 小时格式。默认情况下,该值将由系统的设置决定。
|
||||
|
||||
public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) {
|
||||
mOnDateTimeSetListener = callBack;
|
||||
}
|
||||
|
||||
private void updateTitle(long date) {
|
||||
int flag =
|
||||
DateUtils.FORMAT_SHOW_YEAR |
|
||||
DateUtils.FORMAT_SHOW_DATE |
|
||||
DateUtils.FORMAT_SHOW_TIME;
|
||||
flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_24HOUR;
|
||||
setTitle(DateUtils.formatDateTime(this.getContext(), date, flag));
|
||||
}
|
||||
|
||||
public void onClick(DialogInterface arg0, int arg1) {
|
||||
if (mOnDateTimeSetListener != null) {
|
||||
mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis());
|
||||
}
|
||||
}
|
||||
// 重写了 onClick() 方法,以便在用户点击“确定”按钮后,将用户选择的日期时间作为参数传递到 OnDateTimeSet() 方法中,从而通知调用者。
|
||||
|
||||
}
|
||||
@ -1,200 +0,0 @@
|
||||
// Apache许可证协议
|
||||
|
||||
package net.micode.notes.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.text.Layout;
|
||||
import android.text.Selection;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.URLSpan;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MenuItem.OnMenuItemClickListener;
|
||||
import android.view.MotionEvent;
|
||||
import android.widget.EditText;
|
||||
|
||||
import net.micode.notes.R;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class NoteEditText extends EditText {
|
||||
private static final String TAG = "NoteEditText";
|
||||
private int mIndex;
|
||||
private int mSelectionStartBeforeDelete;
|
||||
|
||||
private static final String SCHEME_TEL = "tel:" ;
|
||||
private static final String SCHEME_HTTP = "http:" ;
|
||||
private static final String SCHEME_EMAIL = "mailto:" ;
|
||||
|
||||
private static final Map<String, Integer> sSchemaActionResMap = new HashMap<String, Integer>();
|
||||
static {
|
||||
sSchemaActionResMap.put(SCHEME_TEL, R.string.note_link_tel);
|
||||
sSchemaActionResMap.put(SCHEME_HTTP, R.string.note_link_web);
|
||||
sSchemaActionResMap.put(SCHEME_EMAIL, R.string.note_link_email);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call by the {@link NoteEditActivity} to delete or add edit text
|
||||
*/
|
||||
public interface OnTextViewChangeListener {
|
||||
/**
|
||||
* Delete current edit text when {@link KeyEvent#KEYCODE_DEL} happens
|
||||
* and the text is null
|
||||
*/
|
||||
void onEditTextDelete(int index, String text);
|
||||
|
||||
/**
|
||||
* Add edit text after current edit text when {@link KeyEvent#KEYCODE_ENTER}
|
||||
* happen
|
||||
*/
|
||||
void onEditTextEnter(int index, String text);
|
||||
|
||||
/**
|
||||
* Hide or show item option when text change
|
||||
*/
|
||||
void onTextChange(int index, boolean hasText);
|
||||
}
|
||||
|
||||
private OnTextViewChangeListener mOnTextViewChangeListener;
|
||||
|
||||
public NoteEditText(Context context) {
|
||||
super(context, null);
|
||||
mIndex = 0;
|
||||
}
|
||||
|
||||
public void setIndex(int index) {
|
||||
mIndex = index;
|
||||
}//用于设置控件在父容器中的位置索引
|
||||
|
||||
public void setOnTextViewChangeListener(OnTextViewChangeListener listener) {
|
||||
mOnTextViewChangeListener = listener;
|
||||
}//用于设置文本变化的监听器
|
||||
|
||||
public NoteEditText(Context context, AttributeSet attrs) {
|
||||
super(context, attrs, android.R.attr.editTextStyle);
|
||||
}
|
||||
|
||||
public NoteEditText(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
|
||||
int x = (int) event.getX();
|
||||
int y = (int) event.getY();
|
||||
x -= getTotalPaddingLeft();
|
||||
y -= getTotalPaddingTop();
|
||||
x += getScrollX();
|
||||
y += getScrollY();
|
||||
|
||||
Layout layout = getLayout();
|
||||
int line = layout.getLineForVertical(y);
|
||||
int off = layout.getOffsetForHorizontal(line, x);
|
||||
Selection.setSelection(getText(), off);
|
||||
break;
|
||||
}//实现了点击控件后,将光标移动到点击位置的功能
|
||||
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_ENTER:
|
||||
if (mOnTextViewChangeListener != null) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case KeyEvent.KEYCODE_DEL:
|
||||
mSelectionStartBeforeDelete = getSelectionStart();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||
switch(keyCode) {
|
||||
case KeyEvent.KEYCODE_DEL:
|
||||
if (mOnTextViewChangeListener != null) {
|
||||
if (0 == mSelectionStartBeforeDelete && mIndex != 0) {
|
||||
mOnTextViewChangeListener.onEditTextDelete(mIndex, getText().toString());
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "OnTextViewChangeListener was not seted");
|
||||
}
|
||||
break;
|
||||
case KeyEvent.KEYCODE_ENTER:
|
||||
if (mOnTextViewChangeListener != null) {
|
||||
int selectionStart = getSelectionStart();
|
||||
String text = getText().subSequence(selectionStart, length()).toString();
|
||||
setText(getText().subSequence(0, selectionStart));
|
||||
mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, text);
|
||||
} else {
|
||||
Log.d(TAG, "OnTextViewChangeListener was not seted");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
// onKeyDown和onKeyUp方法实现了按下和松开键盘按键时的响应。
|
||||
|
||||
@Override
|
||||
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
|
||||
if (mOnTextViewChangeListener != null) {
|
||||
mOnTextViewChangeListener.onTextChange(mIndex, focused || !TextUtils.isEmpty(getText()));
|
||||
}
|
||||
super.onFocusChanged(focused, direction, previouslyFocusedRect);
|
||||
}//控件获得或失去焦点时触发,将焦点状态通知给监听器。
|
||||
|
||||
@Override
|
||||
protected void onCreateContextMenu(ContextMenu menu) {
|
||||
if (getText() instanceof Spanned) {
|
||||
int selStart = getSelectionStart();
|
||||
int selEnd = getSelectionEnd();
|
||||
|
||||
int min = Math.min(selStart, selEnd);
|
||||
int max = Math.max(selStart, selEnd);
|
||||
|
||||
final URLSpan[] urls = ((Spanned) getText()).getSpans(min, max, URLSpan.class);
|
||||
if (urls.length == 1) {
|
||||
int defaultResId = 0;
|
||||
for(String schema: sSchemaActionResMap.keySet()) {
|
||||
if(urls[0].getURL().indexOf(schema) >= 0) {
|
||||
defaultResId = sSchemaActionResMap.get(schema);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultResId == 0) {
|
||||
defaultResId = R.string.note_link_other;
|
||||
}
|
||||
|
||||
menu.add(0, 0, 0, defaultResId).setOnMenuItemClickListener(
|
||||
new OnMenuItemClickListener() {
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
// goto a new intent
|
||||
urls[0].onClick(NoteEditText.this);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
super.onCreateContextMenu(menu);
|
||||
}
|
||||
// 创建上下文菜单,当用户长按控件中的链接时,根据链接的协议类型创建不同的菜单项,点击菜单项后跳转到相应的链接。
|
||||
}
|
||||
@ -1,210 +0,0 @@
|
||||
// Apache许可证协议
|
||||
|
||||
package net.micode.notes.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import net.micode.notes.data.Contact;
|
||||
import net.micode.notes.data.Notes;
|
||||
import net.micode.notes.data.Notes.NoteColumns;
|
||||
import net.micode.notes.tool.DataUtils;
|
||||
|
||||
|
||||
public class NoteItemData {
|
||||
static final String [] PROJECTION = new String [] {
|
||||
NoteColumns.ID,
|
||||
NoteColumns.ALERTED_DATE,
|
||||
NoteColumns.BG_COLOR_ID,
|
||||
NoteColumns.CREATED_DATE,
|
||||
NoteColumns.HAS_ATTACHMENT,
|
||||
NoteColumns.MODIFIED_DATE,
|
||||
NoteColumns.NOTES_COUNT,
|
||||
NoteColumns.PARENT_ID,
|
||||
NoteColumns.SNIPPET,
|
||||
NoteColumns.TYPE,
|
||||
NoteColumns.WIDGET_ID,
|
||||
NoteColumns.WIDGET_TYPE,
|
||||
};
|
||||
|
||||
private static final int ID_COLUMN = 0;
|
||||
private static final int ALERTED_DATE_COLUMN = 1;
|
||||
private static final int BG_COLOR_ID_COLUMN = 2;
|
||||
private static final int CREATED_DATE_COLUMN = 3;
|
||||
private static final int HAS_ATTACHMENT_COLUMN = 4;
|
||||
private static final int MODIFIED_DATE_COLUMN = 5;
|
||||
private static final int NOTES_COUNT_COLUMN = 6;
|
||||
private static final int PARENT_ID_COLUMN = 7;
|
||||
private static final int SNIPPET_COLUMN = 8;
|
||||
private static final int TYPE_COLUMN = 9;
|
||||
private static final int WIDGET_ID_COLUMN = 10;
|
||||
private static final int WIDGET_TYPE_COLUMN = 11;
|
||||
|
||||
private long mId;
|
||||
private long mAlertDate;
|
||||
private int mBgColorId;
|
||||
private long mCreatedDate;
|
||||
private boolean mHasAttachment;
|
||||
private long mModifiedDate;
|
||||
private int mNotesCount;
|
||||
private long mParentId;
|
||||
private String mSnippet;
|
||||
private int mType;
|
||||
private int mWidgetId;
|
||||
private int mWidgetType;
|
||||
private String mName;
|
||||
private String mPhoneNumber;
|
||||
|
||||
private boolean mIsLastItem;
|
||||
private boolean mIsFirstItem;
|
||||
private boolean mIsOnlyOneItem;
|
||||
private boolean mIsOneNoteFollowingFolder;
|
||||
private boolean mIsMultiNotesFollowingFolder;
|
||||
|
||||
public NoteItemData(Context context, Cursor cursor) {
|
||||
mId = cursor.getLong(ID_COLUMN);
|
||||
mAlertDate = cursor.getLong(ALERTED_DATE_COLUMN);
|
||||
mBgColorId = cursor.getInt(BG_COLOR_ID_COLUMN);
|
||||
mCreatedDate = cursor.getLong(CREATED_DATE_COLUMN);
|
||||
mHasAttachment = cursor.getInt(HAS_ATTACHMENT_COLUMN) > 0;
|
||||
mModifiedDate = cursor.getLong(MODIFIED_DATE_COLUMN);
|
||||
mNotesCount = cursor.getInt(NOTES_COUNT_COLUMN);
|
||||
mParentId = cursor.getLong(PARENT_ID_COLUMN);
|
||||
mSnippet = cursor.getString(SNIPPET_COLUMN);
|
||||
mSnippet = mSnippet.replace(NoteEditActivity.TAG_CHECKED, "").replace(
|
||||
NoteEditActivity.TAG_UNCHECKED, "");
|
||||
mType = cursor.getInt(TYPE_COLUMN);
|
||||
mWidgetId = cursor.getInt(WIDGET_ID_COLUMN);
|
||||
mWidgetType = cursor.getInt(WIDGET_TYPE_COLUMN);
|
||||
|
||||
mPhoneNumber = "";
|
||||
if (mParentId == Notes.ID_CALL_RECORD_FOLDER) {
|
||||
mPhoneNumber = DataUtils.getCallNumberByNoteId(context.getContentResolver(), mId);
|
||||
if (!TextUtils.isEmpty(mPhoneNumber)) {
|
||||
mName = Contact.getContact(context, mPhoneNumber);
|
||||
if (mName == null) {
|
||||
mName = mPhoneNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mName == null) {
|
||||
mName = "";
|
||||
}
|
||||
checkPosition(cursor);
|
||||
}
|
||||
|
||||
private void checkPosition(Cursor cursor) {
|
||||
mIsLastItem = cursor.isLast();
|
||||
mIsFirstItem = cursor.isFirst();
|
||||
mIsOnlyOneItem = (cursor.getCount() == 1);
|
||||
mIsMultiNotesFollowingFolder = false;
|
||||
mIsOneNoteFollowingFolder = false;
|
||||
|
||||
if (mType == Notes.TYPE_NOTE && !mIsFirstItem) {
|
||||
int position = cursor.getPosition();
|
||||
if (cursor.moveToPrevious()) {
|
||||
if (cursor.getInt(TYPE_COLUMN) == Notes.TYPE_FOLDER
|
||||
|| cursor.getInt(TYPE_COLUMN) == Notes.TYPE_SYSTEM) {
|
||||
if (cursor.getCount() > (position + 1)) {
|
||||
mIsMultiNotesFollowingFolder = true;
|
||||
} else {
|
||||
mIsOneNoteFollowingFolder = true;
|
||||
}
|
||||
}
|
||||
if (!cursor.moveToNext()) {
|
||||
throw new IllegalStateException("cursor move to previous but can't move back");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isOneFollowingFolder() {
|
||||
return mIsOneNoteFollowingFolder;
|
||||
}
|
||||
|
||||
public boolean isMultiFollowingFolder() {
|
||||
return mIsMultiNotesFollowingFolder;
|
||||
}
|
||||
|
||||
public boolean isLast() {
|
||||
return mIsLastItem;
|
||||
}
|
||||
|
||||
public String getCallName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
public boolean isFirst() {
|
||||
return mIsFirstItem;
|
||||
}
|
||||
|
||||
public boolean isSingle() {
|
||||
return mIsOnlyOneItem;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public long getAlertDate() {
|
||||
return mAlertDate;
|
||||
}
|
||||
|
||||
public long getCreatedDate() {
|
||||
return mCreatedDate;
|
||||
}
|
||||
|
||||
public boolean hasAttachment() {
|
||||
return mHasAttachment;
|
||||
}
|
||||
|
||||
public long getModifiedDate() {
|
||||
return mModifiedDate;
|
||||
}
|
||||
|
||||
public int getBgColorId() {
|
||||
return mBgColorId;
|
||||
}
|
||||
|
||||
public long getParentId() {
|
||||
return mParentId;
|
||||
}
|
||||
|
||||
public int getNotesCount() {
|
||||
return mNotesCount;
|
||||
}
|
||||
|
||||
public long getFolderId () {
|
||||
return mParentId;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
public int getWidgetType() {
|
||||
return mWidgetType;
|
||||
}
|
||||
|
||||
public int getWidgetId() {
|
||||
return mWidgetId;
|
||||
}
|
||||
|
||||
public String getSnippet() {
|
||||
return mSnippet;
|
||||
}
|
||||
|
||||
public boolean hasAlert() {
|
||||
return (mAlertDate > 0);
|
||||
}
|
||||
|
||||
public boolean isCallRecord() {
|
||||
return (mParentId == Notes.ID_CALL_RECORD_FOLDER && !TextUtils.isEmpty(mPhoneNumber));
|
||||
}
|
||||
|
||||
public static int getNoteType(Cursor cursor) {
|
||||
return cursor.getInt(TYPE_COLUMN);
|
||||
}
|
||||
}
|
||||
@ -1,171 +0,0 @@
|
||||
// Apache许可证协议
|
||||
|
||||
package net.micode.notes.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CursorAdapter;
|
||||
|
||||
import net.micode.notes.data.Notes;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
||||
|
||||
public class NotesListAdapter extends CursorAdapter {
|
||||
private static final String TAG = "NotesListAdapter";
|
||||
private Context mContext;
|
||||
private HashMap<Integer, Boolean> mSelectedIndex;
|
||||
private int mNotesCount;
|
||||
private boolean mChoiceMode;
|
||||
|
||||
public static class AppWidgetAttribute {
|
||||
public int widgetId;
|
||||
public int widgetType;
|
||||
};
|
||||
|
||||
public NotesListAdapter(Context context) {
|
||||
super(context, null);
|
||||
mSelectedIndex = new HashMap<>();
|
||||
mContext = context;
|
||||
mNotesCount = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
return new NotesListItem(context);
|
||||
}//创建一个新的笔记列表项视图,即 NotesListItem。
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
if (view instanceof NotesListItem) {
|
||||
NoteItemData itemData = new NoteItemData(context, cursor);
|
||||
((NotesListItem) view).bind(context, itemData, mChoiceMode,
|
||||
isSelectedItem(cursor.getPosition()));
|
||||
}
|
||||
}//将笔记数据绑定到给定的笔记列表项视图中。
|
||||
|
||||
public void setCheckedItem(final int position, final boolean checked) {
|
||||
mSelectedIndex.put(position, checked);
|
||||
notifyDataSetChanged();
|
||||
}//设置给定位置的笔记是否被选中,并通知适配器数据已更改。
|
||||
|
||||
public boolean isInChoiceMode() {
|
||||
return mChoiceMode;
|
||||
}//返回是否处于选择笔记的模式。
|
||||
|
||||
public void setChoiceMode(boolean mode) {
|
||||
mSelectedIndex.clear();
|
||||
mChoiceMode = mode;
|
||||
}//设置选择笔记的模式,并清空 mSelectedIndex。
|
||||
|
||||
public void selectAll(boolean checked) {
|
||||
Cursor cursor = getCursor();
|
||||
for (int i = 0; i < getCount(); i++) {
|
||||
if (cursor.moveToPosition(i)) {
|
||||
if (NoteItemData.getNoteType(cursor) == Notes.TYPE_NOTE) {
|
||||
setCheckedItem(i, checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}//选择所有笔记。
|
||||
|
||||
public HashSet<Long> getSelectedItemIds() {
|
||||
HashSet<Long> itemSet = new HashSet<Long>();
|
||||
for (Integer position : mSelectedIndex.keySet()) {
|
||||
if (mSelectedIndex.get(position) == true) {
|
||||
Long id = getItemId(position);
|
||||
if (id == Notes.ID_ROOT_FOLDER) {
|
||||
Log.d(TAG, "Wrong item id, should not happen");
|
||||
} else {
|
||||
itemSet.add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return itemSet;
|
||||
}//返回选定的笔记的 ID。
|
||||
|
||||
|
||||
public HashSet<AppWidgetAttribute> getSelectedWidget() {
|
||||
HashSet<AppWidgetAttribute> itemSet = new HashSet<>();
|
||||
for (Integer position : mSelectedIndex.keySet()) {
|
||||
if (Boolean.TRUE.equals(mSelectedIndex.get(position))) {
|
||||
Cursor c = (Cursor) getItem(position);
|
||||
if (c != null) {
|
||||
AppWidgetAttribute widget = new AppWidgetAttribute();
|
||||
NoteItemData item = new NoteItemData(mContext, c);
|
||||
widget.widgetId = item.getWidgetId();
|
||||
widget.widgetType = item.getWidgetType();
|
||||
itemSet.add(widget);
|
||||
/**
|
||||
* Don't close cursor here, only the adapter could close it
|
||||
*/
|
||||
} else {
|
||||
Log.e(TAG, "Invalid cursor");
|
||||
return new HashSet<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
return itemSet;
|
||||
}//返回选定的小部件信息。
|
||||
|
||||
public int getSelectedCount() {
|
||||
Collection<Boolean> values = mSelectedIndex.values();
|
||||
if (null == values) {
|
||||
return 0;
|
||||
}
|
||||
Iterator<Boolean> iter = values.iterator();
|
||||
int count = 0;
|
||||
while (iter.hasNext()) {
|
||||
if (iter.next()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}//返回选定笔记的数量。
|
||||
|
||||
public boolean isAllSelected() {
|
||||
int checkedCount = getSelectedCount();
|
||||
return (checkedCount != 0 && checkedCount == mNotesCount);
|
||||
}//返回是否已经选择了所有笔记。
|
||||
|
||||
public boolean isSelectedItem(final int position) {
|
||||
if (null == mSelectedIndex.get(position)) {
|
||||
return false;
|
||||
}
|
||||
return mSelectedIndex.get(position);
|
||||
}//返回给定位置的笔记是否被选中。
|
||||
|
||||
@Override
|
||||
protected void onContentChanged() {
|
||||
super.onContentChanged();
|
||||
calcNotesCount();
|
||||
}//当笔记数据发生变化时,重新计算笔记数量。
|
||||
|
||||
@Override
|
||||
public void changeCursor(Cursor cursor) {
|
||||
super.changeCursor(cursor);
|
||||
calcNotesCount();
|
||||
}//更改笔记数据游标时,重新计算笔记数量。
|
||||
|
||||
private void calcNotesCount() {
|
||||
mNotesCount = 0;
|
||||
for (int i = 0; i < getCount(); i++) {
|
||||
Cursor c = (Cursor) getItem(i);
|
||||
if (c != null) {
|
||||
if (NoteItemData.getNoteType(c) == Notes.TYPE_NOTE) {
|
||||
mNotesCount++;
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Invalid cursor");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}//计算笔记数量。
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
// Apache许可证协议
|
||||
package net.micode.notes.widget;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.Context;
|
||||
|
||||
import net.micode.notes.R;
|
||||
import net.micode.notes.data.Notes;
|
||||
import net.micode.notes.tool.ResourceParser;
|
||||
|
||||
|
||||
public class NoteWidgetProvider_2x extends NoteWidgetProvider { // 2x2大小的窗口小部件
|
||||
@Override // 重写窗口小部件中的更新函数
|
||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
||||
super.update(context, appWidgetManager, appWidgetIds);
|
||||
}
|
||||
|
||||
@Override // 重写窗口小部件中的获取布局ID函数
|
||||
protected int getLayoutId() {
|
||||
return R.layout.widget_2x;
|
||||
}
|
||||
|
||||
@Override // 重写窗口小部件中的获取资源ID函数
|
||||
protected int getBgResourceId(int bgId) {
|
||||
return ResourceParser.WidgetBgResources.getWidget2xBgResource(bgId);
|
||||
}
|
||||
|
||||
@Override // 重写窗口小部件中的获取宽度类型函数
|
||||
protected int getWidgetType() {
|
||||
return Notes.TYPE_WIDGET_2X;
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
// Apache许可证协议
|
||||
|
||||
package net.micode.notes.widget;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.Context;
|
||||
|
||||
import net.micode.notes.R;
|
||||
import net.micode.notes.data.Notes;
|
||||
import net.micode.notes.tool.ResourceParser;
|
||||
|
||||
|
||||
public class NoteWidgetProvider_4x extends NoteWidgetProvider { // 4x4大小的窗口小部件
|
||||
@Override // 重写窗口小部件中的更新函数
|
||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
||||
super.update(context, appWidgetManager, appWidgetIds);
|
||||
}
|
||||
|
||||
@Override // 重写窗口小部件中的获取布局ID函数
|
||||
protected int getLayoutId() {
|
||||
return R.layout.widget_4x;
|
||||
}
|
||||
|
||||
@Override // 重写窗口小部件中的获取资源ID函数
|
||||
protected int getBgResourceId(int bgId) {
|
||||
return ResourceParser.WidgetBgResources.getWidget4xBgResource(bgId);
|
||||
}
|
||||
|
||||
@Override // 重写窗口小部件中的获取宽度类型函数
|
||||
protected int getWidgetType() {
|
||||
return Notes.TYPE_WIDGET_4X;
|
||||
}
|
||||
}
|
||||
@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="#88555555" android:state_pressed="true" />
|
||||
<item android:color="#ff999999" android:state_selected="true" />
|
||||
<item android:color="#ff000000" />
|
||||
</selector>
|
||||
@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="#50000000" />
|
||||
</selector>
|
||||
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 245 B |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 443 B |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |