Compare commits

..

1 Commits

Author SHA1 Message Date
曹馨语 7ab1c7a154 add
1 month ago

Binary file not shown.

@ -1,175 +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.
*/
// 包声明,表明该类属于 net.micode.notes.ui 包
package net.micode.notes.ui;
// 导入 Java 标准库中的 Calendar 类,用于处理日期和时间
import java.util.Calendar;
// 导入项目中的资源类 R
import net.micode.notes.R;
// 导入自定义的 DateTimePicker 类
import net.micode.notes.ui.DateTimePicker;
// 导入自定义的 DateTimePicker 类中的 OnDateTimeChangedListener 接口
import net.micode.notes.ui.DateTimePicker.OnDateTimeChangedListener;
// 导入 Android 系统的 AlertDialog 类,用于创建对话框
import android.app.AlertDialog;
// 导入 Android 系统的 Context 类,用于获取应用程序的上下文信息
import android.content.Context;
// 导入 Android 系统的 DialogInterface 类,用于处理对话框的交互事件
import android.content.DialogInterface;
// 导入 DialogInterface 中的 OnClickListener 接口,用于处理点击事件
import android.content.DialogInterface.OnClickListener;
// 导入 Android 系统的 DateFormat 类,用于格式化日期和时间
import android.text.format.DateFormat;
// 导入 Android 系统的 DateUtils 类,用于处理日期和时间的工具类
import android.text.format.DateUtils;
/**
* DateTimePickerDialog AlertDialog
* OnDateTimeSetListener
*/
public class DateTimePickerDialog extends AlertDialog implements OnClickListener {
// 用于存储当前选择的日期和时间
private Calendar mDate = Calendar.getInstance();
// 标记是否使用 24 小时制显示时间
private boolean mIs24HourView;
// 日期和时间选择完成后的回调接口
private OnDateTimeSetListener mOnDateTimeSetListener;
// 自定义的日期和时间选择器视图
private DateTimePicker mDateTimePicker;
/**
* OnDateTimeSetListener OnDateTimeSet
*
*/
public interface OnDateTimeSetListener {
/**
*
* @param dialog
* @param date
*/
void OnDateTimeSet(AlertDialog dialog, long date);
}
/**
* DateTimePickerDialog
* @param context
* @param date
*/
public DateTimePickerDialog(Context context, long date) {
// 调用父类 AlertDialog 的构造函数
super(context);
// 创建自定义的 DateTimePicker 实例
mDateTimePicker = new DateTimePicker(context);
// 将 DateTimePicker 设置为对话框的视图
setView(mDateTimePicker);
// 为 DateTimePicker 设置日期和时间改变的监听器
mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() {
/**
* mDate
* @param view DateTimePicker
* @param year
* @param month
* @param dayOfMonth
* @param hourOfDay
* @param minute
*/
public void onDateTimeChanged(DateTimePicker view, int year, int month,
int dayOfMonth, int hourOfDay, int minute) {
// 更新 mDate 对象的年份
mDate.set(Calendar.YEAR, year);
// 更新 mDate 对象的月份
mDate.set(Calendar.MONTH, month);
// 更新 mDate 对象的日期
mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth);
// 更新 mDate 对象的小时
mDate.set(Calendar.HOUR_OF_DAY, hourOfDay);
// 更新 mDate 对象的分钟
mDate.set(Calendar.MINUTE, minute);
// 调用 updateTitle 方法更新对话框的标题
updateTitle(mDate.getTimeInMillis());
}
});
// 设置 mDate 对象的时间为传入的日期和时间
mDate.setTimeInMillis(date);
// 将秒数设置为 0
mDate.set(Calendar.SECOND, 0);
// 设置 DateTimePicker 的当前日期和时间
mDateTimePicker.setCurrentDate(mDate.getTimeInMillis());
// 设置对话框的确定按钮,并设置点击监听器为当前类实例
setButton(context.getString(R.string.datetime_dialog_ok), this);
// 设置对话框的取消按钮,不设置点击监听器
setButton2(context.getString(R.string.datetime_dialog_cancel), (OnClickListener)null);
// 根据系统设置判断是否使用 24 小时制
set24HourView(DateFormat.is24HourFormat(this.getContext()));
// 调用 updateTitle 方法更新对话框的标题
updateTitle(mDate.getTimeInMillis());
}
/**
* 使 24
* @param is24HourView 使 24
*/
public void set24HourView(boolean is24HourView) {
mIs24HourView = is24HourView;
}
/**
*
* @param callBack OnDateTimeSetListener
*/
public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) {
mOnDateTimeSetListener = callBack;
}
/**
*
* @param date
*/
private void updateTitle(long date) {
// 定义日期和时间格式化的标志
int flag =
// 显示年份
DateUtils.FORMAT_SHOW_YEAR |
// 显示日期
DateUtils.FORMAT_SHOW_DATE |
// 显示时间
DateUtils.FORMAT_SHOW_TIME;
// 根据是否使用 24 小时制添加相应的标志
flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_24HOUR;
// 使用 DateUtils 格式化日期和时间,并设置为对话框的标题
setTitle(DateUtils.formatDateTime(this.getContext(), date, flag));
}
/**
*
* OnDateTimeSet
* @param arg0 DialogInterface
* @param arg1
*/
public void onClick(DialogInterface arg0, int arg1) {
// 检查回调接口是否为空
if (mOnDateTimeSetListener != null) {
// 调用回调接口的 OnDateTimeSet 方法传递选择的日期和时间
mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis());
}
}
}

@ -1,116 +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.
*/
// 声明该类所在的包,表明该类属于 net.micode.notes.ui 模块
package net.micode.notes.ui;
// 导入 Android 上下文类,用于获取应用程序环境信息
import android.content.Context;
// 导入 Android 菜单类,用于创建和管理菜单
import android.view.Menu;
// 导入 Android 菜单项类,用于表示菜单中的每一项
import android.view.MenuItem;
// 导入 Android 视图类,是所有 UI 组件的基类
import android.view.View;
// 导入 Android 视图点击监听器接口,用于处理视图的点击事件
import android.view.View.OnClickListener;
// 导入 Android 按钮类,用于创建可点击的按钮
import android.widget.Button;
// 导入 Android 弹出菜单类,用于创建弹出式菜单
import android.widget.PopupMenu;
// 导入 Android 弹出菜单项点击监听器接口,用于处理弹出菜单项的点击事件
import android.widget.PopupMenu.OnMenuItemClickListener;
// 导入应用资源类,用于访问应用中的资源,如布局、字符串等
import net.micode.notes.R;
/**
* DropdownMenu
*/
public class DropdownMenu {
// 声明一个按钮对象,用于触发下拉菜单的显示
private Button mButton;
// 声明一个弹出菜单对象,用于显示下拉菜单的内容
private PopupMenu mPopupMenu;
// 声明一个菜单对象,用于管理弹出菜单中的菜单项
private Menu mMenu;
/**
*
*
* @param context
* @param button
* @param menuId ID
*/
public DropdownMenu(Context context, Button button, int menuId) {
// 将传入的按钮赋值给成员变量 mButton
mButton = button;
// 为按钮设置背景资源,使用下拉图标
mButton.setBackgroundResource(R.drawable.dropdown_icon);
// 创建一个弹出菜单对象,关联到传入的按钮上
mPopupMenu = new PopupMenu(context, mButton);
// 获取弹出菜单的菜单对象
mMenu = mPopupMenu.getMenu();
// 使用菜单布局资源 ID 来填充菜单内容
mPopupMenu.getMenuInflater().inflate(menuId, mMenu);
// 为按钮设置点击监听器
mButton.setOnClickListener(new OnClickListener() {
/**
*
*
* @param v
*/
public void onClick(View v) {
// 显示弹出菜单
mPopupMenu.show();
}
});
}
/**
*
*
* @param listener
*/
public void setOnDropdownMenuItemClickListener(OnMenuItemClickListener listener) {
// 检查弹出菜单对象是否不为空
if (mPopupMenu != null) {
// 为弹出菜单设置菜单项点击监听器
mPopupMenu.setOnMenuItemClickListener(listener);
}
}
/**
* ID
*
* @param id ID
* @return null
*/
public MenuItem findItem(int id) {
// 在菜单中查找指定 ID 的菜单项
return mMenu.findItem(id);
}
/**
*
*
* @param title
*/
public void setTitle(CharSequence title) {
// 设置按钮的文本内容为传入的标题
mButton.setText(title);
}
}

@ -1,135 +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.ui;
import android.content.Context;
import android.database.Cursor;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
/**
* FoldersListAdapter CursorAdapter
* CursorAdapter Cursor AdapterView
*/
public class FoldersListAdapter extends CursorAdapter {
// 定义从数据库中查询所需的列,这里查询了笔记的 ID 和摘要
public static final String [] PROJECTION = {
NoteColumns.ID,
NoteColumns.SNIPPET
};
// 定义 PROJECTION 数组中 ID 列的索引
public static final int ID_COLUMN = 0;
// 定义 PROJECTION 数组中名称列的索引
public static final int NAME_COLUMN = 1;
/**
* FoldersListAdapter
* @param context
* @param c Cursor
*/
public FoldersListAdapter(Context context, Cursor c) {
super(context, c);
// TODO Auto-generated constructor stub
}
/**
* Cursor
* Adapter
* @param context
* @param cursor Cursor
* @param parent
* @return
*/
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// 创建一个新的 FolderListItem 视图
return new FolderListItem(context);
}
/**
* Cursor
* Adapter
* @param view
* @param context
* @param cursor Cursor
*/
@Override
public void bindView(View view, Context context, Cursor cursor) {
// 检查视图是否为 FolderListItem 类型
if (view instanceof FolderListItem) {
// 获取文件夹名称,如果是根文件夹,则显示特定的文本,否则显示从数据库中获取的名称
String folderName = (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
// 调用 FolderListItem 的 bind 方法,将文件夹名称绑定到视图上
((FolderListItem) view).bind(folderName);
}
}
/**
*
* @param context
* @param position
* @return
*/
public String getFolderName(Context context, int position) {
// 获取指定位置的 Cursor 对象
Cursor cursor = (Cursor) getItem(position);
// 获取文件夹名称,如果是根文件夹,则显示特定的文本,否则显示从数据库中获取的名称
return (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context
.getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN);
}
/**
* FolderListItem LinearLayout
* FoldersListAdapter
*/
private class FolderListItem extends LinearLayout {
// 用于显示文件夹名称的 TextView
private TextView mName;
/**
* FolderListItem
* @param context
*/
public FolderListItem(Context context) {
super(context);
// 加载布局文件 folder_list_item.xml 到当前视图
inflate(context, R.layout.folder_list_item, this);
// 查找布局文件中的 TextView 控件
mName = (TextView) findViewById(R.id.tv_folder_name);
}
/**
* TextView
* @param name
*/
public void bind(String name) {
// 设置 TextView 的文本为文件夹名称
mName.setText(name);
}
}
}

File diff suppressed because it is too large Load Diff

@ -1,309 +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.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;
// 自定义的 EditText 类,继承自 EditText用于处理笔记编辑的特定逻辑
public class NoteEditText extends EditText {
// 日志标签,用于调试信息输出
private static final String TAG = "NoteEditText";
// 该 EditText 在集合中的索引
private int mIndex;
// 删除操作前的选择起始位置
private int mSelectionStartBeforeDelete;
// 定义支持的 URL 协议
private static final String SCHEME_TEL = "tel:" ;
private static final String SCHEME_HTTP = "http:" ;
private static final String SCHEME_EMAIL = "mailto:" ;
// 存储 URL 协议和对应的菜单资源 ID 的映射
private static final Map<String, Integer> sSchemaActionResMap = new HashMap<String, Integer>();
static {
// 初始化映射,将不同协议与对应的菜单文本资源 ID 关联
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);
}
/**
* NoteEditActivity EditText
*/
public interface OnTextViewChangeListener {
/**
* EditText
* @param index EditText
* @param text EditText
*/
void onEditTextDelete(int index, String text);
/**
* EditText EditText
* @param index EditText
* @param text
*/
void onEditTextEnter(int index, String text);
/**
*
* @param index EditText
* @param hasText EditText
*/
void onTextChange(int index, boolean hasText);
}
// 文本变化监听器
private OnTextViewChangeListener mOnTextViewChangeListener;
/**
* 使
* @param context
*/
public NoteEditText(Context context) {
super(context, null);
// 初始化索引为 0
mIndex = 0;
}
/**
* EditText
* @param index
*/
public void setIndex(int index) {
mIndex = index;
}
/**
*
* @param listener
*/
public void setOnTextViewChangeListener(OnTextViewChangeListener listener) {
mOnTextViewChangeListener = listener;
}
/**
* 使
* @param context
* @param attrs
*/
public NoteEditText(Context context, AttributeSet attrs) {
super(context, attrs, android.R.attr.editTextStyle);
}
/**
* 使
* @param context
* @param attrs
* @param defStyle
*/
public NoteEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
/**
*
* @param event
* @return
*/
@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);
}
/**
*
* @param keyCode
* @param event
* @return
*/
@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);
}
/**
*
* @param keyCode
* @param event
* @return
*/
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
switch(keyCode) {
case KeyEvent.KEYCODE_DEL:
// 如果设置了监听器
if (mOnTextViewChangeListener != null) {
// 当选择起始位置为 0 且索引不为 0 时,触发删除操作
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));
// 触发添加 EditText 操作
mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, text);
} else {
// 未设置监听器,输出日志
Log.d(TAG, "OnTextViewChangeListener was not seted");
}
break;
default:
break;
}
return super.onKeyUp(keyCode, event);
}
/**
*
* @param focused
* @param direction
* @param previouslyFocusedRect
*/
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
// 如果设置了监听器
if (mOnTextViewChangeListener != null) {
// 失去焦点且文本为空时,触发文本变化事件
if (!focused && TextUtils.isEmpty(getText())) {
mOnTextViewChangeListener.onTextChange(mIndex, false);
} else {
// 其他情况,触发文本变化事件
mOnTextViewChangeListener.onTextChange(mIndex, true);
}
}
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
/**
*
* @param menu
*/
@Override
protected void onCreateContextMenu(ContextMenu menu) {
// 如果文本是 Spanned 类型
if (getText() instanceof Spanned) {
// 获取选择的起始和结束位置
int selStart = getSelectionStart();
int selEnd = getSelectionEnd();
// 计算选择范围的最小值和最大值
int min = Math.min(selStart, selEnd);
int max = Math.max(selStart, selEnd);
// 获取选择范围内的 URLSpan 数组
final URLSpan[] urls = ((Spanned) getText()).getSpans(min, max, URLSpan.class);
// 如果只有一个 URLSpan
if (urls.length == 1) {
int defaultResId = 0;
// 遍历支持的协议
for(String schema: sSchemaActionResMap.keySet()) {
// 如果 URL 包含该协议
if(urls[0].getURL().indexOf(schema) >= 0) {
// 获取对应的菜单资源 ID
defaultResId = sSchemaActionResMap.get(schema);
break;
}
}
// 如果未找到匹配的协议,使用默认的菜单资源 ID
if (defaultResId == 0) {
defaultResId = R.string.note_link_other;
}
// 添加菜单项,并设置点击监听器
menu.add(0, 0, 0, defaultResId).setOnMenuItemClickListener(
new OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
// 点击菜单项时,触发 URLSpan 的点击事件
urls[0].onClick(NoteEditText.this);
return true;
}
});
}
}
super.onCreateContextMenu(menu);
}
}
Loading…
Cancel
Save