添加相册集浏览窗口图片置顶功能
- 新增 PinnedImageDbHelper 数据库帮助类,存储图片置顶路径 - 使用独立数据库文件 pinned_image.db 存储图片置顶数据 - 相册集封面试图添加置顶/取消置顶菜单,长按弹出 - 置顶图片显示置顶图标并排在前面显示 - 相册集浏览窗口初始加载时按置顶排序
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Sun Apr 26 09:00:16 CST 2026
|
||||
#Sun Apr 26 09:40:02 CST 2026
|
||||
stageCount=4
|
||||
libraryProject=
|
||||
baseVersion=15.0
|
||||
publishVersion=15.0.3
|
||||
buildCount=11
|
||||
buildCount=22
|
||||
baseBetaVersion=15.0.4
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cc.winboll.studio.gallery;
|
||||
|
||||
import android.content.DialogInterface;
|
||||
import android.net.Uri;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -10,6 +11,8 @@ import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.bumptech.glide.Glide;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
||||
import cc.winboll.studio.libappbase.LogUtils;
|
||||
|
||||
@@ -20,6 +23,7 @@ public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ViewHolder>
|
||||
private OnImageClickListener listener;
|
||||
private int bgType = 0;
|
||||
private Preferences prefs;
|
||||
private PinnedImageDbHelper pinnedDbHelper;
|
||||
|
||||
private int getBgRes() {
|
||||
switch (bgType) {
|
||||
@@ -45,13 +49,60 @@ public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ViewHolder>
|
||||
public void setData(ArrayList<Uri> urls, ArrayList<String> paths) {
|
||||
this.imageUrls = urls;
|
||||
this.imagePaths = paths;
|
||||
sortPinnedFirst();
|
||||
LogUtils.d(TAG, "setData: " + urls.size() + " images");
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void sortPinnedFirst() {
|
||||
if (pinnedDbHelper == null || imagePaths.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ArrayList<String> pinnedPaths = new ArrayList<>();
|
||||
ArrayList<String> unpinnedPaths = new ArrayList<>();
|
||||
for (String path : imagePaths) {
|
||||
if (pinnedDbHelper.isPinned(path)) {
|
||||
pinnedPaths.add(path);
|
||||
} else {
|
||||
unpinnedPaths.add(path);
|
||||
}
|
||||
}
|
||||
Comparator<String> pathComparator = new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(String p1, String p2) {
|
||||
return p1.compareToIgnoreCase(p2);
|
||||
}
|
||||
};
|
||||
Collections.sort(pinnedPaths, pathComparator);
|
||||
Collections.sort(unpinnedPaths, pathComparator);
|
||||
|
||||
ArrayList<Uri> newUrls = new ArrayList<>();
|
||||
ArrayList<String> newPaths = new ArrayList<>();
|
||||
for (String path : pinnedPaths) {
|
||||
int index = imagePaths.indexOf(path);
|
||||
if (index >= 0) {
|
||||
newUrls.add(imageUrls.get(index));
|
||||
newPaths.add(path);
|
||||
}
|
||||
}
|
||||
for (String path : unpinnedPaths) {
|
||||
int index = imagePaths.indexOf(path);
|
||||
if (index >= 0) {
|
||||
newUrls.add(imageUrls.get(index));
|
||||
newPaths.add(path);
|
||||
}
|
||||
}
|
||||
|
||||
imageUrls.clear();
|
||||
imagePaths.clear();
|
||||
imageUrls.addAll(newUrls);
|
||||
imagePaths.addAll(newPaths);
|
||||
}
|
||||
|
||||
public void setContext(android.content.Context context) {
|
||||
prefs = new Preferences(context);
|
||||
bgType = prefs.getBgType();
|
||||
pinnedDbHelper = PinnedImageDbHelper.getInstance(context);
|
||||
}
|
||||
|
||||
public void refreshBg() {
|
||||
@@ -60,7 +111,37 @@ public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ViewHolder>
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void refreshPinned() {
|
||||
if (pinnedDbHelper == null || imagePaths.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
sortPinnedFirst();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void showContextMenu(View view, final int position) {
|
||||
final String imagePath = imagePaths.get(position);
|
||||
android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(view.getContext());
|
||||
builder.setTitle("Image");
|
||||
boolean isPinned = pinnedDbHelper != null && pinnedDbHelper.isPinned(imagePath);
|
||||
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 && which == 0) {
|
||||
if (isPinned) {
|
||||
pinnedDbHelper.unpinImage(imagePath);
|
||||
} else {
|
||||
pinnedDbHelper.pinImage(imagePath);
|
||||
}
|
||||
refreshPinned();
|
||||
}
|
||||
}
|
||||
});
|
||||
builder.show();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
@@ -80,7 +161,12 @@ public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ViewHolder>
|
||||
|
||||
final ArrayList<Uri> urls = imageUrls;
|
||||
final ArrayList<String> paths = imagePaths;
|
||||
holder.imageView.setOnClickListener(new OnClickListener() {
|
||||
final String imagePath = imagePaths.get(position);
|
||||
|
||||
boolean isPinned = pinnedDbHelper != null && pinnedDbHelper.isPinned(imagePath);
|
||||
holder.pinIcon.setVisibility(isPinned ? View.VISIBLE : View.GONE);
|
||||
|
||||
holder.itemView.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (listener != null) {
|
||||
@@ -88,6 +174,14 @@ public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ViewHolder>
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
showContextMenu(holder.itemView, position);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -97,9 +191,11 @@ public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.ViewHolder>
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
ImageView imageView;
|
||||
ImageView pinIcon;
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
imageView = itemView.findViewById(R.id.image);
|
||||
pinIcon = itemView.findViewById(R.id.pin_icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ 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 String DB_NAME = "pinned_album.db";
|
||||
private static final int DB_VERSION = 1;
|
||||
private static final String TABLE_NAME = "pinned_albums";
|
||||
private static final String COLUMN_PATH = "album_path";
|
||||
|
||||
@@ -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 PinnedImageDbHelper extends SQLiteOpenHelper {
|
||||
public static final String TAG = "PinnedImageDbHelper";
|
||||
private static final String DB_NAME = "pinned_image.db";
|
||||
private static final int DB_VERSION = 1;
|
||||
private static final String TABLE_NAME = "pinned_images";
|
||||
private static final String COLUMN_PATH = "image_path";
|
||||
|
||||
private static final String SQL_CREATE = "CREATE TABLE " + TABLE_NAME + " ("
|
||||
+ COLUMN_PATH + " TEXT PRIMARY KEY)";
|
||||
|
||||
private static PinnedImageDbHelper dbHelper;
|
||||
|
||||
public static PinnedImageDbHelper getInstance(Context context) {
|
||||
if (dbHelper == null) {
|
||||
dbHelper = new PinnedImageDbHelper(context.getApplicationContext());
|
||||
}
|
||||
return dbHelper;
|
||||
}
|
||||
|
||||
public PinnedImageDbHelper(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 pinImage(String imagePath) {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(COLUMN_PATH, imagePath);
|
||||
db.insertWithOnConflict(TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_IGNORE);
|
||||
LogUtils.d(TAG, "pinImage: " + imagePath);
|
||||
}
|
||||
|
||||
public void unpinImage(String imagePath) {
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
db.delete(TABLE_NAME, COLUMN_PATH + " = ?", new String[]{imagePath});
|
||||
LogUtils.d(TAG, "unpinImage: " + imagePath);
|
||||
}
|
||||
|
||||
public boolean isPinned(String imagePath) {
|
||||
SQLiteDatabase db = getReadableDatabase();
|
||||
Cursor cursor = db.query(TABLE_NAME, null, COLUMN_PATH + " = ?",
|
||||
new String[]{imagePath}, 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;
|
||||
}
|
||||
}
|
||||
@@ -12,4 +12,15 @@
|
||||
android:scaleType="centerCrop"
|
||||
android:background="@color/black"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pin_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="top|end"
|
||||
android:layout_margin="4dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:padding="3dp"
|
||||
android:src="@drawable/ic_pin"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</FrameLayout>
|
||||
Reference in New Issue
Block a user