From 4d0d8c4d59368baa2ed29b037544580bbd8903b5 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Sun, 26 Apr 2026 09:06:27 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=9B=B8=E5=86=8C=E9=9B=86?= =?UTF-8?q?=E7=BD=AE=E9=A1=B6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 长按相册封面显示菜单,可选择置顶 - 置顶的相册优先显示并按名称排序 - 非置顶的相册也按名称排序 - 置顶图标显示在封面上 --- gallery/build.properties | 4 +- .../winboll/studio/gallery/AlbumAdapter.java | 86 ++++++++++++++++++- .../winboll/studio/gallery/MainActivity.java | 1 + .../studio/gallery/PinnedAlbumDbHelper.java | 78 +++++++++++++++++ gallery/src/main/res/drawable/ic_pin.xml | 9 ++ gallery/src/main/res/layout/item_album.xml | 15 +++- 6 files changed, 188 insertions(+), 5 deletions(-) create mode 100644 gallery/src/main/java/cc/winboll/studio/gallery/PinnedAlbumDbHelper.java create mode 100644 gallery/src/main/res/drawable/ic_pin.xml diff --git a/gallery/build.properties b/gallery/build.properties index 82bcca4..3d42bc2 100644 --- a/gallery/build.properties +++ b/gallery/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Sun Apr 26 08:19:05 CST 2026 +#Sun Apr 26 09:00:16 CST 2026 stageCount=4 libraryProject= baseVersion=15.0 publishVersion=15.0.3 -buildCount=1 +buildCount=11 baseBetaVersion=15.0.4 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 15b0615..70d6157 100644 --- a/gallery/src/main/java/cc/winboll/studio/gallery/AlbumAdapter.java +++ b/gallery/src/main/java/cc/winboll/studio/gallery/AlbumAdapter.java @@ -5,6 +5,7 @@ import android.provider.MediaStore; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; +import android.view.View.OnLongClickListener; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; @@ -13,6 +14,8 @@ 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 cc.winboll.studio.libappbase.LogUtils; @@ -22,6 +25,7 @@ public class AlbumAdapter extends RecyclerView.Adapter private OnAlbumClickListener listener; private Preferences prefs; private int bgType = 0; + private PinnedAlbumDbHelper pinnedDbHelper; private int getBgRes() { switch (bgType) { @@ -45,22 +49,89 @@ public class AlbumAdapter extends RecyclerView.Adapter } public void setData(ArrayList albums) { - this.albums = albums; + this.albums = sortAlbums(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(); + pinnedDbHelper = PinnedAlbumDbHelper.getInstance(context); } public void refreshBg() { if (prefs != null) { bgType = prefs.getBgType(); + } + notifyDataSetChanged(); + } + + public void refreshPinned() { + if (pinnedDbHelper != null && albums != null && !albums.isEmpty()) { + ArrayList pinned = new ArrayList<>(); + ArrayList unpinned = new ArrayList<>(); + for (Album album : albums) { + if (pinnedDbHelper.isPinned(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); notifyDataSetChanged(); } } + +private void showContextMenu(View view, final Album album) { + android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(view.getContext()); + builder.setTitle(album.getName()); + boolean isPinned = pinnedDbHelper != null && pinnedDbHelper.isPinned(album.getPath()); + String[] items = isPinned ? new String[]{"取消置顶"} : new String[]{"置顶"}; + builder.setItems(items, new android.content.DialogInterface.OnClickListener() { + @Override + public void onClick(android.content.DialogInterface dialog, int which) { + if (pinnedDbHelper != null) { + if (which == 0) { + if (isPinned) { + pinnedDbHelper.unpinAlbum(album.getPath()); + } else { + pinnedDbHelper.pinAlbum(album.getPath()); + } + refreshPinned(); + } + } + } + }); + builder.show(); + } @NonNull @Override @@ -77,6 +148,17 @@ public class AlbumAdapter extends RecyclerView.Adapter holder.coverImage.setBackgroundResource(getBgRes()); + boolean isPinned = pinnedDbHelper != null && pinnedDbHelper.isPinned(album.getPath()); + holder.pinIcon.setVisibility(isPinned ? View.VISIBLE : View.GONE); + + holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + showContextMenu(holder.itemView, album); + return true; + } + }); + holder.albumName.setText(album.getName()); holder.imageCount.setText(album.getImageCount() + " photos"); @@ -134,11 +216,13 @@ public class AlbumAdapter extends RecyclerView.Adapter static class ViewHolder extends RecyclerView.ViewHolder { ImageView coverImage; + ImageView pinIcon; TextView albumName; TextView imageCount; ViewHolder(View itemView) { super(itemView); coverImage = itemView.findViewById(R.id.album_cover); + pinIcon = itemView.findViewById(R.id.pin_icon); albumName = itemView.findViewById(R.id.album_name); imageCount = itemView.findViewById(R.id.image_count); } 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 1373f20..6b33283 100644 --- a/gallery/src/main/java/cc/winboll/studio/gallery/MainActivity.java +++ b/gallery/src/main/java/cc/winboll/studio/gallery/MainActivity.java @@ -247,6 +247,7 @@ public class MainActivity extends AppCompatActivity { } if (adapter != null) { adapter.refreshBg(); + adapter.refreshPinned(); } } diff --git a/gallery/src/main/java/cc/winboll/studio/gallery/PinnedAlbumDbHelper.java b/gallery/src/main/java/cc/winboll/studio/gallery/PinnedAlbumDbHelper.java new file mode 100644 index 0000000..cbe60cc --- /dev/null +++ b/gallery/src/main/java/cc/winboll/studio/gallery/PinnedAlbumDbHelper.java @@ -0,0 +1,78 @@ +package cc.winboll.studio.gallery; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import cc.winboll.studio.libappbase.LogUtils; + +public class PinnedAlbumDbHelper extends SQLiteOpenHelper { + public static final String TAG = "PinnedAlbumDbHelper"; + private static final String DB_NAME = "gallery.db"; + private static final int DB_VERSION = 1; + private static final String TABLE_NAME = "pinned_albums"; + private static final String COLUMN_PATH = "album_path"; + + private static final String SQL_CREATE = "CREATE TABLE " + TABLE_NAME + " (" + + COLUMN_PATH + " TEXT PRIMARY KEY)"; + + private static PinnedAlbumDbHelper dbHelper; + + public static PinnedAlbumDbHelper getInstance(Context context) { + if (dbHelper == null) { + dbHelper = new PinnedAlbumDbHelper(context.getApplicationContext()); + } + return dbHelper; + } + + public PinnedAlbumDbHelper(Context context) { + super(context, DB_NAME, null, DB_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL(SQL_CREATE); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); + onCreate(db); + } + + public void pinAlbum(String albumPath) { + SQLiteDatabase db = getWritableDatabase(); + ContentValues values = new ContentValues(); + values.put(COLUMN_PATH, albumPath); + db.insertWithOnConflict(TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_IGNORE); + LogUtils.d(TAG, "pinAlbum: " + albumPath); + } + + public void unpinAlbum(String albumPath) { + SQLiteDatabase db = getWritableDatabase(); + db.delete(TABLE_NAME, COLUMN_PATH + " = ?", new String[]{albumPath}); + LogUtils.d(TAG, "unpinAlbum: " + albumPath); + } + + public boolean isPinned(String albumPath) { + SQLiteDatabase db = getReadableDatabase(); + Cursor cursor = db.query(TABLE_NAME, null, COLUMN_PATH + " = ?", + new String[]{albumPath}, null, null, null); + boolean pinned = cursor.getCount() > 0; + cursor.close(); + return pinned; + } + + public String[] getPinnedPaths() { + SQLiteDatabase db = getReadableDatabase(); + Cursor cursor = db.query(TABLE_NAME, new String[]{COLUMN_PATH}, null, null, null, null, null); + String[] paths = new String[cursor.getCount()]; + int i = 0; + while (cursor.moveToNext()) { + paths[i++] = cursor.getString(0); + } + cursor.close(); + return paths; + } +} \ No newline at end of file diff --git a/gallery/src/main/res/drawable/ic_pin.xml b/gallery/src/main/res/drawable/ic_pin.xml new file mode 100644 index 0000000..9963da0 --- /dev/null +++ b/gallery/src/main/res/drawable/ic_pin.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/gallery/src/main/res/layout/item_album.xml b/gallery/src/main/res/layout/item_album.xml index a73ebb1..4947a7e 100644 --- a/gallery/src/main/res/layout/item_album.xml +++ b/gallery/src/main/res/layout/item_album.xml @@ -9,8 +9,8 @@ android:id="@+id/album_cover" android:layout_width="match_parent" android:layout_height="120dp" - android:scaleType="centerCrop" - android:background="@color/black"/> + android:layout_margin="2dp" + android:scaleType="centerCrop"/> + +