修复相册删除与恢复显示不正常的BUG

This commit is contained in:
2026-04-25 05:43:45 +08:00
parent ab9ff33b72
commit 21f38be35d
5 changed files with 148 additions and 8 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}
});
}
}
}
}
} }

View File

@@ -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);
}
});
}
} }

0
gradlew vendored Normal file → Executable file
View File