Merge branch 'master' of https://bdgit.educoder.net/p82feo7wg/MiNoteRead into luogang_branch

# Conflicts:
#	src/Notes-master/res/layout/note_edit.xml
#	src/Notes-master/res/values-zh-rCN/strings.xml
#	src/Notes-master/res/values/strings.xml
#	src/Notes-master/src/net/micode/notes/tool/DataUtils.java
#	src/Notes-master/src/net/micode/notes/ui/NoteEditActivity.java
pull/23/head
AetherPendragon 2 months ago
commit 5b1a3021f5

@ -17,6 +17,7 @@
<!-- 已移除package属性已注释minSdkVersion可选删除 -->
<!-- <uses-sdk android:minSdkVersion="14" /> -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_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" />

@ -56,15 +56,6 @@
android:layout_marginRight="8dip"
android:textAppearance="@style/TextAppearanceSecondaryItem" />
<!-- 插入图片按钮 -->
<ImageButton
android:id="@+id/btn_insert_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@android:drawable/ic_menu_gallery"
android:background="@drawable/bg_btn_set_color"
android:layout_marginRight="8dip" />
<ImageButton
android:id="@+id/btn_set_bg_color"
@ -87,7 +78,8 @@
<LinearLayout
android:id="@+id/sv_note_edit"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:orientation="vertical">
<ImageView
@ -197,6 +189,57 @@
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
<!-- 富文本工具栏 - 放置在页面底部 -->
<HorizontalScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#F5F5F5"
android:scrollbars="none">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="4dp">
<ImageButton
android:id="@+id/btn_bold"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:src="@android:drawable/ic_menu_edit"
android:contentDescription="@string/formatting_bold" />
<ImageButton
android:id="@+id/btn_italic"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:src="@android:drawable/ic_menu_edit"
android:contentDescription="@string/formatting_italic" />
<ImageButton
android:id="@+id/btn_underline"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:src="@android:drawable/ic_menu_edit"
android:contentDescription="@string/formatting_underline" />
<!-- 插入图片按钮 -->
<ImageButton
android:id="@+id/btn_insert_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@android:drawable/ic_menu_gallery"
android:background="@drawable/bg_btn_set_color"
android:layout_marginRight="8dip" />
<ImageButton
android:id="@+id/btn_set_bg_color_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/bg_btn_set_color" />
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
<ImageView
@ -252,9 +295,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_marginRight="3dip"
android:focusable="false"
android:visibility="gone"
android:layout_marginRight="3dip"
android:src="@drawable/selected" />
</FrameLayout>
@ -273,9 +317,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_marginRight="2dip"
android:focusable="false"
android:visibility="gone"
android:layout_marginRight="2dip"
android:src="@drawable/selected" />
</FrameLayout>

@ -88,6 +88,8 @@
<string name="error_note_not_exist">The note is not exist</string>
<string name="error_note_empty_for_clock">Sorry, can not set clock on empty note</string>
<string name="error_note_empty_for_send_to_desktop">Sorry, can not send and empty note to home</string>
<string name="error_permission_denied">Permission denied, cannot access images</string>
<string name="error_image_insert_failed">Failed to insert image, please try again</string>
<string name="success_sdcard_export">Export successful</string>
<string name="failed_sdcard_export">Export fail</string>
<string name="format_exported_file_location">Export text file (%1$s) to SD (%2$s) directory</string>

@ -81,11 +81,11 @@ public class DataUtils {
// Query the note from note table
cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id),
null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
// Read all columns from the note
ContentValues trashValues = new ContentValues();
// Copy all columns from note to trash
for (String column : cursor.getColumnNames()) {
int columnIndex = cursor.getColumnIndex(column);
@ -109,13 +109,13 @@ public class DataUtils {
}
}
}
// Set deleted_date to current time
trashValues.put("deleted_date", System.currentTimeMillis());
// Insert into trash table
resolver.insert(Notes.CONTENT_TRASH_URI, trashValues);
// 在删除note之前先备份DATA表的数据
if (db != null) {
// 查询该note的所有DATA数据
@ -163,7 +163,7 @@ public class DataUtils {
// Delete from note table (this will trigger deletion of DATA table via trigger)
resolver.delete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), null, null);
}
if (cursor != null) {
cursor.close();
cursor = null;
@ -202,7 +202,7 @@ public class DataUtils {
}
public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids,
long folderId) {
long folderId) {
if (ids == null) {
Log.d(TAG, "the ids is null");
return true;
@ -305,8 +305,8 @@ public class DataUtils {
public static boolean checkVisibleFolderName(ContentResolver resolver, String name) {
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null,
NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER +
" AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER +
" AND " + NoteColumns.SNIPPET + "=?",
" AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER +
" AND " + NoteColumns.SNIPPET + "=?",
new String[] { name }, null);
boolean exist = false;
if(cursor != null) {
@ -391,7 +391,7 @@ public class DataUtils {
// Query the note from trash table
cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_TRASH_URI, trashId),
null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
// Read all columns from the trash note
ContentValues noteValues = new ContentValues();
@ -428,14 +428,14 @@ public class DataUtils {
}
}
}
// Insert back to note table
Uri restoredUri = resolver.insert(Notes.CONTENT_NOTE_URI, noteValues);
if (restoredUri == null) {
Log.e(TAG, "Failed to restore note to note table");
return false;
}
// 获取恢复后的note ID可能是新的ID
long restoredNoteId = ContentUris.parseId(restoredUri);
if (restoredNoteId <= 0) {
@ -500,7 +500,7 @@ public class DataUtils {
// Delete from trash table
resolver.delete(ContentUris.withAppendedId(Notes.CONTENT_TRASH_URI, trashId), null, null);
return true;
}
return false;
@ -582,7 +582,7 @@ public class DataUtils {
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
new String [] { CallNote.NOTE_ID },
CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL("
+ CallNote.PHONE_NUMBER + ",?)",
+ CallNote.PHONE_NUMBER + ",?)",
new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber },
null);
@ -620,6 +620,8 @@ public class DataUtils {
public static String getFormattedSnippet(String snippet) {
if (snippet != null) {
snippet = snippet.trim();
// 替换[IMAGE]标签为友好的占位符
snippet = snippet.replaceAll("\\[IMAGE\\].*?\\[/IMAGE\\]", "[图片]");
int index = snippet.indexOf('\n');
if (index != -1) {
snippet = snippet.substring(0, index);

@ -27,11 +27,16 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Paint;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.style.BackgroundColorSpan;
@ -47,23 +52,19 @@ import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ImageButton;
import android.provider.MediaStore;
import android.net.Uri;
import java.io.File;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Editable;
import android.text.style.ImageSpan;
import android.graphics.Typeface;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.content.ContentResolver;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
// import android.support.annotation.NonNull;
import android.Manifest;
import android.graphics.Color;
import java.io.InputStream;
import java.io.FileOutputStream;
@ -443,6 +444,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
return new SpannableString("");
}
Log.d(TAG, "Converting text to Spannable with images: " + text);
// 创建一个新的SpannableStringBuilder
SpannableStringBuilder builder = new SpannableStringBuilder();
@ -451,6 +454,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
int imageStart = text.indexOf("[IMAGE]", startIndex);
while (imageStart != -1) {
Log.d(TAG, "Found [IMAGE] tag at position: " + imageStart);
// 添加[IMAGE]标签之前的文本
builder.append(text.substring(startIndex, imageStart));
@ -462,43 +467,97 @@ public class NoteEditActivity extends Activity implements OnClickListener,
break;
}
Log.d(TAG, "Found [/IMAGE] tag at position: " + imageEnd);
// 提取图片URI
String imageUri = text.substring(imageStart + "[IMAGE]".length(), imageEnd);
Log.d(TAG, "Found image URI: " + imageUri);
Log.d(TAG, "Extracted image URI: " + imageUri);
// 创建一个占位符字符串,用于插入ImageSpan
String placeholder = " ";
int placeholderStart = builder.length();
builder.append(placeholder);
// 保留原始的[IMAGE]uri[/IMAGE]标签,直接在上面添加ImageSpan
String fullImageTag = "[IMAGE]" + imageUri + "[/IMAGE]";
int tagStart = builder.length();
builder.append(fullImageTag);
// 尝试将图片URI转换为Drawable并创建ImageSpan
try {
// 确保URI是有效的
Uri uri = Uri.parse(imageUri);
if (uri == null) {
Log.e(TAG, "Invalid URI: " + imageUri);
// 更新索引,继续处理下一个标签
startIndex = imageEnd + "[/IMAGE]".length();
imageStart = text.indexOf("[IMAGE]", startIndex);
continue;
}
Log.d(TAG, "Attempting to load image from URI: " + uri.toString());
// 使用BitmapFactory直接加载图片这是最可靠的方式
ContentResolver resolver = getContentResolver();
InputStream inputStream = resolver.openInputStream(Uri.parse(imageUri));
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
inputStream.close();
// 计算图片的合适大小确保它能适应EditText的宽度
int screenWidth = getResources().getDisplayMetrics().widthPixels;
int imageWidth = bitmap.getWidth();
int imageHeight = bitmap.getHeight();
float scale = (float) screenWidth / (float) imageWidth;
int scaledHeight = (int) (imageHeight * scale);
// 缩放图片
Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, screenWidth, scaledHeight, true);
Drawable drawable = new android.graphics.drawable.BitmapDrawable(getResources(), scaledBitmap);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
// 创建ImageSpan并添加到SpannableStringBuilder中
ImageSpan imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_BASELINE);
builder.setSpan(imageSpan, placeholderStart, placeholderStart + placeholder.length(), SpannableString.SPAN_INCLUSIVE_EXCLUSIVE);
InputStream inputStream = null;
try {
inputStream = resolver.openInputStream(uri);
if (inputStream == null) {
Log.e(TAG, "Failed to open input stream for URI: " + uri.toString());
// 更新索引,继续处理下一个标签
startIndex = imageEnd + "[/IMAGE]".length();
imageStart = text.indexOf("[IMAGE]", startIndex);
continue;
}
// 解码图片
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
if (bitmap == null) {
Log.e(TAG, "Failed to decode bitmap from URI: " + uri.toString());
// 更新索引,继续处理下一个标签
startIndex = imageEnd + "[/IMAGE]".length();
imageStart = text.indexOf("[IMAGE]", startIndex);
continue;
}
Log.d(TAG, "Successfully decoded bitmap with dimensions: " + bitmap.getWidth() + "x" + bitmap.getHeight());
// 计算图片的合适大小确保它能适应EditText的宽度
int screenWidth = getResources().getDisplayMetrics().widthPixels;
// 减去左右边距,确保图片能完整显示
int maxWidth = screenWidth - 40;
int imageWidth = bitmap.getWidth();
int imageHeight = bitmap.getHeight();
// 计算缩放比例
float scale = 1.0f;
if (imageWidth > maxWidth) {
scale = (float) maxWidth / (float) imageWidth;
}
Log.d(TAG, "Calculated scale: " + scale);
// 缩放图片(如果需要)
if (scale < 1.0f) {
bitmap = Bitmap.createScaledBitmap(bitmap, (int)(imageWidth * scale), (int)(imageHeight * scale), true);
Log.d(TAG, "Scaled bitmap to: " + bitmap.getWidth() + "x" + bitmap.getHeight());
}
// 创建Drawable并设置边界
Drawable drawable = new android.graphics.drawable.BitmapDrawable(getResources(), bitmap);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
// 创建ImageSpan并添加到SpannableStringBuilder中
ImageSpan imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_BASELINE);
builder.setSpan(imageSpan, tagStart, tagStart + fullImageTag.length(), SpannableString.SPAN_INCLUSIVE_EXCLUSIVE);
Log.d(TAG, "Successfully added ImageSpan for URI: " + imageUri);
} finally {
// 确保InputStream被正确关闭
if (inputStream != null) {
try {
inputStream.close();
} catch (Exception e) {
Log.e(TAG, "Error closing input stream: " + e.toString());
}
}
}
} catch (Exception e) {
Log.e(TAG, "Error loading image: " + e.toString());
// 如果加载图片失败直接显示图片URI
builder.append("[IMAGE]");
builder.append(imageUri);
builder.append("[/IMAGE]");
e.printStackTrace();
}
// 更新索引,继续查找下一个[IMAGE]标签
@ -509,6 +568,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
// 添加剩余的文本
builder.append(text.substring(startIndex));
Log.d(TAG, "Final SpannableStringBuilder content: " + builder.toString());
return new SpannableString(builder);
}
@ -679,7 +739,7 @@ public class NoteEditActivity extends Activity implements OnClickListener,
if (mBtnInsertImage != null) {
mBtnInsertImage.setOnClickListener(this);
}
// 初始化富文本功能按钮
initRichEditorButtons();
}
@ -1368,6 +1428,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
/**
* OMO
*/
private static final int REQUEST_CODE_PERMISSION_STORAGE = 101;
private void pickImageFromGallery() {
try {
// 意图:打开系统相册选择图片
@ -1387,6 +1449,21 @@ public class NoteEditActivity extends Activity implements OnClickListener,
}
}
// 处理权限请求结果
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE_PERMISSION_STORAGE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 权限被授予,执行图片选择
pickImageFromGallery();
} else {
// 权限被拒绝,显示提示
showToast(R.string.error_permission_denied);
}
}
}
/**
* OMO
*/

Loading…
Cancel
Save