diff --git a/gallery/build.properties b/gallery/build.properties index b6ef745..58fd4c6 100644 --- a/gallery/build.properties +++ b/gallery/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Sun Jul 19 06:11:23 GMT 2026 +#Sun Jul 19 14:50:39 CST 2026 stageCount=17 libraryProject= baseVersion=15.0 publishVersion=15.0.16 -buildCount=5 +buildCount=8 baseBetaVersion=15.0.17 diff --git a/gallery/src/main/java/cc/winboll/studio/gallery/AlbumAdapter.java b/gallery/src/main/java/cc/winboll/studio/gallery/AlbumAdapter.java index 1b3570c..1e31eb0 100644 --- a/gallery/src/main/java/cc/winboll/studio/gallery/AlbumAdapter.java +++ b/gallery/src/main/java/cc/winboll/studio/gallery/AlbumAdapter.java @@ -1,7 +1,6 @@ package cc.winboll.studio.gallery; import android.net.Uri; -import android.provider.MediaStore; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; @@ -14,8 +13,9 @@ import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import java.io.File; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; import cc.winboll.studio.libappbase.LogUtils; @@ -62,28 +62,11 @@ public class AlbumAdapter extends RecyclerView.Adapter } public void setData(ArrayList albums) { - this.albums = sortAlbums(albums); + this.albums = albums; LogUtils.d(TAG, "setData: " + albums.size() + " albums"); notifyDataSetChanged(); } - private ArrayList sortAlbums(ArrayList list) { - if (pinnedDbHelper == null || list == null || list.isEmpty()) { - return list; - } - ArrayList pinned = new ArrayList<>(); - ArrayList unpinned = new ArrayList<>(); - for (Album album : list) { - if (pinnedDbHelper.isPinned(album.getPath())) { - pinned.add(album); - } else { - unpinned.add(album); - } - } - pinned.addAll(unpinned); - return pinned; - } - public void setContext(android.content.Context context) { prefs = new Preferences(context); bgType = prefs.getBgType(); @@ -103,23 +86,17 @@ public class AlbumAdapter extends RecyclerView.Adapter public void refreshPinned() { if (pinnedDbHelper != null && albums != null && !albums.isEmpty()) { - ArrayList pinned = new ArrayList<>(); - ArrayList unpinned = new ArrayList<>(); + Set pinnedPaths = new HashSet(); + pinnedPaths.addAll(Arrays.asList(pinnedDbHelper.getPinnedPaths())); + ArrayList pinned = new ArrayList(); + ArrayList unpinned = new ArrayList(); for (Album album : albums) { - if (pinnedDbHelper.isPinned(album.getPath())) { + if (pinnedPaths.contains(album.getPath())) { pinned.add(album); } else { unpinned.add(album); } } - Comparator nameComparator = new Comparator() { - @Override - public int compare(Album a1, Album a2) { - return a1.getName().compareToIgnoreCase(a2.getName()); - } - }; - Collections.sort(pinned, nameComparator); - Collections.sort(unpinned, nameComparator); albums.clear(); albums.addAll(pinned); albums.addAll(unpinned); diff --git a/gallery/src/main/java/cc/winboll/studio/gallery/MainActivity.java b/gallery/src/main/java/cc/winboll/studio/gallery/MainActivity.java index 7835450..e5063c9 100644 --- a/gallery/src/main/java/cc/winboll/studio/gallery/MainActivity.java +++ b/gallery/src/main/java/cc/winboll/studio/gallery/MainActivity.java @@ -13,6 +13,8 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; +import android.os.Handler; +import android.os.Looper; import android.provider.MediaStore; import android.provider.Settings; import android.view.Menu; @@ -38,6 +40,11 @@ import java.io.File; import java.io.FileFilter; import java.io.FilenameFilter; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; public class MainActivity extends AppCompatActivity { public static final String TAG = "MainActivity"; @@ -47,6 +54,8 @@ public class MainActivity extends AppCompatActivity { private AlbumAdapter adapter; private Preferences prefs; private FloatingActionButton fabScrollTop; + private final ExecutorService executor = Executors.newSingleThreadExecutor(); + private final Handler mainHandler = new Handler(Looper.getMainLooper()); @Override protected void onCreate(Bundle savedInstanceState) { @@ -72,37 +81,37 @@ public class MainActivity extends AppCompatActivity { fabScrollTop = findViewById(R.id.fab_scroll_top); fabScrollTop.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - recyclerView.scrollToPosition(0); - } - }); + @Override + public void onClick(View v) { + recyclerView.scrollToPosition(0); + } + }); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { - @Override - public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { - super.onScrolled(recyclerView, dx, dy); - GridLayoutManager layoutManager = (GridLayoutManager) recyclerView.getLayoutManager(); - if (layoutManager != null) { - int firstVisible = layoutManager.findFirstVisibleItemPosition(); - if (firstVisible > 0) { - fabScrollTop.setVisibility(View.VISIBLE); - } else { - fabScrollTop.setVisibility(View.GONE); - } - } - } - }); + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + GridLayoutManager layoutManager = (GridLayoutManager) recyclerView.getLayoutManager(); + if (layoutManager != null) { + int firstVisible = layoutManager.findFirstVisibleItemPosition(); + if (firstVisible > 0) { + fabScrollTop.setVisibility(View.VISIBLE); + } else { + fabScrollTop.setVisibility(View.GONE); + } + } + } + }); adapter.setOnAlbumClickListener(new OnAlbumClickListener() { - @Override - public void onAlbumClick(Album album) { - Intent intent = new Intent(MainActivity.this, AlbumActivity.class); - intent.putExtra(AlbumActivity.EXTRA_ALBUM_PATH, album.getPath()); - intent.putExtra(AlbumActivity.EXTRA_ALBUM_NAME, album.getName()); - startActivity(intent); - } - }); + @Override + public void onAlbumClick(Album album) { + Intent intent = new Intent(MainActivity.this, AlbumActivity.class); + intent.putExtra(AlbumActivity.EXTRA_ALBUM_PATH, album.getPath()); + intent.putExtra(AlbumActivity.EXTRA_ALBUM_NAME, album.getName()); + startActivity(intent); + } + }); checkAndRequestPermissions(); } @@ -154,13 +163,13 @@ public class MainActivity extends AppCompatActivity { private void requestPermission() { ActivityCompat.requestPermissions(this, - new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, - PERMISSION_REQUEST_CODE); + new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, + PERMISSION_REQUEST_CODE); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, - @NonNull int[] grantResults) { + @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == PERMISSION_REQUEST_CODE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { @@ -171,96 +180,113 @@ public class MainActivity extends AppCompatActivity { } } - private void loadAlbums() { - LogUtils.d(TAG, "loadAlbums"); + private void loadAlbums() { + executor.execute(new Runnable() { + @Override + public void run() { + final ArrayList albums = loadAlbumsInBackground(); + mainHandler.post(new Runnable() { + @Override + public void run() { + if (albums.isEmpty()) { + Toast.makeText(MainActivity.this, R.string.no_images_found, Toast.LENGTH_SHORT).show(); + } + adapter.setData(albums); + LogUtils.d(TAG, "Loaded " + albums.size() + " albums"); + } + }); + } + }); + } + + private ArrayList loadAlbumsInBackground() { + LogUtils.d(TAG, "loadAlbumsInBackground"); String folderPath = prefs.getFolderPath(); File baseFolder = new File(folderPath); - LogUtils.d(TAG, "baseFolder: " + baseFolder.getAbsolutePath() + ", exists=" + baseFolder.exists()); if (!baseFolder.exists() || !baseFolder.isDirectory()) { folderPath = Preferences.getDefaultPath(); baseFolder = new File(folderPath); - LogUtils.d(TAG, "try default: " + baseFolder.getAbsolutePath() + ", exists=" + baseFolder.exists()); if (!baseFolder.exists()) { folderPath = Environment.getExternalStorageDirectory() + "/Pictures"; baseFolder = new File(folderPath); - LogUtils.d(TAG, "try Pictures: " + baseFolder.getAbsolutePath() + ", exists=" + baseFolder.exists()); } } AlbumCoverDbHelper coverDbHelper = AlbumCoverDbHelper.getInstance(this); - ArrayList albums = new ArrayList<>(); + PinnedAlbumDbHelper pinnedDbHelper = PinnedAlbumDbHelper.getInstance(this); - FileFilter directoryFilter = new FileFilter() { + Set pinnedPaths = new HashSet(); + String[] pinnedArray = pinnedDbHelper.getPinnedPaths(); + pinnedPaths.addAll(Arrays.asList(pinnedArray)); + + ArrayList albums = new ArrayList(); + + File[] subfolders = baseFolder.listFiles(new FileFilter() { @Override public boolean accept(File file) { return file.isDirectory(); } - }; - File[] subfolders = baseFolder.listFiles(directoryFilter); - LogUtils.d(TAG, "subfolders: " + (subfolders != null ? subfolders.length : 0)); + }); if (subfolders != null) { for (File subfolder : subfolders) { - LogUtils.d(TAG, "scanning folder: " + subfolder.getName()); String albumPath = subfolder.getAbsolutePath(); String coverPath = coverDbHelper.getCover(albumPath); - LogUtils.d(TAG, "loadAlbums: album=" + albumPath + ", coverPath=" + coverPath); Uri coverUri = null; if (coverPath != null) { File coverFile = new File(coverPath); if (coverFile.exists()) { coverUri = Uri.fromFile(coverFile); - LogUtils.d(TAG, "loadAlbums: cover from file=" + coverFile.getAbsolutePath()); } else { coverUri = getUriFromPath(coverPath); - LogUtils.d(TAG, "loadAlbums: cover from media store path=" + coverPath); - } - } - if (coverUri == null) { - ArrayList images = getImagesInFolder(albumPath); - if (!images.isEmpty()) { - coverUri = images.get(0); } } ArrayList allImages = getImagesInFolder(albumPath); + if (coverUri == null && !allImages.isEmpty()) { + coverUri = allImages.get(0); + } if (coverUri != null || !allImages.isEmpty()) { - if (coverUri == null && !allImages.isEmpty()) { - coverUri = allImages.get(0); - } int imageCount = allImages.size(); albums.add(new Album(subfolder.getName(), albumPath, coverUri, imageCount)); - LogUtils.d(TAG, "album added: " + subfolder.getName() + ", " + imageCount + " images"); } } } - if (albums.isEmpty()) { - Toast.makeText(this, R.string.no_images_found, Toast.LENGTH_SHORT).show(); - LogUtils.i(TAG, "No albums found"); + ArrayList pinned = new ArrayList(); + ArrayList unpinned = new ArrayList(); + for (Album album : albums) { + if (pinnedPaths.contains(album.getPath())) { + pinned.add(album); + } else { + unpinned.add(album); + } } - adapter.setData(albums); - LogUtils.d(TAG, "Loaded " + albums.size() + " albums"); + pinned.addAll(unpinned); + return pinned; } private Uri getUriFromPath(String path) { String[] projection = { MediaStore.Images.Media._ID }; String selection = MediaStore.Images.Media.DATA + " = ?"; String[] selectionArgs = { path }; - try (Cursor cursor = getContentResolver().query( - MediaStore.Images.Media.EXTERNAL_CONTENT_URI, - projection, selection, selectionArgs, null)) { - if (cursor != null) { + Cursor cursor = getContentResolver().query( + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + projection, selection, selectionArgs, null); + if (cursor != null) { + try { if (cursor.moveToFirst()) { long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)); return Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, String.valueOf(id)); } + } finally { + cursor.close(); } } return null; } private ArrayList getImagesInFolder(String folderPath) { - ArrayList imageUrls = new ArrayList<>(); + ArrayList imageUrls = new ArrayList(); ContentResolver contentResolver = getContentResolver(); Uri collection = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; @@ -268,24 +294,22 @@ public class MainActivity extends AppCompatActivity { String[] selectionArgs = new String[]{folderPath + "/%"}; String sortOrder = MediaStore.Images.Media.DATE_ADDED + " DESC"; - LogUtils.d(TAG, "getImagesInFolder: " + folderPath); - - try (Cursor cursor = contentResolver.query(collection, null, selection, selectionArgs, sortOrder)) { - if (cursor != null) { - LogUtils.d(TAG, "cursor count: " + cursor.getCount()); + Cursor cursor = contentResolver.query(collection, null, selection, selectionArgs, sortOrder); + if (cursor != null) { + try { int dataColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); while (cursor.moveToNext()) { String path = cursor.getString(dataColumn); if (path != null) { long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)); Uri contentUri = Uri.withAppendedPath(collection, String.valueOf(id)); - LogUtils.d(TAG, "image: id=" + id + ", path=" + path); imageUrls.add(contentUri); } } + } finally { + cursor.close(); } } - LogUtils.d(TAG, "found " + imageUrls.size() + " images"); return imageUrls; } @@ -294,10 +318,7 @@ public class MainActivity extends AppCompatActivity { getMenuInflater().inflate(R.menu.menu_main, menu); MenuItem debugItem = menu.findItem(R.id.action_debug); if (debugItem != null) { - //debugItem.setVisible(true); - //debugItem.setVisible(false); debugItem.setVisible(App.isDebugging()); - ToastUtils.show(String.format("App.isDebugging() is %s", App.isDebugging())); } return true; } @@ -312,31 +333,26 @@ public class MainActivity extends AppCompatActivity { startActivity(intent); return true; } else if (id == R.id.action_change_bg_color) { - //Toast.makeText(this, "修改背景颜色", Toast.LENGTH_SHORT).show(); - if (BackgroundUtils.DrawableType.COLOR == BackgroundUtils.getInstance().getDrawableType()) { - - ColorPickerDialog dlg = new ColorPickerDialog(this, BackgroundUtils.getInstance().getColor()); - dlg.setOnColorChangedListener(new com.a4455jkjh.colorpicker.view.OnColorChangedListener() { - - @Override - public void beforeColorChanged() { - } - - @Override - public void onColorChanged(int color) { - BackgroundUtils.getInstance().initFromColor(MainActivity.this, color); - View content = findViewById(android.R.id.content); - if (content != null) { - content.setBackground(BackgroundUtils.getInstance().getDrawable()); - } - } - - @Override - public void afterColorChanged() { - } - }); - dlg.show(); - } + if (BackgroundUtils.DrawableType.COLOR == BackgroundUtils.getInstance().getDrawableType()) { + ColorPickerDialog dlg = new ColorPickerDialog(this, BackgroundUtils.getInstance().getColor()); + dlg.setOnColorChangedListener(new com.a4455jkjh.colorpicker.view.OnColorChangedListener() { + @Override + public void beforeColorChanged() { + } + @Override + public void onColorChanged(int color) { + BackgroundUtils.getInstance().initFromColor(MainActivity.this, color); + View content = findViewById(android.R.id.content); + if (content != null) { + content.setBackground(BackgroundUtils.getInstance().getDrawable()); + } + } + @Override + public void afterColorChanged() { + } + }); + dlg.show(); + } return true; } else if (id == R.id.action_settings) { startActivity(new Intent(this, SettingsActivity.class)); @@ -368,7 +384,6 @@ public class MainActivity extends AppCompatActivity { super.onResume(); registerReceiver(coverUpdatedReceiver, new IntentFilter(Preferences.ACTION_COVER_UPDATED)); if (checkPermission()) { - scanMediaStore(); loadAlbums(); } if (adapter != null) { @@ -384,45 +399,9 @@ public class MainActivity extends AppCompatActivity { unregisterReceiver(coverUpdatedReceiver); } - 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 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); - } - }); - } - } - } + @Override + protected void onDestroy() { + super.onDestroy(); + executor.shutdownNow(); } }