MiNotes/src/main/java/net/micode/notes/ui/NoteEditActivity.java

1563 lines
62 KiB

This file contains ambiguous Unicode characters!

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

package net.micode.notes.ui;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.app.SearchManager;
import android.appwidget.AppWidgetManager;
import android.content.ContentUris;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Paint;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.style.BackgroundColorSpan;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.TextNote;
import net.micode.notes.model.WorkingNote;
import net.micode.notes.model.WorkingNote.NoteSettingChangedListener;
import net.micode.notes.tool.DataUtils;
import net.micode.notes.tool.ResourceParser;
import net.micode.notes.tool.ResourceParser.TextAppearanceResources;
import net.micode.notes.ui.DateTimePickerDialog.OnDateTimeSetListener;
import net.micode.notes.ui.NoteEditText.OnTextViewChangeListener;
import net.micode.notes.widget.NoteWidgetProvider_2x;
import net.micode.notes.widget.NoteWidgetProvider_4x;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jp.wasabeef.richeditor.RichEditor;
/**
* @Package: net.micode.notes.ui
* @ClassName: NoteEditActivity
* @Description:
* 该类主要是针对标签的编辑
* 继承了系统内部许多和监听有关的类
* @Author: YangYizhe
* @CreateDate: 12/21/2023 12:47 AM
* @Version: 1.0
*/
public class NoteEditActivity extends Activity implements OnClickListener,
NoteSettingChangedListener, OnTextViewChangeListener {
private class HeadViewHolder {
public TextView tvModified;
public ImageView ivAlertIcon;
public TextView tvAlertDate;
public ImageView ibSetBgColor;
public TextView textNum;
}
private static final Map<Integer, Integer> sBgSelectorBtnsMap = new HashMap<Integer, Integer>();
static {
sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW);
sBgSelectorBtnsMap.put(R.id.iv_bg_red, ResourceParser.RED);
sBgSelectorBtnsMap.put(R.id.iv_bg_blue, ResourceParser.BLUE);
sBgSelectorBtnsMap.put(R.id.iv_bg_green, ResourceParser.GREEN);
sBgSelectorBtnsMap.put(R.id.iv_bg_white, ResourceParser.WHITE);
}
private static final Map<Integer, Integer> sBgSelectorSelectionMap = new HashMap<Integer, Integer>();
static {
sBgSelectorSelectionMap.put(ResourceParser.YELLOW, R.id.iv_bg_yellow_select);
sBgSelectorSelectionMap.put(ResourceParser.RED, R.id.iv_bg_red_select);
sBgSelectorSelectionMap.put(ResourceParser.BLUE, R.id.iv_bg_blue_select);
sBgSelectorSelectionMap.put(ResourceParser.GREEN, R.id.iv_bg_green_select);
sBgSelectorSelectionMap.put(ResourceParser.WHITE, R.id.iv_bg_white_select);
}
private static final Map<Integer, Integer> sFontSizeBtnsMap = new HashMap<Integer, Integer>();
static {
sFontSizeBtnsMap.put(R.id.ll_font_large, ResourceParser.TEXT_LARGE);
sFontSizeBtnsMap.put(R.id.ll_font_small, ResourceParser.TEXT_SMALL);
sFontSizeBtnsMap.put(R.id.ll_font_normal, ResourceParser.TEXT_MEDIUM);
sFontSizeBtnsMap.put(R.id.ll_font_super, ResourceParser.TEXT_SUPER);
}
private static final Map<Integer, Integer> sFontSelectorSelectionMap = new HashMap<Integer, Integer>();
static {
sFontSelectorSelectionMap.put(ResourceParser.TEXT_LARGE, R.id.iv_large_select);
sFontSelectorSelectionMap.put(ResourceParser.TEXT_SMALL, R.id.iv_small_select);
sFontSelectorSelectionMap.put(ResourceParser.TEXT_MEDIUM, R.id.iv_medium_select);
sFontSelectorSelectionMap.put(ResourceParser.TEXT_SUPER, R.id.iv_super_select);
}
private static final String TAG = "NoteEditActivity";
private HeadViewHolder mNoteHeaderHolder;
private View mHeadViewPanel;
private View mNoteBgColorSelector;
private View mFontSizeSelector;
//private EditText mNoteEditor;
private RichEditor mNoteEditor;//富文本编辑器
private TextView mPreview;
private String mText;//mText和mNoteLength是给富文本编辑器的
private int mNoteLength;
private int mFontSize;
private View mNoteEditorPanel;
public WorkingNote mWorkingNote;
private SharedPreferences mSharedPrefs;
private int mFontSizeId;
private static final String PREFERENCE_FONT_SIZE = "pref_font_size";
private static final int SHORTCUT_ICON_TITLE_MAX_LEN = 10;
public static final String TAG_CHECKED = String.valueOf('\u221A');
public static final String TAG_UNCHECKED = String.valueOf('\u25A1');
private LinearLayout mEditTextList;
private String mUserQuery;
private Pattern mPattern;
/**
* 新增方法:
* 初始化富文本编辑框
*/
public void initRichEditor(){
mNoteEditor.setEditorHeight(200);//设置编辑器界面高度
mNoteEditor.setEditorFontSize(22);//字体大小
mNoteEditor.setEditorFontColor(1);//字体颜色
mNoteEditor.setPadding(0, 0, 0, 0);//内边距
mNoteEditor.setPlaceholder("点击输入内容");//设置默认显示语句
mNoteEditor.setInputEnabled(true);//设置编辑器是否可用
mNoteEditor.setBackgroundResource(R.drawable.edit_yellow);//编辑背景
mNoteEditor.setOnTextChangeListener(new RichEditor.OnTextChangeListener() {
@Override
public void onTextChange(String text) {
mText = text;
mNoteLength = removeBlank(textChange(mText)).length();
mNoteHeaderHolder.tvModified.setText(DateUtils.formatDateTime(NoteEditActivity.this,
mWorkingNote.getModifiedDate(), DateUtils.FORMAT_SHOW_DATE
| DateUtils.FORMAT_NUMERIC_DATE | DateUtils.FORMAT_SHOW_TIME
| DateUtils.FORMAT_SHOW_YEAR)+"\n字符数"+mNoteLength);
}
});
findViewById(R.id.action_undo).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.undo();
}
});
findViewById(R.id.action_redo).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.redo();
}
});
findViewById(R.id.action_bold).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setBold();
}
});
findViewById(R.id.action_italic).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setItalic();
}
});
findViewById(R.id.action_subscript).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setSubscript();
}
});
findViewById(R.id.action_superscript).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setSuperscript();
}
});
findViewById(R.id.action_strikethrough).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setStrikeThrough();
}
});
findViewById(R.id.action_underline).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setUnderline();
}
});
findViewById(R.id.action_heading1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setHeading(1);
}
});
findViewById(R.id.action_heading2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setHeading(2);
}
});
findViewById(R.id.action_heading3).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setHeading(3);
}
});
findViewById(R.id.action_heading4).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setHeading(4);
}
});
findViewById(R.id.action_heading5).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setHeading(5);
}
});
findViewById(R.id.action_heading6).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setHeading(6);
}
});
/**findViewById(R.id.action_txt_color).setOnClickListener(new View.OnClickListener() {
private boolean isChanged;
@Override
public void onClick(View v) {
mNoteEditor.setTextColor(isChanged ? Color.BLACK : Color.RED);
isChanged = !isChanged;
}
});*/
/**findViewById(R.id.action_bg_color).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {//设置点击响应方法
mNoteEditor.focusEditor();
new AlertDialog.Builder(NoteEditActivity.this).setTitle("选择字体背景颜色")//设置一个AlertDialog供用户选择具体的颜色
.setSingleChoiceItems(R.array.text_bg_color, 0,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
//红
case 0:
mNoteEditor.setTextBackgroundColor(Color.RED);
break;
//黄
case 1:
mNoteEditor.setTextBackgroundColor(Color.YELLOW);
break;
//蓝
case 2:
mNoteEditor.setTextBackgroundColor(Color.BLUE);
break;
//绿
case 3:
mNoteEditor.setTextBackgroundColor(Color.GREEN);
break;
//黑
case 4:
mNoteEditor.setTextBackgroundColor(Color.BLACK);
break;
case 5:
mNoteEditor.setTextBackgroundColor(Color.WHITE);
break;
}
}
}).show();
}
});*/
findViewById(R.id.action_indent).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setIndent();
}
});
findViewById(R.id.action_outdent).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setOutdent();
}
});
findViewById(R.id.action_align_left).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setAlignLeft();
}
});
findViewById(R.id.action_align_center).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setAlignCenter();
}
});
findViewById(R.id.action_align_right).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setAlignRight();
}
});
findViewById(R.id.action_blockquote).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setBlockquote();
}
});
findViewById(R.id.action_insert_bullets).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setBullets();
}
});
findViewById(R.id.action_insert_numbers).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.setNumbers();
}
});
/**findViewById(R.id.action_insert_link).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.insertLink("https://github.com/wasabeef", "wasabeef");
}
});*/
/**findViewById(R.id.action_insert_image).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.insertImage("https://raw.githubusercontent.com/wasabeef/art/master/chip.jpg",
"dachshund", 320);
}
});*/
findViewById(R.id.action_insert_checkbox).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mNoteEditor.insertTodo();
}
});
}
/**
* @method textChange
* @description 对原始文本进行处理,去除图片字符、换行符和空格字符
* @date: 1/3/2024 8:48 AM
* @author: YangYizhe
* @param oriText
* @return 处理后的文本
*/
private String textChange(String oriText) {
StringBuilder stringBuilder = new StringBuilder(oriText);
// 移除所有<>
removeAngleBrackets(stringBuilder);
// 将&nbsp;替换为普通空格
int index = stringBuilder.indexOf("&nbsp;");
while (index != -1) {
stringBuilder.replace(index, index + 6, " ");
index = stringBuilder.indexOf("&nbsp;", index + 1);
}
return stringBuilder.toString();
}
private String removeBlank(String oriText) {
StringBuilder stringBuilder = new StringBuilder(oriText);
// 移除换行符和其他空格
for (int i = 0; i < stringBuilder.length(); i++) {
char c = stringBuilder.charAt(i);
if (c == '\n' || c == ' ') {
stringBuilder.deleteCharAt(i);
i--;
}
}
return stringBuilder.toString();
}
/**
* @method removeAngleBrackets
* @description 用以辅助移除<></>
* @date: 1/18/2024 7:22 PM
* @author: YangYizhe
* @param
* @return
*/
private void removeAngleBrackets(StringBuilder stringBuilder) {
int startIndex = stringBuilder.indexOf("<");
int endIndex = stringBuilder.indexOf(">");
if (startIndex != -1 && endIndex != -1 && startIndex < endIndex) {
stringBuilder.delete(startIndex, endIndex + 1);
removeAngleBrackets(stringBuilder);
}
}
/**
* @method count
* @description 监听编辑框文本变化并更新字符数
* @date: 1/3/2024 9:09 AM
* @author: YangYizhe
*/
/**private void count() {
mNoteEditor.addTextChangedListener(new TextWatcher() {
int currentLength = 0;
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
mNoteHeaderHolder.textNum.setText("字数:" + currentLength);
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
currentLength = textChange(mNoteEditor.getText().toString()).length();
}
@Override
public void afterTextChanged(Editable s) {
mNoteHeaderHolder.textNum.setText("字数:" + currentLength);
}
});
}*/
/**
*在 Activity 创建时进行一些初始化工作,包括设置布局、初始化状态和资源等操作
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.note_edit);
if (savedInstanceState == null && !initActivityState(getIntent())) {
finish();
return;
}
initResources();
initRichEditor();
//count();
}
/**
* Current activity may be killed when the memory is low. Once it is killed, for another time
* user load this activity, we should restore the former state
*/
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState != null && savedInstanceState.containsKey(Intent.EXTRA_UID)) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.putExtra(Intent.EXTRA_UID, savedInstanceState.getLong(Intent.EXTRA_UID));
if (!initActivityState(intent)) {
finish();
return;
}
Log.d(TAG, "Restoring from killed activity");
}
}
private boolean initActivityState(Intent intent) {
/**
* If the user specified the {@link Intent#ACTION_VIEW} but not provided with id,
* then jump to the NotesListActivity
*/
mWorkingNote = null;
if (TextUtils.equals(Intent.ACTION_VIEW, intent.getAction())) {
long noteId = intent.getLongExtra(Intent.EXTRA_UID, 0);
mUserQuery = "";
/**
* Starting from the searched result
*/
//根据键值查找ID
if (intent.hasExtra(SearchManager.EXTRA_DATA_KEY)) {
noteId = Long.parseLong(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY));
mUserQuery = intent.getStringExtra(SearchManager.USER_QUERY);
}
//如果ID在数据库中未找到
if (!DataUtils.visibleInNoteDatabase(getContentResolver(), noteId, Notes.TYPE_NOTE)) {
Intent jump = new Intent(this, NotesListActivity.class);
startActivity(jump);
//程序将跳转到上面声明的intent——jump
showToast(R.string.error_note_not_exist);
finish();
return false;
}
//ID在数据库中找到
else {
mWorkingNote = WorkingNote.load(this, noteId);
if (mWorkingNote == null) {
Log.e(TAG, "load note failed with note id" + noteId);
//打印出红色的错误信息
finish();
return false;
}
}
getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN
| WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
} else if(TextUtils.equals(Intent.ACTION_INSERT_OR_EDIT, intent.getAction())) {
long folderId = intent.getLongExtra(Notes.INTENT_EXTRA_FOLDER_ID, 0);
int widgetId = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
int widgetType = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_TYPE,
Notes.TYPE_WIDGET_INVALIDE);
int bgResId = intent.getIntExtra(Notes.INTENT_EXTRA_BACKGROUND_ID,
ResourceParser.getDefaultBgId(this));
String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
long callDate = intent.getLongExtra(Notes.INTENT_EXTRA_CALL_DATE, 0);
if (callDate != 0 && phoneNumber != null) {
if (TextUtils.isEmpty(phoneNumber)) {
Log.w(TAG, "The call record number is null");
}
long noteId = 0;
if ((noteId = DataUtils.getNoteIdByPhoneNumberAndCallDate(getContentResolver(),
phoneNumber, callDate)) > 0) {
mWorkingNote = WorkingNote.load(this, noteId);
if (mWorkingNote == null) {
Log.e(TAG, "load call note failed with note id" + noteId);
finish();
return false;
}
} else {
mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId,
widgetType, bgResId);
mWorkingNote.convertToCallNote(phoneNumber, callDate);
}
} else {
mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId, widgetType,
bgResId);
}
getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
| WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
} else {
Log.e(TAG, "Intent not specified action, should not support");
finish();
return false;
}
mWorkingNote.setOnSettingStatusChangedListener(this);
return true;
}
@Override
protected void onResume() {
super.onResume();
initNoteScreen();
}
/**
* @method initNoteScreen
* @description 初始化笔记页面
* @date: 12/24/2023 6:24 PM
* @author: YangYizhe
*/
private void initNoteScreen() {
mNoteEditor.setEditorFontSize(30);
if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) {
switchToListMode(mWorkingNote.getContent());
} else {
mNoteEditor.setHtml(String.valueOf(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)));
//mNoteEditor.setSelection(mText.length());
}
for (Integer id : sBgSelectorSelectionMap.keySet()) {
findViewById(sBgSelectorSelectionMap.get(id)).setVisibility(View.GONE);
}
mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId());
mNoteEditorPanel.setBackgroundResource(mWorkingNote.getBgColorResId());
mNoteHeaderHolder.tvModified.setText(DateUtils.formatDateTime(this,
mWorkingNote.getModifiedDate(), DateUtils.FORMAT_SHOW_DATE
| DateUtils.FORMAT_NUMERIC_DATE | DateUtils.FORMAT_SHOW_TIME
| DateUtils.FORMAT_SHOW_YEAR));
/**
* TODO: Add the menu for setting alert. Currently disable it because the DateTimePicker
* is not ready
*/
showAlertHeader();
}
/**
* @method showAlertHeader
* @description
* 根据当前便签是否设置了提醒时间来显示或隐藏提醒信息头部
* 如果设置了提醒时间,会根据当前时间判断提醒是否过期
* 如果已经过期,则在头部显示“已过期”字样
* 否则在头部显示距离提醒时间还有多长时间,同时显示一个提醒图标。
* 如果没有设置提醒时间,则隐藏提醒信息头部。
* @date: 12/24/2023 6:24 PM
* @author: YangYizhe
*/
private void showAlertHeader() {
if (mWorkingNote.hasClockAlert()) {
long time = System.currentTimeMillis();
if (time > mWorkingNote.getAlertDate()) {
mNoteHeaderHolder.tvAlertDate.setText(R.string.note_alert_expired);
}
else {
mNoteHeaderHolder.tvAlertDate.setText(DateUtils.getRelativeTimeSpanString(
mWorkingNote.getAlertDate(), time, DateUtils.MINUTE_IN_MILLIS));
}
mNoteHeaderHolder.tvAlertDate.setVisibility(View.VISIBLE);
mNoteHeaderHolder.ivAlertIcon.setVisibility(View.VISIBLE);
} else {
mNoteHeaderHolder.tvAlertDate.setVisibility(View.GONE);
mNoteHeaderHolder.ivAlertIcon.setVisibility(View.GONE);
};
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
initActivityState(intent);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
/**
* For new note without note id, we should firstly save it to
* generate a id. If the editing note is not worth saving, there
* is no id which is equivalent to create new note
*/
if (!mWorkingNote.existInDatabase()) {
saveNote();
}
outState.putLong(Intent.EXTRA_UID, mWorkingNote.getNoteId());
Log.d(TAG, "Save working note id: " + mWorkingNote.getNoteId() + " onSaveInstanceState");
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (mNoteBgColorSelector.getVisibility() == View.VISIBLE
&& !inRangeOfView(mNoteBgColorSelector, ev)) {
mNoteBgColorSelector.setVisibility(View.GONE);
return true;
}
if (mFontSizeSelector.getVisibility() == View.VISIBLE
&& !inRangeOfView(mFontSizeSelector, ev)) {
mFontSizeSelector.setVisibility(View.GONE);
return true;
}
return super.dispatchTouchEvent(ev);
}
private boolean inRangeOfView(View view, MotionEvent ev) {
int []location = new int[2];
view.getLocationOnScreen(location);
int x = location[0];
int y = location[1];
if (ev.getX() < x
|| ev.getX() > (x + view.getWidth())
|| ev.getY() < y
|| ev.getY() > (y + view.getHeight()))
{
return false;
}
return true;
}
private void initResources() {
mHeadViewPanel = findViewById(R.id.note_title);
mNoteHeaderHolder = new HeadViewHolder();
mNoteHeaderHolder.tvModified = (TextView) findViewById(R.id.tv_modified_date);
mNoteHeaderHolder.ivAlertIcon = (ImageView) findViewById(R.id.iv_alert_icon);
mNoteHeaderHolder.tvAlertDate = (TextView) findViewById(R.id.tv_alert_date);
mNoteHeaderHolder.ibSetBgColor = (ImageView) findViewById(R.id.btn_set_bg_color);
mNoteHeaderHolder.textNum = (TextView) findViewById(R.id.text_num);
mNoteHeaderHolder.ibSetBgColor.setOnClickListener(this);
mNoteEditor = findViewById(R.id.note_edit_view);
mNoteEditor.setOnTextChangeListener(new RichEditor.OnTextChangeListener() {
@Override
public void onTextChange(String text) {
mText = text;
mNoteLength = removeBlank(textChange(mText)).length();
mNoteHeaderHolder.tvModified.setText(DateUtils.formatDateTime(NoteEditActivity.this,
mWorkingNote.getModifiedDate(), DateUtils.FORMAT_SHOW_DATE
| DateUtils.FORMAT_NUMERIC_DATE | DateUtils.FORMAT_SHOW_TIME
| DateUtils.FORMAT_SHOW_YEAR)+"\n字符数"+mNoteLength);
}
});
mNoteEditorPanel = findViewById(R.id.sv_note_edit);
mNoteBgColorSelector = findViewById(R.id.note_bg_color_selector);
for (int id : sBgSelectorBtnsMap.keySet()) {
ImageView iv = (ImageView) findViewById(id);
iv.setOnClickListener(this);
}
mFontSizeSelector = findViewById(R.id.font_size_selector);
for (int id : sFontSizeBtnsMap.keySet()) {
View view = findViewById(id);
view.setOnClickListener(this);
};
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
mFontSizeId = mSharedPrefs.getInt(PREFERENCE_FONT_SIZE, ResourceParser.BG_DEFAULT_FONT_SIZE);
/**
* HACKME: Fix bug of store the resource id in shared preference.
* The id may larger than the length of resources, in this case,
* return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE}
*/
if(mFontSizeId >= TextAppearanceResources.getResourcesSize()) {
mFontSizeId = ResourceParser.BG_DEFAULT_FONT_SIZE;
}
mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list);
}
@Override
protected void onPause() {
super.onPause();
if(saveNote()) {
Log.d(TAG, "Note data was saved with length:" + mWorkingNote.getContent().length());
}
clearSettingState();
}
/**
* @method updateWidget
* @description 更新小部件的操作
* @date: 12/24/2023 6:21 PM
* @author: YangYizhe
*/
private void updateWidget() {
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_2X) {
intent.setClass(this, NoteWidgetProvider_2x.class);
} else if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_4X) {
intent.setClass(this, NoteWidgetProvider_4x.class);
} else {
Log.e(TAG, "Unspported widget type");
return;
}
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {
mWorkingNote.getWidgetId()
});
sendBroadcast(intent);
setResult(RESULT_OK, intent);
}
public void onClick(View v) {
int id = v.getId();
if (id == R.id.btn_set_bg_color) {
mNoteBgColorSelector.setVisibility(View.VISIBLE);
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(
View.VISIBLE);
} else if (sBgSelectorBtnsMap.containsKey(id)) {
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(
View.GONE);
mWorkingNote.setBgColorId(sBgSelectorBtnsMap.get(id));
mNoteBgColorSelector.setVisibility(View.GONE);
} else if (sFontSizeBtnsMap.containsKey(id)) {
findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.GONE);
mFontSizeId = sFontSizeBtnsMap.get(id);
mSharedPrefs.edit().putInt(PREFERENCE_FONT_SIZE, mFontSizeId).commit();
findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE);
if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) {
getWorkingText();
switchToListMode(mWorkingNote.getContent());
} else {
mNoteEditor.setEditorFontSize(mFontSizeId);
}
mFontSizeSelector.setVisibility(View.GONE);
}
}
@Override
public void onBackPressed() {
if(clearSettingState()) {
return;
}
saveNote();
super.onBackPressed();
}
/**
* @method clearSettingState
* @description 清除设置状态,
* @date: 12/24/2023 6:22 PM
* @author: YangYizhe
* @return boolean 返回是否成功清除设置状态
*/
private boolean clearSettingState() {
if (mNoteBgColorSelector.getVisibility() == View.VISIBLE) {
mNoteBgColorSelector.setVisibility(View.GONE);
return true;
} else if (mFontSizeSelector.getVisibility() == View.VISIBLE) {
mFontSizeSelector.setVisibility(View.GONE);
return true;
}
return false;
}
/**
* @method onBackgroundColorChanged
* @description 当背景颜色改变时调用
* @date: 12/24/2023 6:23 PM
* @author: YangYizhe
*/
public void onBackgroundColorChanged() {
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(
View.VISIBLE);
mNoteEditorPanel.setBackgroundResource(mWorkingNote.getBgColorResId());
mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId());
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (isFinishing()) {
return true;
}
clearSettingState();
menu.clear();
if (mWorkingNote.getFolderId() == Notes.ID_CALL_RECORD_FOLDER) {
getMenuInflater().inflate(R.menu.call_note_edit, menu);
} else {
getMenuInflater().inflate(R.menu.note_edit, menu);
}
if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) {
menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_normal_mode);
} else {
menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_list_mode);
}
if (mWorkingNote.hasClockAlert()) {
menu.findItem(R.id.menu_alert).setVisible(false);
} else {
menu.findItem(R.id.menu_delete_remind).setVisible(false);
}
return true;
}
@Override
/**
* @method onOptionsItemSelected
* @description 处理菜单项选择的操作
* @date: 12/24/2023 6:21 PM
* @author: YangYizhe
* @param [item] 被选中的菜单项
* @return boolean 返回操作是否成功
*/
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
if (itemId == R.id.menu_new_note) {
createNewNote();
} else if (itemId == R.id.menu_delete) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.alert_title_delete));
builder.setIcon(android.R.drawable.ic_dialog_alert);
builder.setMessage(getString(R.string.alert_message_delete_note));
builder.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
deleteCurrentNote();
finish();
}
});
builder.setNegativeButton(android.R.string.cancel, null);
builder.show();
} else if (itemId == R.id.menu_font_size) {
mFontSizeSelector.setVisibility(View.VISIBLE);
findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE);
} else if (itemId == R.id.menu_list_mode) {
mWorkingNote.setCheckListMode(mWorkingNote.getCheckListMode() == 0 ?
TextNote.MODE_CHECK_LIST : 0);
} else if (itemId == R.id.menu_share) {
getWorkingText();
sendTo(this, mWorkingNote.getContent());
} else if (itemId == R.id.menu_send_to_desktop) {
sendToDesktop();
} else if (itemId == R.id.menu_alert) {
setReminder();
} else if (itemId == R.id.menu_delete_remind) {
mWorkingNote.setAlertDate(0, false);
}
return true;
}
/**
* @method setReminder
* @description 设置提醒Remind me
* @date: 12/21/2023 8:04 AM
* @author: YangYizhe
*/
private void setReminder() {
DateTimePickerDialog d = new DateTimePickerDialog(this, System.currentTimeMillis());
d.setOnDateTimeSetListener(new OnDateTimeSetListener() {
public void OnDateTimeSet(AlertDialog dialog, long date) {
mWorkingNote.setAlertDate(date , true);
//选择提醒的日期
}
});
d.show();
}
/**
* Share note to apps that support {@link Intent#ACTION_SEND} action
* and {@text/plain} type
*/
private void sendTo(Context context, String info) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_TEXT, info);
intent.setType("text/plain");
context.startActivity(intent);
}
private void createNewNote() {
// Firstly, save current editing notes
saveNote();
// For safety, start a new NoteEditActivity
finish();
Intent intent = new Intent(this, NoteEditActivity.class);
intent.setAction(Intent.ACTION_INSERT_OR_EDIT);
intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mWorkingNote.getFolderId());
startActivity(intent);
}
private void deleteCurrentNote() {
if (mWorkingNote.existInDatabase()) {
HashSet<Long> ids = new HashSet<Long>();
long id = mWorkingNote.getNoteId();
if (id != Notes.ID_ROOT_FOLDER) {
ids.add(id);
} else {
Log.d(TAG, "Wrong note id, should not happen");
}
if (!isSyncMode()) {
if (!DataUtils.batchDeleteNotes(getContentResolver(), ids)) {
Log.e(TAG, "Delete Note error");
}
} else {
if (!DataUtils.batchMoveToFolder(getContentResolver(), ids, Notes.ID_TRASH_FOLER)) {
Log.e(TAG, "Move notes to trash folder error, should not happens");
}
}
}
mWorkingNote.markDeleted(true);
}
private boolean isSyncMode() {
return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0;
}
public void onClockAlertChanged(long date, boolean set) {
/**
* User could set clock to an unsaved note, so before setting the
* alert clock, we should save the note first
*/
if (!mWorkingNote.existInDatabase()) {
saveNote();
}
if (mWorkingNote.getNoteId() > 0) {
Intent intent = new Intent(this, AlarmReceiver.class);
intent.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mWorkingNote.getNoteId()));
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
AlarmManager alarmManager = ((AlarmManager) getSystemService(ALARM_SERVICE));
showAlertHeader();
if(!set) {
alarmManager.cancel(pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, date, pendingIntent);
}
} else {
/**
* There is the condition that user has input nothing (the note is
* not worthy saving), we have no note id, remind the user that he
* should input something
*/
Log.e(TAG, "Clock alert setting error");
showToast(R.string.error_note_empty_for_clock);
}
}
/**
* 当小部件发生改变时调用updateWidget
*/
public void onWidgetChanged() {
updateWidget();
}
/**
* @method onEditTextDelete
* @description 删除文本框的操作
* @date: 12/24/2023 6:19 PM
* @author: YangYizhe
* @param index 文本框索引
* @param text 文本框中的文本内容
*/
public void onEditTextDelete(int index, String text) {
int childCount = mEditTextList.getChildCount();
if (childCount == 1) {
return;
}
for (int i = index + 1; i < childCount; i++) {
((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text))
.setIndex(i - 1);
}
mEditTextList.removeViewAt(index);
NoteEditText edit = null;
if(index == 0) {
edit = (NoteEditText) mEditTextList.getChildAt(0).findViewById(
R.id.et_edit_text);
} else {
edit = (NoteEditText) mEditTextList.getChildAt(index - 1).findViewById(
R.id.et_edit_text);
}
int length = edit.length();
edit.append(text);
edit.requestFocus();
edit.setSelection(length);
}
/**
* @method onEditTextEnter
* @description 编辑文本框中按下回车键的操作
* @date: 12/24/2023 6:19 PM
* @author: YangYizhe
* @param index 文本框索引
* @param text 文本框中的文本内容
*/
public void onEditTextEnter(int index, String text) {
/**
* Should not happen, check for debug
*/
if(index > mEditTextList.getChildCount()) {
Log.e(TAG, "Index out of mEditTextList boundrary, should not happen");
}
View view = getListItem(text, index);
mEditTextList.addView(view, index);
NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text);
edit.requestFocus();
edit.setSelection(0);
for (int i = index + 1; i < mEditTextList.getChildCount(); i++) {
((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text))
.setIndex(i);
}
}
/**
* @method switchToListMode
* @description 切换到列表模式
* @date: 12/24/2023 6:19 PM
* @author: YangYizhe
* @param text 列表文本
*/
private void switchToListMode(String text) {
mEditTextList.removeAllViews();
String[] items = text.split("\n");
int index = 0;
for (String item : items) {
if(!TextUtils.isEmpty(item)) {
mEditTextList.addView(getListItem(item, index));
index++;
}
}
mEditTextList.addView(getListItem("", index));
mEditTextList.getChildAt(index).findViewById(R.id.et_edit_text).requestFocus();
mNoteEditor.setVisibility(View.GONE);
mEditTextList.setVisibility(View.VISIBLE);
}
/**
* @param fullText 完整文本
* @param userQuery 用户查询关键词
* @return 带有高亮效果的 Spannable 对象
* @method getHighlightQueryResult
* @description 获取高亮查询结果
* @date: 12/24/2023 6:18 PM
* @author: YangYizhe
*/
private SpannableString getHighlightQueryResult(String fullText, String userQuery) {
SpannableString spannable = new SpannableString(fullText == null ? "" : fullText);
if (!TextUtils.isEmpty(userQuery)) {
mPattern = Pattern.compile(userQuery);
Matcher m = mPattern.matcher(fullText);
int start = 0;
while (m.find(start)) {
spannable.setSpan(
new BackgroundColorSpan(this.getResources().getColor(
R.color.user_query_highlight)), m.start(), m.end(),
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
start = m.end();
}
}
return spannable;
}
/**
* @method getListItem
* @description 获取列表项视图
* @date: 12/24/2023 6:17 PM
* @author: YangYizhe
* @param item 列表项内容
* @param index 列表项索引
* @return 列表项视图
*/
private View getListItem(String item, int index) {
View view = LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null);
final NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text);
edit.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId));
CheckBox cb = ((CheckBox) view.findViewById(R.id.cb_edit_item));
cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
} else {
edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
}
}
});
if (item.startsWith(TAG_CHECKED)) {
cb.setChecked(true);
edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
item = item.substring(TAG_CHECKED.length(), item.length()).trim();
} else if (item.startsWith(TAG_UNCHECKED)) {
cb.setChecked(false);
edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
item = item.substring(TAG_UNCHECKED.length(), item.length()).trim();
}
edit.setOnTextViewChangeListener(this);
edit.setIndex(index);
edit.setText(getHighlightQueryResult(item, mUserQuery));
return view;
}
/**
* @method onTextChange
* @description 当文本内容发生变化时的处理方法
* @date: 12/24/2023 6:17 PM
* @author: YangYizhe
* @param index 文本索引
* @param hasText 是否有文本内容
*/
public void onTextChange(int index, boolean hasText) {
if (index >= mEditTextList.getChildCount()) {
Log.e(TAG, "Wrong index, should not happen");
return;
}
if(hasText) {
mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.VISIBLE);
} else {
mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.GONE);
}
}
/**
* @method onCheckListModeChanged
* @description 当检查列表模式发生变化时的处理方法
* @date: 12/24/2023 6:17 PM
* @author: YangYizhe
* @param oldMode 旧的模式
* @param newMode 新的模式
*/
public void onCheckListModeChanged(int oldMode, int newMode) {
if (newMode == TextNote.MODE_CHECK_LIST) {
switchToListMode(textChange(mText));
} else {
if (!getWorkingText()) {
mWorkingNote.setWorkingText(mWorkingNote.getContent().replace(TAG_UNCHECKED + " ",
""));
}
mNoteEditor.setHtml(String.valueOf(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)));
mEditTextList.setVisibility(View.GONE);
mNoteEditor.setVisibility(View.VISIBLE);
}
}
/**
* @method getWorkingText
* @description 获取正在编辑的文本内容
* @date: 12/24/2023 6:12 PM
* @author: YangYizhe
* @return 是否存在已打钩的选项
*/
private boolean getWorkingText() {
boolean hasChecked = false;//初始化check标记
if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) {
/**
* 若模式为CHECK_LIST
* 先创建可变字符串
* 遍历所有子编辑框的视图
*/
StringBuilder sb = new StringBuilder();
for (int i = 0; i < mEditTextList.getChildCount(); i++) {
View view = mEditTextList.getChildAt(i);
NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text);
if (!TextUtils.isEmpty(edit.getText())) {
/**
* 若文本不为空
* 该选项框已打钩
* 扩展字符串为已打钩并把标记置true
*/
if (((CheckBox) view.findViewById(R.id.cb_edit_item)).isChecked()) {
sb.append(TAG_CHECKED).append(" ").append(edit.getText()).append("\n");
hasChecked = true;
} else {
//扩展字符串添加未打钩
sb.append(TAG_UNCHECKED).append(" ").append(edit.getText()).append("\n");
}
}
}
mWorkingNote.setWorkingText(sb.toString());//利用编辑好的字符串设置运行便签的内容
} else {// 若不是该模式直接用编辑器中的内容设置运行中标签的内容
mWorkingNote.setWorkingText(textChange(mText));
}
return hasChecked;
}
/**
* @method saveNote
* @description
* 保存便签,退出时候会自动调本函数
* @date: 12/21/2023 8:14 AM
* @author: YangYizhe
*/
private boolean saveNote() {
getWorkingText();
boolean saved = mWorkingNote.saveNote();
if (TextUtils.isEmpty(mWorkingNote.getContent())) {
deleteCurrentNote();//删除当前便签
saved = false; // 标记为未保存
}
//运行 getWorkingText()之后保存
if (saved) {
/**
* There are two modes from List view to edit view, open one note,
* create/edit a node. Opening node requires to the original
* position in the list when back from edit view, while creating a
* new node requires to the top of the list. This code
* {@link #RESULT_OK} is used to identify the create/edit state
*/
//如英文注释所说链接RESULT_OK是为了识别保存的2种情况一是创建后保存二是修改后保存
setResult(RESULT_OK);
}
return saved;
}
/**
* @method sendToDesktop
* @description
* send to home功能发到桌面上
* @date: 12/21/2023 8:15 AM
* @author: YangYizhe
*/
private void sendToDesktop() {
/**
* Before send message to home, we should make sure that current
* editing note is exists in databases. So, for new note, firstly
* save it
*/
if (!mWorkingNote.existInDatabase()) {
saveNote();
}
if (mWorkingNote.getNoteId() > 0) {
Intent sender = new Intent();
Intent shortcutIntent = new Intent(this, NoteEditActivity.class);
shortcutIntent.setAction(Intent.ACTION_VIEW);
shortcutIntent.putExtra(Intent.EXTRA_UID, mWorkingNote.getNoteId());
sender.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
sender.putExtra(Intent.EXTRA_SHORTCUT_NAME,
makeShortcutIconTitle(mWorkingNote.getContent()));
sender.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
Intent.ShortcutIconResource.fromContext(this, R.drawable.icon_app));
sender.putExtra("duplicate", true);
sender.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
showToast(R.string.info_note_enter_desktop);
sendBroadcast(sender);
} else {
/**
* There is the condition that user has input nothing (the note is
* not worthy saving), we have no note id, remind the user that he
* should input something
*/
Log.e(TAG, "Send to desktop error");
showToast(R.string.error_note_empty_for_send_to_desktop);
}
}
/**
* @method makeShortcutIconTitle
* @description 生成快捷方式图标标题
* @date: 12/24/2023 6:11 PM
* @author: YangYizhe
* @param content 内容
* @return 生成的快捷方式图标标题
*/
private String makeShortcutIconTitle(String content) {
content = content.replace(TAG_CHECKED, "");
content = content.replace(TAG_UNCHECKED, "");
return content.length() > SHORTCUT_ICON_TITLE_MAX_LEN ? content.substring(0,
SHORTCUT_ICON_TITLE_MAX_LEN) : content;
}
private void showToast(int resId) {
showToast(resId, Toast.LENGTH_SHORT);
}
private void showToast(int resId, int duration) {
Toast.makeText(this, resId, duration).show();
}
/**
* @method convertToImage
* @description: 路径字符串格式 转换为 图片image格式
* @date: 2024/1/3 19:19
* @author: WuShuxian
* @param: void
* @return: void
*/
/**private void convertToImage() {
NoteEditText noteEditText = (NoteEditText) findViewById(R.id.note_edit_view); //获取当前的edit
Editable editable = noteEditText.getText();//1.获取text
String noteText = editable.toString(); //2.将note内容转换为字符串
int length = editable.length(); //内容的长度
//3.截取img片段 [local]+uri+[/local]提取uri。算法效率有待改善可以考虑KMP
for(int i = 0; i < length; i++) {
for(int j = i; j < length; j++) {
String img_fragment = noteText.substring(i, j+1); //img_fragment关于图片路径的片段
if(img_fragment.length() > 15 && img_fragment.endsWith("[/local]") &&
img_fragment.startsWith("[local]")){
int limit = 7; //[local]为7个字符
int len = img_fragment.length()-15;//[local][/local]共15个字符剩下的为真正的path长度
String path = img_fragment.substring(limit,limit+len);//获取到了图片路径从[local]之后的len个字符就是path
Bitmap bitmap = null;
Log.d(TAG, "图片的路径是:"+path);
try {
bitmap = BitmapFactory.decodeFile(path);//将图片路径解码为图片格式
} catch (Exception e) {
e.printStackTrace();
}
//若图片存在
if(bitmap!=null){
Log.d(TAG, "图片不为null");
ImageSpan imageSpan = new ImageSpan(NoteEditActivity.this, bitmap);
String ss = "[local]" + path + "[/local]";
SpannableString spannableString = new SpannableString(ss);//4.创建一个SpannableString对象以便插入用ImageSpan对象封装的图像
spannableString.setSpan(imageSpan, 0, ss.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);//5.将指定的标记对象附加到文本的开始...结束范围
Log.d(TAG, "Create spannable string success!");
Editable edit_text = noteEditText.getEditableText();
edit_text.delete(i,i+len+15); //6.删掉图片路径的文字
edit_text.insert(i, spannableString); //7.在路径的起始位置插入图片
}
}
}
}
}*/
/**
* @method onActivityResult
* @description: 插入图片时重写onActivityResult()来处理返回的数据,点击插入图片返回后执行
* @date: 2024/1/3 19:20
* @author: WuShuxian
* @param:
* @return: void
*/
/**@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
ContentResolver resolver = getContentResolver();
switch (requestCode) {
case PHOTO_REQUEST:
Uri originalUri = intent.getData(); //1.获得图片的真实路径
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream(resolver.openInputStream(originalUri));//2.解码图片
} catch (FileNotFoundException e) {
Log.d(TAG, "onActivityResult: get file_exception");
e.printStackTrace();
}
//3.根据Bitmap对象创建ImageSpan对象
if(bitmap != null){
Log.d(TAG, "onActivityResult: bitmap is not null");
ImageSpan imageSpan = new ImageSpan(NoteEditActivity.this, bitmap);
String path = getPath(this,originalUri);
String img_fragment= "[local]" + path + "[/local]";//4.使用[local][/local]将path括起来用于之后方便识别图片路径在note中的位置
SpannableString spannableString = new SpannableString(img_fragment);//创建一个SpannableString对象以便插入用ImageSpan对象封装的图像
spannableString.setSpan(imageSpan, 0,
img_fragment.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
NoteEditText e = (NoteEditText) findViewById(R.id.note_edit_view);//5.将选择的图片追加到EditText中光标所在位置
int index = e.getSelectionStart(); //获取光标所在位置
Log.d(TAG, "Index是: " + index);
Editable edit_text = e.getEditableText();
edit_text.insert(index, spannableString); //将图片插入到光标所在位置
mWorkingNote.setWorkingText(e.getText().toString());
//6.把改动提交到数据库中,两个数据库表都要改的
ContentResolver contentResolver = getContentResolver();
ContentValues contentValues = new ContentValues();
final long id = mWorkingNote.getNoteId();
contentValues.put("snippet",mWorkingNote.getContent());
contentResolver.update(Uri.parse("content://micode_notes/note"),
contentValues,"_id=?",new String[]{""+id});
ContentValues contentValues1 = new ContentValues();
contentValues1.put("content",mWorkingNote.getContent());
contentResolver.update(Uri.parse("content://micode_notes/data"),
contentValues1,"mime_type=? and note_id=?",
new String[]{"vnd.android.cursor.item/text_note",""+id});
}else{
Toast.makeText(NoteEditActivity.this, "获取图片失败", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}*/
/**
* @method getPath
* @description: 获取文件的real path
* @date: 2024/1/3 19:22
* @author: WuShuxian
* @param:
* @return:
*/
/**public String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// Media
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}*/
/**
* @method isMediaDocument
* @description: 判断是否为媒体文件
* @date: 2024/1/3 19:23
* @author: WuShuxian
* @param: uri
* @return:
*/
/**public boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
/**
* @method getDataColumn
* @description: 获取数据列_获取此 Uri 的数据列的值。这对MediaStore Uris 和其他基于文件的 ContentProvider。
* @date: 2024/1/3 19:23
* @author: WuShuxian
* @param:
* @return:
*/
/**public String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {column};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @method checkStoragePermissions
* @description: 用于动态申请权限
* @date: 2024/1/6 8:58
* @author: WuShuxian
* @param: activity
* @return: void
*/
/**public static void checkStoragePermissions(Activity activity){
try{
//监测是否有写/读的权限
int permission= ActivityCompat.checkSelfPermission(activity,
"android.permission.WRITE_EXTERNAL_STORAGE");
int permission1= ActivityCompat.checkSelfPermission(activity,
"android.permission.READ_EXTERNAL_STORAGE");
if(permission != PackageManager.PERMISSION_GRANTED){
//没有写的权限,去申请写的权限,或弹出对话框
ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE,REQUEST_EXTERNAL_STORAGE);
}
if(permission1 != PackageManager.PERMISSION_GRANTED){
//没有读的权限,去申请读的权限,或弹出对话框
ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE,REQUEST_EXTERNAL_STORAGE);
}
}catch (Exception e){
e.printStackTrace();
}
}
/**
* @method textToSpeach
* @description: 朗读功能
* @date: 2024/1/16 20:21
* @author: WuShuxian
*/
/**private void textToSpeach(){
mTTS.speak(mNoteEditor.getText().toString(),TextToSpeech.QUEUE_FLUSH,null);
}*/
}