修复相册删除与恢复显示不正常的BUG
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
#Created by .winboll/winboll_app_build.gradle
|
#Created by .winboll/winboll_app_build.gradle
|
||||||
#Fri Apr 24 20:49:06 GMT 2026
|
#Sat Apr 25 05:39:21 CST 2026
|
||||||
stageCount=0
|
stageCount=0
|
||||||
libraryProject=
|
libraryProject=
|
||||||
baseVersion=15.0
|
baseVersion=15.0
|
||||||
publishVersion=15.0.0
|
publishVersion=15.0.0
|
||||||
buildCount=4
|
buildCount=14
|
||||||
baseBetaVersion=15.0.1
|
baseBetaVersion=15.0.1
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package cc.winboll.studio.gallery;
|
package cc.winboll.studio.gallery;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.provider.MediaStore;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
@@ -9,6 +11,7 @@ import android.widget.TextView;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import com.bumptech.glide.Glide;
|
import com.bumptech.glide.Glide;
|
||||||
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import cc.winboll.studio.libappbase.LogUtils;
|
import cc.winboll.studio.libappbase.LogUtils;
|
||||||
@@ -43,10 +46,8 @@ public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder>
|
|||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
|
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
|
||||||
final Album album = albums.get(position);
|
final Album album = albums.get(position);
|
||||||
Glide.with(holder.coverImage.getContext())
|
LogUtils.d(TAG, "bind: " + album.getName() + ", cover=" + album.getCoverUri());
|
||||||
.load(album.getCoverUri())
|
|
||||||
.centerCrop()
|
|
||||||
.into(holder.coverImage);
|
|
||||||
holder.albumName.setText(album.getName());
|
holder.albumName.setText(album.getName());
|
||||||
holder.imageCount.setText(album.getImageCount() + " photos");
|
holder.imageCount.setText(album.getImageCount() + " photos");
|
||||||
|
|
||||||
@@ -58,6 +59,43 @@ public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.ViewHolder>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Uri coverUri = album.getCoverUri();
|
||||||
|
if (coverUri != null) {
|
||||||
|
String uriString = coverUri.toString();
|
||||||
|
LogUtils.d(TAG, "uri scheme: " + coverUri.getScheme() + ", path: " + uriString);
|
||||||
|
|
||||||
|
// For content:// URIs, try to get the actual file path
|
||||||
|
if ("content".equals(coverUri.getScheme())) {
|
||||||
|
try {
|
||||||
|
android.database.Cursor cursor = holder.coverImage.getContext().getContentResolver()
|
||||||
|
.query(coverUri, new String[]{MediaStore.Images.Media.DATA}, null, null, null);
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
int dataColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
|
||||||
|
String filePath = cursor.getString(dataColumn);
|
||||||
|
cursor.close();
|
||||||
|
if (filePath != null) {
|
||||||
|
File actualFile = new File(filePath);
|
||||||
|
LogUtils.d(TAG, "actual file: " + actualFile.getAbsolutePath() + ", exists=" + actualFile.exists());
|
||||||
|
// Use file path instead of content URI for better compatibility
|
||||||
|
Glide.with(holder.coverImage.getContext())
|
||||||
|
.load(actualFile)
|
||||||
|
.centerCrop()
|
||||||
|
.into(holder.coverImage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtils.e(TAG, "query error: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to content URI
|
||||||
|
Glide.with(holder.coverImage.getContext())
|
||||||
|
.load(coverUri)
|
||||||
|
.centerCrop()
|
||||||
|
.into(holder.coverImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import android.content.ContentResolver;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.media.MediaScannerConnection;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -26,6 +27,7 @@ import cc.winboll.studio.libappbase.LogUtils;
|
|||||||
import cc.winboll.studio.libappbase.LogActivity;
|
import cc.winboll.studio.libappbase.LogActivity;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileFilter;
|
import java.io.FileFilter;
|
||||||
|
import java.io.FilenameFilter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
@@ -133,13 +135,16 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
LogUtils.d(TAG, "loadAlbums");
|
LogUtils.d(TAG, "loadAlbums");
|
||||||
String folderPath = prefs.getFolderPath();
|
String folderPath = prefs.getFolderPath();
|
||||||
File baseFolder = new File(folderPath);
|
File baseFolder = new File(folderPath);
|
||||||
|
LogUtils.d(TAG, "baseFolder: " + baseFolder.getAbsolutePath() + ", exists=" + baseFolder.exists());
|
||||||
|
|
||||||
if (!baseFolder.exists() || !baseFolder.isDirectory()) {
|
if (!baseFolder.exists() || !baseFolder.isDirectory()) {
|
||||||
folderPath = Environment.getExternalStorageDirectory() + "/DCIM";
|
folderPath = Environment.getExternalStorageDirectory() + "/DCIM";
|
||||||
baseFolder = new File(folderPath);
|
baseFolder = new File(folderPath);
|
||||||
|
LogUtils.d(TAG, "try DCIM: " + baseFolder.getAbsolutePath() + ", exists=" + baseFolder.exists());
|
||||||
if (!baseFolder.exists()) {
|
if (!baseFolder.exists()) {
|
||||||
folderPath = Environment.getExternalStorageDirectory() + "/Pictures";
|
folderPath = Environment.getExternalStorageDirectory() + "/Pictures";
|
||||||
baseFolder = new File(folderPath);
|
baseFolder = new File(folderPath);
|
||||||
|
LogUtils.d(TAG, "try Pictures: " + baseFolder.getAbsolutePath() + ", exists=" + baseFolder.exists());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,12 +157,15 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
File[] subfolders = baseFolder.listFiles(directoryFilter);
|
File[] subfolders = baseFolder.listFiles(directoryFilter);
|
||||||
|
LogUtils.d(TAG, "subfolders: " + (subfolders != null ? subfolders.length : 0));
|
||||||
if (subfolders != null) {
|
if (subfolders != null) {
|
||||||
for (File subfolder : subfolders) {
|
for (File subfolder : subfolders) {
|
||||||
|
LogUtils.d(TAG, "scanning folder: " + subfolder.getName());
|
||||||
ArrayList<Uri> images = getImagesInFolder(subfolder.getAbsolutePath());
|
ArrayList<Uri> images = getImagesInFolder(subfolder.getAbsolutePath());
|
||||||
if (!images.isEmpty()) {
|
if (!images.isEmpty()) {
|
||||||
Uri latestImage = images.get(0);
|
Uri latestImage = images.get(0);
|
||||||
albums.add(new Album(subfolder.getName(), subfolder.getAbsolutePath(), latestImage, images.size()));
|
albums.add(new Album(subfolder.getName(), subfolder.getAbsolutePath(), latestImage, images.size()));
|
||||||
|
LogUtils.d(TAG, "album added: " + subfolder.getName() + ", " + images.size() + " images");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,19 +187,24 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
String[] selectionArgs = new String[]{folderPath + "/%"};
|
String[] selectionArgs = new String[]{folderPath + "/%"};
|
||||||
String sortOrder = MediaStore.Images.Media.DATE_ADDED + " DESC";
|
String sortOrder = MediaStore.Images.Media.DATE_ADDED + " DESC";
|
||||||
|
|
||||||
|
LogUtils.d(TAG, "getImagesInFolder: " + folderPath);
|
||||||
|
|
||||||
try (Cursor cursor = contentResolver.query(collection, null, selection, selectionArgs, sortOrder)) {
|
try (Cursor cursor = contentResolver.query(collection, null, selection, selectionArgs, sortOrder)) {
|
||||||
if (cursor != null) {
|
if (cursor != null) {
|
||||||
|
LogUtils.d(TAG, "cursor count: " + cursor.getCount());
|
||||||
int dataColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
|
int dataColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
String path = cursor.getString(dataColumn);
|
String path = cursor.getString(dataColumn);
|
||||||
if (path != null) {
|
if (path != null) {
|
||||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID));
|
long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID));
|
||||||
Uri contentUri = Uri.withAppendedPath(collection, String.valueOf(id));
|
Uri contentUri = Uri.withAppendedPath(collection, String.valueOf(id));
|
||||||
|
LogUtils.d(TAG, "image: id=" + id + ", path=" + path);
|
||||||
imageUrls.add(contentUri);
|
imageUrls.add(contentUri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
LogUtils.d(TAG, "found " + imageUrls.size() + " images");
|
||||||
return imageUrls;
|
return imageUrls;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +241,50 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
if (checkPermission()) {
|
if (checkPermission()) {
|
||||||
|
scanMediaStore();
|
||||||
loadAlbums();
|
loadAlbums();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void scanMediaStore() {
|
||||||
|
String folderPath = prefs.getFolderPath();
|
||||||
|
File baseFolder = new File(folderPath);
|
||||||
|
if (baseFolder.exists() && baseFolder.isDirectory()) {
|
||||||
|
File[] subfolders = baseFolder.listFiles(new FileFilter() {
|
||||||
|
@Override
|
||||||
|
public boolean accept(File file) {
|
||||||
|
return file.isDirectory();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (subfolders != null) {
|
||||||
|
ArrayList<String> paths = new ArrayList<>();
|
||||||
|
for (File subfolder : subfolders) {
|
||||||
|
File[] images = subfolder.listFiles(new FilenameFilter() {
|
||||||
|
@Override
|
||||||
|
public boolean accept(File dir, String name) {
|
||||||
|
String lower = name.toLowerCase();
|
||||||
|
return lower.endsWith(".jpg") || lower.endsWith(".jpeg")
|
||||||
|
|| lower.endsWith(".png") || lower.endsWith(".gif")
|
||||||
|
|| lower.endsWith(".webp") || lower.endsWith(".bmp");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (images != null) {
|
||||||
|
for (File img : images) {
|
||||||
|
paths.add(img.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!paths.isEmpty()) {
|
||||||
|
LogUtils.d(TAG, "scanning " + paths.size() + " files to MediaStore");
|
||||||
|
String[] pathArray = paths.toArray(new String[0]);
|
||||||
|
MediaScannerConnection.scanFile(this, pathArray, null, new MediaScannerConnection.OnScanCompletedListener() {
|
||||||
|
@Override
|
||||||
|
public void onScanCompleted(String path, Uri uri) {
|
||||||
|
LogUtils.d(TAG, "scanCompleted: " + path + " -> " + uri);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package cc.winboll.studio.gallery;
|
package cc.winboll.studio.gallery;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.media.MediaScannerConnection;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -50,25 +53,58 @@ public class TrashManager {
|
|||||||
public boolean restore(long id, String fileName, String originalPath) {
|
public boolean restore(long id, String fileName, String originalPath) {
|
||||||
LogUtils.i(TAG, "restore: " + fileName + " -> " + originalPath);
|
LogUtils.i(TAG, "restore: " + fileName + " -> " + originalPath);
|
||||||
File trashFile = new File(TrashDbHelper.getTrashPath(), fileName);
|
File trashFile = new File(TrashDbHelper.getTrashPath(), fileName);
|
||||||
|
LogUtils.d(TAG, "trashFile exists: " + trashFile.exists() + ", path: " + trashFile.getAbsolutePath());
|
||||||
if (!trashFile.exists()) {
|
if (!trashFile.exists()) {
|
||||||
|
LogUtils.e(TAG, "trashFile not exists: " + trashFile.getAbsolutePath());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
File originalFolder = new File(originalPath).getParentFile();
|
File originalFolder = new File(originalPath).getParentFile();
|
||||||
|
LogUtils.d(TAG, "originalFolder: " + originalFolder + ", exists: " + (originalFolder != null && originalFolder.exists()));
|
||||||
if (originalFolder != null && !originalFolder.exists()) {
|
if (originalFolder != null && !originalFolder.exists()) {
|
||||||
originalFolder.mkdirs();
|
boolean created = originalFolder.mkdirs();
|
||||||
|
LogUtils.d(TAG, "mkdirs result: " + created + ", path: " + originalFolder.getAbsolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
File originalFile = new File(originalPath);
|
File originalFile = new File(originalPath);
|
||||||
String restoreName = originalFile.getName();
|
String restoreName = originalFile.getName();
|
||||||
File restoreFile = new File(originalFolder, restoreName);
|
File restoreFile = new File(originalFolder, restoreName);
|
||||||
|
LogUtils.d(TAG, "restoreFile: " + restoreFile.getAbsolutePath() + ", exists: " + restoreFile.exists());
|
||||||
|
|
||||||
if (trashFile.renameTo(restoreFile)) {
|
boolean renameResult = trashFile.renameTo(restoreFile);
|
||||||
|
LogUtils.d(TAG, "renameTo result: " + renameResult);
|
||||||
|
|
||||||
|
if (renameResult) {
|
||||||
dbHelper.delete(id);
|
dbHelper.delete(id);
|
||||||
LogUtils.i(TAG, "Restored: " + fileName);
|
LogUtils.i(TAG, "Restored: " + fileName);
|
||||||
|
scanMedia(restoreFile.getAbsolutePath());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try copy + delete if rename failed
|
||||||
|
LogUtils.i(TAG, "renameTo failed, trying copy + delete");
|
||||||
|
try {
|
||||||
|
java.io.InputStream in = new java.io.FileInputStream(trashFile);
|
||||||
|
java.io.OutputStream out = new java.io.FileOutputStream(restoreFile);
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int len;
|
||||||
|
while ((len = in.read(buffer)) > 0) {
|
||||||
|
out.write(buffer, 0, len);
|
||||||
|
}
|
||||||
|
in.close();
|
||||||
|
out.close();
|
||||||
|
boolean deleted = trashFile.delete();
|
||||||
|
LogUtils.d(TAG, "copy+delete result: " + deleted);
|
||||||
|
if (deleted) {
|
||||||
|
dbHelper.delete(id);
|
||||||
|
LogUtils.i(TAG, "Restored (copy): " + fileName);
|
||||||
|
scanMedia(restoreFile.getAbsolutePath());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LogUtils.e(TAG, "copy failed: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
LogUtils.e(TAG, "Failed to restore: " + fileName);
|
LogUtils.e(TAG, "Failed to restore: " + fileName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -109,4 +145,14 @@ public class TrashManager {
|
|||||||
}
|
}
|
||||||
return ".jpg";
|
return ".jpg";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void scanMedia(String filePath) {
|
||||||
|
LogUtils.d(TAG, "scanMedia: " + filePath);
|
||||||
|
MediaScannerConnection.scanFile(context, new String[]{filePath}, null, new android.media.MediaScannerConnection.OnScanCompletedListener() {
|
||||||
|
@Override
|
||||||
|
public void onScanCompleted(String path, Uri uri) {
|
||||||
|
LogUtils.d(TAG, "scanCompleted: " + path + " -> " + uri);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user