From 65323628ffa46056fadd3dd0449b12e3f99c0476 Mon Sep 17 00:00:00 2001 From: lihongwei Date: Tue, 15 Oct 2024 16:05:25 +0800 Subject: [PATCH] =?UTF-8?q?V1.0.2(4)=20=E6=B7=BB=E5=8A=A0=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E6=9C=AC=E5=9C=B0=E5=9B=BE=E7=89=87=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 4 +- app/proguard-rules.pro | 4 +- app/src/main/AndroidManifest.xml | 9 +- .../com/lh/wallpaper2/DetailsActivity.java | 9 +- .../com/lh/wallpaper2/InitialActivity.java | 2 +- .../java/com/lh/wallpaper2/MainActivity.java | 11 +- .../com/lh/wallpaper2/SettingActivity.java | 92 +++++++ .../java/com/lh/wallpaper2/ViewActivity.java | 37 ++- .../action/FavoriteWallpaperListener.java | 2 +- .../lh/wallpaper2/adapter/DetailsAdapter.java | 1 + .../adapter/FavoriteWallpaperAdapter.java | 3 +- .../adapter/ImageRecyclerViewAdapter.java | 109 +++++++++ .../adapter/InfoWallpaperAdapter.java | 12 +- .../wallpaper2/fragment/FavoriteFragment.java | 8 +- .../lh/wallpaper2/fragment/HomeFragment.java | 25 +- .../wallpaper2/fragment/ImportFragment.java | 231 ++++++++++++++++++ .../{entity => room}/AppDatabase.java | 10 +- .../lh/wallpaper2/{db => room}/Favorite.java | 2 +- .../com/lh/wallpaper2/room/ImageEntry.java | 31 +++ .../com/lh/wallpaper2/room/ImageEntryDao.java | 26 ++ .../lh/wallpaper2/{dao => room}/TaskDao.java | 4 +- app/src/main/res/drawable/_delete.xml | 9 + app/src/main/res/drawable/frame.xml | 37 +++ app/src/main/res/drawable/import_icon.xml | 19 ++ app/src/main/res/drawable/setting.xml | 9 + app/src/main/res/layout/activity_main.xml | 5 +- app/src/main/res/layout/activity_setting.xml | 124 ++++++++++ app/src/main/res/layout/activity_view.xml | 65 ++--- app/src/main/res/layout/details_vh.xml | 6 +- app/src/main/res/layout/fragment_favorite.xml | 2 +- app/src/main/res/layout/fragment_home.xml | 22 +- app/src/main/res/layout/fragment_import.xml | 55 +++++ app/src/main/res/layout/fragment_preview.xml | 2 +- .../layout/home_wallpaper_adapter_list.xml | 41 ++-- app/src/main/res/layout/item_import.xml | 25 ++ app/src/main/res/menu/nav_menu.xml | 8 +- app/src/main/res/mipmap-hdpi/import_back.png | Bin 0 -> 178570 bytes app/src/main/res/mipmap-hdpi/import_title.png | Bin 0 -> 18408 bytes 38 files changed, 949 insertions(+), 112 deletions(-) create mode 100644 app/src/main/java/com/lh/wallpaper2/SettingActivity.java create mode 100644 app/src/main/java/com/lh/wallpaper2/adapter/ImageRecyclerViewAdapter.java create mode 100644 app/src/main/java/com/lh/wallpaper2/fragment/ImportFragment.java rename app/src/main/java/com/lh/wallpaper2/{entity => room}/AppDatabase.java (74%) rename app/src/main/java/com/lh/wallpaper2/{db => room}/Favorite.java (94%) create mode 100644 app/src/main/java/com/lh/wallpaper2/room/ImageEntry.java create mode 100644 app/src/main/java/com/lh/wallpaper2/room/ImageEntryDao.java rename app/src/main/java/com/lh/wallpaper2/{dao => room}/TaskDao.java (88%) create mode 100644 app/src/main/res/drawable/_delete.xml create mode 100644 app/src/main/res/drawable/frame.xml create mode 100644 app/src/main/res/drawable/import_icon.xml create mode 100644 app/src/main/res/drawable/setting.xml create mode 100644 app/src/main/res/layout/activity_setting.xml create mode 100644 app/src/main/res/layout/fragment_import.xml create mode 100644 app/src/main/res/layout/item_import.xml create mode 100644 app/src/main/res/mipmap-hdpi/import_back.png create mode 100644 app/src/main/res/mipmap-hdpi/import_title.png diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7ac81c2..576ae1c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -15,8 +15,8 @@ android { minSdk = 23 //noinspection OldTargetApi targetSdk = 34 - versionCode = 3 - versionName = "1.0.1" + versionCode = 4 + versionName = "1.0.2" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" setProperty("archivesBaseName", "WallpapersHaven_V" + versionName + "(${versionCode})_$timestamp") } diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index c4f2b5a..b6bd385 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -27,10 +27,10 @@ -keepclassmembers class * { @androidx.room.Query ; } --keep class com.lh.wallpaper2.entity.AppDatabase { *; } +-keep class com.lh.wallpaper2.room.AppDatabase { *; } -keep class com.lh.wallpaper2.json.Info { *; } -keepclassmembers class com.lh.wallpaper2.json.Url { *; } --keep class com.lh.wallpaper2.db.Favorite { *; } +-keep class com.lh.wallpaper2.room.Favorite { *; } -keep class com.google.gson.** { *; } -keepattributes Signature diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4ad91e3..09c09b8 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,9 +4,11 @@ - - + + + diff --git a/app/src/main/java/com/lh/wallpaper2/DetailsActivity.java b/app/src/main/java/com/lh/wallpaper2/DetailsActivity.java index 5fa00a2..9794169 100644 --- a/app/src/main/java/com/lh/wallpaper2/DetailsActivity.java +++ b/app/src/main/java/com/lh/wallpaper2/DetailsActivity.java @@ -40,7 +40,14 @@ public class DetailsActivity extends AppCompatActivity implements UrlWallpaperLi info = (Info) getIntent().getSerializableExtra(StaticValue.key_info); Log.d("99999999999", "onCreate: " + info.getList().size()); if (info != null) { - textView.setText(info.getName()); + String name = info.getName(); + if (name != null && !name.isEmpty()) { + // 将首字母转换为大写,其他字母保持不变 + String capitalized = name.substring(0, 1).toUpperCase() + name.substring(1); + textView.setText(capitalized); + } else { + textView.setText(name); // 如果 name 为 null 或空,直接设置 + } Log.d("99999999999", "onCreate: " + info.getName()); } setRecyclerView(); diff --git a/app/src/main/java/com/lh/wallpaper2/InitialActivity.java b/app/src/main/java/com/lh/wallpaper2/InitialActivity.java index d5b3cba..e10e163 100644 --- a/app/src/main/java/com/lh/wallpaper2/InitialActivity.java +++ b/app/src/main/java/com/lh/wallpaper2/InitialActivity.java @@ -23,7 +23,6 @@ import java.lang.annotation.Annotation; public class InitialActivity extends AppCompatActivity { private ProgressBar progressBar; // private int progressStatus = 0; - private CountDownTimer countDownTimer; private Handler handler = new Handler(Looper.getMainLooper()); private int progressStatus = 0; @@ -53,6 +52,7 @@ public class InitialActivity extends AppCompatActivity { } Intent intent = new Intent(InitialActivity.this, MainActivity.class); startActivity(intent); + finish(); } }).start(); } diff --git a/app/src/main/java/com/lh/wallpaper2/MainActivity.java b/app/src/main/java/com/lh/wallpaper2/MainActivity.java index 6f88100..d904023 100644 --- a/app/src/main/java/com/lh/wallpaper2/MainActivity.java +++ b/app/src/main/java/com/lh/wallpaper2/MainActivity.java @@ -21,6 +21,7 @@ import com.google.android.material.bottomnavigation.BottomNavigationView; import com.google.android.material.navigation.NavigationBarView; import com.lh.wallpaper2.fragment.FavoriteFragment; import com.lh.wallpaper2.fragment.HomeFragment; +import com.lh.wallpaper2.fragment.ImportFragment; import com.lh.wallpaper2.fragment.SettingFragment; import com.lh.wallpaper2.adapter.MyFragmentStateAdapter; @@ -40,8 +41,8 @@ public class MainActivity extends AppCompatActivity { viewPager = findViewById(R.id.viewPager); List fragments = new ArrayList<>(); fragments.add(new HomeFragment()); + fragments.add(new ImportFragment()); fragments.add(new FavoriteFragment()); - fragments.add(new SettingFragment()); //若跳转多个界面添加多个fragment MyFragmentStateAdapter adapter = new MyFragmentStateAdapter(getSupportFragmentManager(), fragments); viewPager.setAdapter(adapter); @@ -52,9 +53,9 @@ public class MainActivity extends AppCompatActivity { public boolean onNavigationItemSelected(@NonNull MenuItem item) { if (item.getItemId() == R.id.navigation_home) { viewPager.setCurrentItem(0); - } if (item.getItemId() == R.id.navigation_favorite){ + } if (item.getItemId() == R.id.navigation_import){ viewPager.setCurrentItem(1); - } if (item.getItemId() == R.id.navigation_setting) { + } if (item.getItemId() == R.id.navigation_favorite) { viewPager.setCurrentItem(2); } return true; @@ -72,10 +73,10 @@ public class MainActivity extends AppCompatActivity { navigationView.setSelectedItemId(R.id.navigation_home); break; case 1: - navigationView.setSelectedItemId(R.id.navigation_favorite); + navigationView.setSelectedItemId(R.id.navigation_import); break; case 2: - navigationView.setSelectedItemId(R.id.navigation_setting); + navigationView.setSelectedItemId(R.id.navigation_favorite); break; } } diff --git a/app/src/main/java/com/lh/wallpaper2/SettingActivity.java b/app/src/main/java/com/lh/wallpaper2/SettingActivity.java new file mode 100644 index 0000000..becb437 --- /dev/null +++ b/app/src/main/java/com/lh/wallpaper2/SettingActivity.java @@ -0,0 +1,92 @@ +package com.lh.wallpaper2; + +import android.annotation.SuppressLint; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Bundle; +import android.view.View; +import android.widget.ImageView; +import android.widget.RelativeLayout; + +import androidx.appcompat.app.AppCompatActivity; + +public class SettingActivity extends AppCompatActivity { + private RelativeLayout about; + private RelativeLayout feedBack; + private RelativeLayout privacy; + private ImageView back; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_setting); // 新布局文件 + + about = findViewById(R.id.about); + feedBack = findViewById(R.id.feedback); + privacy = findViewById(R.id.Privacy); + back = findViewById(R.id.setting_back); + + back.setOnClickListener(v -> {finish();}); + + privacy.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(SettingActivity.this, PrivacyActivity.class); + startActivity(intent); + } + }); + + about.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + about(); + } + }); + + feedBack.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + @SuppressLint("IntentWithNullActionLaunch") + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse("https://play.google.com/store/apps/details?id=" + getPackageName())); + startActivity(intent); + } + }); + } + + public void about() { + final AlertDialog dialog; + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("About"); + + builder.setMessage("The current version is " + getVersion()); + builder.setPositiveButton("CONFIRM", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); //关闭对话框 + } + }); + dialog = builder.create(); + dialog.show(); + } + + public String getVersion() { + try { + PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0); + return packageInfo.versionName; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public void onBackPressed() { + super.onBackPressed(); + finish(); + } +} diff --git a/app/src/main/java/com/lh/wallpaper2/ViewActivity.java b/app/src/main/java/com/lh/wallpaper2/ViewActivity.java index 6c7cd36..9d57ca7 100644 --- a/app/src/main/java/com/lh/wallpaper2/ViewActivity.java +++ b/app/src/main/java/com/lh/wallpaper2/ViewActivity.java @@ -1,5 +1,5 @@ package com.lh.wallpaper2; -import android.Manifest; + import android.annotation.SuppressLint; import android.app.WallpaperManager; import android.content.Intent; @@ -13,6 +13,7 @@ import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; + import androidx.activity.EdgeToEdge; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -21,19 +22,22 @@ import androidx.cardview.widget.CardView; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentStatePagerAdapter; import androidx.viewpager.widget.ViewPager; + import com.bumptech.glide.Glide; +import com.bumptech.glide.load.resource.bitmap.CenterCrop; import com.bumptech.glide.request.target.CustomTarget; import com.bumptech.glide.request.transition.Transition; -import com.google.android.material.floatingactionbutton.FloatingActionButton; -import com.lh.wallpaper2.dao.TaskDao; -import com.lh.wallpaper2.db.Favorite; +import com.lh.wallpaper2.room.TaskDao; +import com.lh.wallpaper2.room.Favorite; import com.lh.wallpaper2.download.ImageDownloadTask; -import com.lh.wallpaper2.entity.AppDatabase; +import com.lh.wallpaper2.room.AppDatabase; import com.lh.wallpaper2.fragment.PreviewFragment; import com.lh.wallpaper2.json.Url; + import java.io.IOException; import java.util.ArrayList; import java.util.List; + public class ViewActivity extends AppCompatActivity { private ArrayList url; private int position; @@ -51,8 +55,10 @@ public class ViewActivity extends AppCompatActivity { private Favorite info; private Url homeInfo; private String topInfo; + private String importurl; private ImageDownloadTask downloadTask; private ProgressBar process; + @SuppressLint("MissingInflatedId") @Override protected void onCreate(Bundle savedInstanceState) { @@ -67,10 +73,11 @@ public class ViewActivity extends AppCompatActivity { download = findViewById(R.id.download); collect = findViewById(R.id.collection); textViewLoading = findViewById(R.id.textview_loading); - process=findViewById(R.id.progressbar); + process = findViewById(R.id.progressbar); //初始化db initDb(); - topInfo=(String) getIntent().getSerializableExtra("top_info"); + topInfo = (String) getIntent().getSerializableExtra("top_info"); + importurl = (String) getIntent().getSerializableExtra("import"); info = (Favorite) getIntent().getSerializableExtra("info"); url = (ArrayList) getIntent().getSerializableExtra(StaticValue.key_picture); homeInfo = (Url) getIntent().getSerializableExtra("home_info"); @@ -79,14 +86,18 @@ public class ViewActivity extends AppCompatActivity { if (info != null) { selectPreImg = info.getPicture(); judge(); - } else if (homeInfo != null) { + }else if (importurl != null){ + download.setVisibility(View.GONE); + selectPreImg = importurl; + judge(); + } + else if (homeInfo != null) { selectPreImg = homeInfo.getSourceUrl(); judge(); } else if (topInfo != null) { selectPreImg = topInfo; judge(); - } - else { + } else { selectPreImg = url.get(position).getSourceUrl(); judge(); } @@ -172,9 +183,10 @@ public class ViewActivity extends AppCompatActivity { } }); } + private void initDb() { //初始化db - AppDatabase db = AppDatabase.getDatabase(this); + AppDatabase db = AppDatabase.getInstance(this); dao = db.taskDao(); } @@ -184,7 +196,7 @@ public class ViewActivity extends AppCompatActivity { public void run() { Log.d("2323232", "run: " + selectPreImg); if (dao.getTaskByUrl(selectPreImg) != null) { - Log.d("2323232", "run: "+dao.getTaskByUrl(selectPreImg)); + Log.d("2323232", "run: " + dao.getTaskByUrl(selectPreImg)); runOnUiThread(new Runnable() { @Override public void run() { @@ -201,6 +213,7 @@ public class ViewActivity extends AppCompatActivity { Glide.with(this) .asBitmap() .load(selectPreImg) + .centerInside() .into(new CustomTarget() { @Override public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition transition) { diff --git a/app/src/main/java/com/lh/wallpaper2/action/FavoriteWallpaperListener.java b/app/src/main/java/com/lh/wallpaper2/action/FavoriteWallpaperListener.java index 325f273..f9a0055 100644 --- a/app/src/main/java/com/lh/wallpaper2/action/FavoriteWallpaperListener.java +++ b/app/src/main/java/com/lh/wallpaper2/action/FavoriteWallpaperListener.java @@ -1,7 +1,7 @@ package com.lh.wallpaper2.action; -import com.lh.wallpaper2.db.Favorite; +import com.lh.wallpaper2.room.Favorite; public interface FavoriteWallpaperListener { diff --git a/app/src/main/java/com/lh/wallpaper2/adapter/DetailsAdapter.java b/app/src/main/java/com/lh/wallpaper2/adapter/DetailsAdapter.java index bcdc4b2..05c5de0 100644 --- a/app/src/main/java/com/lh/wallpaper2/adapter/DetailsAdapter.java +++ b/app/src/main/java/com/lh/wallpaper2/adapter/DetailsAdapter.java @@ -51,6 +51,7 @@ public class DetailsAdapter extends RecyclerView.Adapter { Glide.with(myContext) .load(info.getPreUrl()) .transform(new RoundedCorners(ReadFile.dp2Px(7))) + .placeholder(R.drawable.preview) .into(imageView); holder.getItemRoot().setOnClickListener(new View.OnClickListener() { @Override diff --git a/app/src/main/java/com/lh/wallpaper2/adapter/FavoriteWallpaperAdapter.java b/app/src/main/java/com/lh/wallpaper2/adapter/FavoriteWallpaperAdapter.java index dfd8a29..b1b5964 100644 --- a/app/src/main/java/com/lh/wallpaper2/adapter/FavoriteWallpaperAdapter.java +++ b/app/src/main/java/com/lh/wallpaper2/adapter/FavoriteWallpaperAdapter.java @@ -13,7 +13,7 @@ import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.bitmap.RoundedCorners; import com.lh.wallpaper2.R; import com.lh.wallpaper2.action.FavoriteWallpaperListener; -import com.lh.wallpaper2.db.Favorite; +import com.lh.wallpaper2.room.Favorite; import com.lh.wallpaper2.file.ReadFile; import com.lh.wallpaper2.recycleView.DetailsWallpaperVH; @@ -45,6 +45,7 @@ public class FavoriteWallpaperAdapter extends RecyclerView.Adapter { + private List imagePaths; + private final Activity context; + private OnImageDeleteListener onImageDeleteListener; // 删除监听器 + + public ImageRecyclerViewAdapter(List imagePaths, Activity context) { + this.imagePaths = imagePaths; + this.context = context; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.item_import, parent, false); + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + String imagePath = imagePaths.get(position); + + RequestOptions requestOptions = new RequestOptions() + .transform(new CenterCrop(), new RoundedCorners(20)); // 20 是圆角半径 + + if (imagePath.startsWith("/data/user/")) { + Glide.with(context) + .load(imagePath) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .apply(requestOptions) + .placeholder(R.drawable.preview) + .into(holder.imageView); + } else { + Glide.with(context) + .load("file:///android_asset/" + imagePath) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .apply(requestOptions) + .placeholder(R.drawable.preview) + .into(holder.imageView); + } + + holder.imageView.setOnClickListener(v -> { + Intent intent = new Intent(context, ViewActivity.class); + intent.putExtra("import", imagePath); + context.startActivity(intent); + }); + + // 设置删除按钮的点击事件 + holder.delete.setOnClickListener(v -> { + int adapterPosition = holder.getAdapterPosition(); // 动态获取当前位置 + if (adapterPosition != RecyclerView.NO_POSITION && onImageDeleteListener != null) { + onImageDeleteListener.onImageDelete(imagePaths.get(adapterPosition)); // 调用删除回调 + } + }); + } + + @Override + public int getItemCount() { + return imagePaths.size(); + } + + // 更新数据并通知数据集更改 + public void updateImagePaths(List newImagePaths) { + this.imagePaths = newImagePaths; + notifyDataSetChanged(); + } + + // 设置删除监听器 + public void setOnImageDeleteListener(OnImageDeleteListener listener) { + this.onImageDeleteListener = listener; + } + + public interface OnImageDeleteListener { + void onImageDelete(String imagePath); + } + + static class ViewHolder extends RecyclerView.ViewHolder { + ImageView imageView; + ImageView delete; + + ViewHolder(View view) { + super(view); + imageView = view.findViewById(R.id.imageView_wallpaper); + delete = view.findViewById(R.id.delete); + } + } +} diff --git a/app/src/main/java/com/lh/wallpaper2/adapter/InfoWallpaperAdapter.java b/app/src/main/java/com/lh/wallpaper2/adapter/InfoWallpaperAdapter.java index 961fefc..65eb2c4 100644 --- a/app/src/main/java/com/lh/wallpaper2/adapter/InfoWallpaperAdapter.java +++ b/app/src/main/java/com/lh/wallpaper2/adapter/InfoWallpaperAdapter.java @@ -38,6 +38,7 @@ public class InfoWallpaperAdapter extends RecyclerView.Adapter public void setInfoWallpaperListener(InfoWallpaperListener infoWallpaperListener) { this.infoWallpaperListener = infoWallpaperListener; } + public InfoWallpaperAdapter(List infoList, Context myCon) { dataInfo = infoList; myContext = myCon; @@ -53,7 +54,16 @@ public class InfoWallpaperAdapter extends RecyclerView.Adapter @Override public void onBindViewHolder(@NonNull InfoWallpaperVH holder, int position) { Info info = dataInfo.get(position); - holder.getText().setText(info.getName()); + String name = info.getName(); + + if (name != null && !name.isEmpty()) { + // 将首字母转换为大写,其他字母保持不变 + String capitalized = name.substring(0, 1).toUpperCase() + name.substring(1); + holder.getText().setText(capitalized); + } else { + holder.getText().setText(name); // 如果 name 为 null 或空,直接设置 + } + ImageView leftImage = holder.getLeftImage(); ImageView rightImage = holder.getRightImage(); Url homeLeftUrl = info.getList().get(0); diff --git a/app/src/main/java/com/lh/wallpaper2/fragment/FavoriteFragment.java b/app/src/main/java/com/lh/wallpaper2/fragment/FavoriteFragment.java index 9ba7d02..1cdcd20 100644 --- a/app/src/main/java/com/lh/wallpaper2/fragment/FavoriteFragment.java +++ b/app/src/main/java/com/lh/wallpaper2/fragment/FavoriteFragment.java @@ -19,9 +19,9 @@ import com.lh.wallpaper2.R; import com.lh.wallpaper2.ViewActivity; import com.lh.wallpaper2.action.FavoriteWallpaperListener; import com.lh.wallpaper2.adapter.FavoriteWallpaperAdapter; -import com.lh.wallpaper2.dao.TaskDao; -import com.lh.wallpaper2.db.Favorite; -import com.lh.wallpaper2.entity.AppDatabase; +import com.lh.wallpaper2.room.TaskDao; +import com.lh.wallpaper2.room.Favorite; +import com.lh.wallpaper2.room.AppDatabase; import com.lh.wallpaper2.file.MyItemSpace; import java.util.ArrayList; import java.util.List; @@ -47,7 +47,7 @@ public class FavoriteFragment extends Fragment implements FavoriteWallpaperListe likeBackground = view.findViewById(R.id.like_background); likeText = view.findViewById(R.id.like_text); - db = AppDatabase.getDatabase(requireContext()); + db = AppDatabase.getInstance(requireContext()); dao = db.taskDao(); setRecyclerviewWallpaper(); loadFavoriteImages(); diff --git a/app/src/main/java/com/lh/wallpaper2/fragment/HomeFragment.java b/app/src/main/java/com/lh/wallpaper2/fragment/HomeFragment.java index 2be6741..c4c0d0a 100644 --- a/app/src/main/java/com/lh/wallpaper2/fragment/HomeFragment.java +++ b/app/src/main/java/com/lh/wallpaper2/fragment/HomeFragment.java @@ -17,6 +17,7 @@ import android.widget.RelativeLayout; import com.bumptech.glide.Glide; import com.lh.wallpaper2.DetailsActivity; import com.lh.wallpaper2.R; +import com.lh.wallpaper2.SettingActivity; import com.lh.wallpaper2.StaticValue; import com.lh.wallpaper2.ViewActivity; import com.lh.wallpaper2.Wallpaper; @@ -30,10 +31,13 @@ public class HomeFragment extends Fragment implements InfoWallpaperListener { private Info info; private RelativeLayout relativeLayout; private ImageView imageView; + private ImageView setting; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } + @SuppressLint("MissingInflatedId") @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, @@ -41,19 +45,28 @@ public class HomeFragment extends Fragment implements InfoWallpaperListener { View view = inflater.inflate(R.layout.fragment_home, container, false); recyclerView = view.findViewById(R.id.home_recyclerView); relativeLayout = view.findViewById(R.id.top_info); - info=Wallpaper.getUserList().get(14); + setting = view.findViewById(R.id.setting); + info = Wallpaper.getUserList().get(14); String topInfo = info.getList().get(0).getSourceUrl(); setRecyclerView(); - imageView=view.findViewById(R.id.top_image); + imageView = view.findViewById(R.id.top_image); Glide.with(requireContext()).load(topInfo).into(imageView); relativeLayout.setOnClickListener(v -> { Intent intent = new Intent(requireContext(), ViewActivity.class); - intent.putExtra("top_info",topInfo); + intent.putExtra("top_info", topInfo); startActivity(intent); }); + setting.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(requireContext(), SettingActivity.class); + startActivity(intent); + } + }); return view; } - private void setRecyclerView(){ + + private void setRecyclerView() { GridLayoutManager gridLayoutManager = new GridLayoutManager(requireContext(), 1); InfoWallpaperAdapter infoWallpaperAdapter = new InfoWallpaperAdapter(Wallpaper.getUserList(), requireContext()); infoWallpaperAdapter.setInfoWallpaperListener(this); @@ -64,14 +77,14 @@ public class HomeFragment extends Fragment implements InfoWallpaperListener { @Override public void onItemClickAction(Info info) { Intent intent = new Intent(requireContext(), DetailsActivity.class); - intent.putExtra(StaticValue.key_info,info); + intent.putExtra(StaticValue.key_info, info); startActivity(intent); } @Override public void onHomeInfoClickAction(Url info) { Intent intent = new Intent(requireContext(), ViewActivity.class); - intent.putExtra("home_info",info); + intent.putExtra("home_info", info); startActivity(intent); } } \ No newline at end of file diff --git a/app/src/main/java/com/lh/wallpaper2/fragment/ImportFragment.java b/app/src/main/java/com/lh/wallpaper2/fragment/ImportFragment.java new file mode 100644 index 0000000..08de780 --- /dev/null +++ b/app/src/main/java/com/lh/wallpaper2/fragment/ImportFragment.java @@ -0,0 +1,231 @@ +package com.lh.wallpaper2.fragment; + +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.Toast; + +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.lh.wallpaper2.R; +import com.lh.wallpaper2.adapter.ImageRecyclerViewAdapter; +import com.lh.wallpaper2.file.MyItemSpace; +import com.lh.wallpaper2.room.AppDatabase; +import com.lh.wallpaper2.room.ImageEntry; +import com.lh.wallpaper2.room.ImageEntryDao; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +public class ImportFragment extends Fragment { + + private static final int PICK_IMAGE_REQUEST_CODE = 202; // 请求码,用于标识图片选择 + private ImageView btnSelectImage; // 选择图片按钮 + private RecyclerView recyclerView; // 显示图片的 RecyclerView + private ImageRecyclerViewAdapter adapter; // 图片适配器 + private List imagePaths = new ArrayList<>(); // 图片路径列表 + private AppDatabase appDatabase; // 数据库实例 + private ImageEntryDao imageEntryDao; // 图片条目 DAO + private LinearLayout linearLayout; // 空视图 + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + // 加载 Fragment 的布局 + View view = inflater.inflate(R.layout.fragment_import, container, false); + + // 初始化控件 + btnSelectImage = view.findViewById(R.id.btn_select_image); + recyclerView = view.findViewById(R.id.recycler_view); + linearLayout = view.findViewById(R.id.empty); + + // 设置 RecyclerView 的布局管理器和适配器 + recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2)); // 网格布局,每行显示两个图片 + MyItemSpace itemDecoration = new MyItemSpace(30, 50, 40); + recyclerView.addItemDecoration(itemDecoration); + + adapter = new ImageRecyclerViewAdapter(imagePaths, requireActivity()); + recyclerView.setAdapter(adapter); + + // 设置选择图片按钮的点击事件 + btnSelectImage.setOnClickListener(v -> openImagePicker()); + + // 初始化数据库和 DAO + appDatabase = AppDatabase.getInstance(requireContext()); + imageEntryDao = appDatabase.imageEntryDao(); + + // 加载图片路径 + loadImagePaths(); + + // 设置图片删除监听器 + adapter.setOnImageDeleteListener(imagePath -> { + // 从数据库中删除图片记录 + new Thread(() -> { + // 删除本地存储中的图片文件 + File imageFile = new File(imagePath); + if (imageFile.exists() && imageFile.delete()) { // 删除文件,成功返回 true + // 文件删除成功后,再删除数据库中的图片记录和更新列表 + imageEntryDao.deleteByPath(imagePath); // 删除数据库中的图片记录 + imagePaths.remove(imagePath); // 从列表中删除图片路径 + + requireActivity().runOnUiThread(() -> { + adapter.updateImagePaths(imagePaths); // 更新 RecyclerView + setView(!imagePaths.isEmpty()); // 更新视图 + Toast.makeText(getContext(), "Image deleted", Toast.LENGTH_SHORT).show(); + }); + } else { + // 文件删除失败时的处理 + requireActivity().runOnUiThread(() -> { + Toast.makeText(getContext(), "Failed to delete image file", Toast.LENGTH_SHORT).show(); + }); + } + }).start(); + }); + + + return view; + } + + @Override + public void onResume() { + super.onResume(); + adapter.notifyDataSetChanged(); // 重新加载适配器内容 + } + + // 打开图片选择器 + private void openImagePicker() { + Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); + startActivityForResult(intent, PICK_IMAGE_REQUEST_CODE); // 启动选择图片的活动 + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == PICK_IMAGE_REQUEST_CODE && resultCode == getActivity().RESULT_OK && data != null) { + Uri selectedImageUri = data.getData(); // 获取选中的图片 URI + if (selectedImageUri != null) { + try { + if (isImageSizeAcceptable(selectedImageUri)) { + saveImageToInternalStorage(selectedImageUri); // 保存图片到内部存储 + } else { + Toast.makeText(getContext(), "图片大小超过限制", Toast.LENGTH_SHORT).show(); + } + } catch (IOException e) { + e.printStackTrace(); + Toast.makeText(getContext(), "无法获取图片大小: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + } + } + + // 检查图片大小是否在允许范围内 + private boolean isImageSizeAcceptable(Uri uri) throws IOException { + InputStream inputStream = requireContext().getContentResolver().openInputStream(uri); + if (inputStream == null) { + return false; + } + long fileSize = inputStream.available(); + inputStream.close(); + long maxFileSize = 10 * 1024 * 1024; // 最大 10MB + return fileSize <= maxFileSize; + } + + // 将选中的图片保存到内部存储 + private void saveImageToInternalStorage(Uri uri) { + try { + InputStream inputStream = requireContext().getContentResolver().openInputStream(uri); + Bitmap bitmap = BitmapFactory.decodeStream(inputStream); + if (bitmap == null) { + Toast.makeText(getContext(), "无法加载图片", Toast.LENGTH_SHORT).show(); + return; + } + File internalStorageDir = requireContext().getFilesDir(); + File imageFile = new File(internalStorageDir, System.currentTimeMillis() + ".jpg"); + FileOutputStream outputStream = new FileOutputStream(imageFile); + bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream); + outputStream.close(); + inputStream.close(); + + String imagePath = imageFile.getAbsolutePath(); + new Thread(() -> { + if (isImageAlreadyExists(imagePath)) { + requireActivity().runOnUiThread(() -> Toast.makeText(getContext(), "该图片已经存在", Toast.LENGTH_SHORT).show()); + imageFile.delete(); + return; + } + imagePaths.add(imagePath); + requireActivity().runOnUiThread(() -> { + adapter.updateImagePaths(imagePaths); + setView(!imagePaths.isEmpty()); + }); + imageEntryDao.insert(new ImageEntry(imagePath)); + }).start(); + + } catch (IOException e) { + e.printStackTrace(); + Toast.makeText(getContext(), "保存图片失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + } + + // 检查图片是否已经存在 + private boolean isImageAlreadyExists(String imagePath) { + File newImageFile = new File(imagePath); + for (String path : imagePaths) { + File existingFile = new File(path); + if (filesAreIdentical(existingFile, newImageFile)) { + return true; + } + } + List imageEntries = imageEntryDao.getAllImages(); + for (ImageEntry imageEntry : imageEntries) { + File existingFile = new File(imageEntry.getImagePath()); + if (filesAreIdentical(existingFile, newImageFile)) { + return true; + } + } + return false; + } + + // 比较两个文件是否相同 + private boolean filesAreIdentical(File file1, File file2) { + return file1.length() == file2.length(); // 比较文件长度 + } + + // 加载图片路径列表 + private void loadImagePaths() { + new Thread(() -> { + imagePaths.clear(); // 清空列表,防止重复添加 + List imageEntries = imageEntryDao.getAllImages(); + for (ImageEntry imageEntry : imageEntries) { + imagePaths.add(imageEntry.getImagePath()); // 添加路径到列表 + } + requireActivity().runOnUiThread(() -> { + adapter.updateImagePaths(imagePaths); + setView(!imagePaths.isEmpty()); + }); + }).start(); + } + + // 更新视图,切换空视图与图片视图 + private void setView(Boolean hasData) { + if (hasData) { + recyclerView.setVisibility(View.VISIBLE); + linearLayout.setVisibility(View.GONE); + } else { + recyclerView.setVisibility(View.GONE); + linearLayout.setVisibility(View.VISIBLE); + } + } +} diff --git a/app/src/main/java/com/lh/wallpaper2/entity/AppDatabase.java b/app/src/main/java/com/lh/wallpaper2/room/AppDatabase.java similarity index 74% rename from app/src/main/java/com/lh/wallpaper2/entity/AppDatabase.java rename to app/src/main/java/com/lh/wallpaper2/room/AppDatabase.java index 1e92aa4..0af8d8f 100644 --- a/app/src/main/java/com/lh/wallpaper2/entity/AppDatabase.java +++ b/app/src/main/java/com/lh/wallpaper2/room/AppDatabase.java @@ -1,4 +1,4 @@ -package com.lh.wallpaper2.entity; +package com.lh.wallpaper2.room; import android.content.Context; @@ -6,16 +6,14 @@ import androidx.room.Database; import androidx.room.Room; import androidx.room.RoomDatabase; -import com.lh.wallpaper2.dao.TaskDao; -import com.lh.wallpaper2.db.Favorite; - -@Database(entities = {Favorite.class}, version = 1) +@Database(entities = {Favorite.class, ImageEntry.class}, version = 1) public abstract class AppDatabase extends RoomDatabase { public abstract TaskDao taskDao(); + public abstract ImageEntryDao imageEntryDao(); private static volatile AppDatabase INSTANCE; - public static AppDatabase getDatabase(final Context context) { + public static AppDatabase getInstance(final Context context) { if (INSTANCE == null) { synchronized (AppDatabase.class) { if (INSTANCE == null) { diff --git a/app/src/main/java/com/lh/wallpaper2/db/Favorite.java b/app/src/main/java/com/lh/wallpaper2/room/Favorite.java similarity index 94% rename from app/src/main/java/com/lh/wallpaper2/db/Favorite.java rename to app/src/main/java/com/lh/wallpaper2/room/Favorite.java index 93a54dd..69de5a9 100644 --- a/app/src/main/java/com/lh/wallpaper2/db/Favorite.java +++ b/app/src/main/java/com/lh/wallpaper2/room/Favorite.java @@ -1,4 +1,4 @@ -package com.lh.wallpaper2.db; +package com.lh.wallpaper2.room; import androidx.room.ColumnInfo; import androidx.room.Entity; import androidx.room.PrimaryKey; diff --git a/app/src/main/java/com/lh/wallpaper2/room/ImageEntry.java b/app/src/main/java/com/lh/wallpaper2/room/ImageEntry.java new file mode 100644 index 0000000..613d5d5 --- /dev/null +++ b/app/src/main/java/com/lh/wallpaper2/room/ImageEntry.java @@ -0,0 +1,31 @@ +package com.lh.wallpaper2.room; + +import androidx.room.Entity; +import androidx.room.PrimaryKey; + +@Entity(tableName = "image_entry") +public class ImageEntry { + @PrimaryKey(autoGenerate = true) + private int id; + private String imagePath; + + public ImageEntry(String imagePath) { + this.imagePath = imagePath; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getImagePath() { + return imagePath; + } + + public void setImagePath(String imagePath) { + this.imagePath = imagePath; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lh/wallpaper2/room/ImageEntryDao.java b/app/src/main/java/com/lh/wallpaper2/room/ImageEntryDao.java new file mode 100644 index 0000000..6b3c5aa --- /dev/null +++ b/app/src/main/java/com/lh/wallpaper2/room/ImageEntryDao.java @@ -0,0 +1,26 @@ +package com.lh.wallpaper2.room; + +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.Query; + +import java.util.List; + +@Dao +public interface ImageEntryDao { + @Insert + void insert(ImageEntry imageEntry); + + @Delete + void delete(ImageEntry imageEntry); + + @Query("SELECT * FROM image_entry") + List getAllImages(); + + @Query("SELECT * FROM image_entry WHERE imagePath = :imagePath LIMIT 1") + ImageEntry findByPath(String imagePath); + + @Query("DELETE FROM image_entry WHERE imagePath = :imagePath") + void deleteByPath(String imagePath); +} diff --git a/app/src/main/java/com/lh/wallpaper2/dao/TaskDao.java b/app/src/main/java/com/lh/wallpaper2/room/TaskDao.java similarity index 88% rename from app/src/main/java/com/lh/wallpaper2/dao/TaskDao.java rename to app/src/main/java/com/lh/wallpaper2/room/TaskDao.java index 8402ed9..f349b63 100644 --- a/app/src/main/java/com/lh/wallpaper2/dao/TaskDao.java +++ b/app/src/main/java/com/lh/wallpaper2/room/TaskDao.java @@ -1,9 +1,9 @@ -package com.lh.wallpaper2.dao; +package com.lh.wallpaper2.room; import androidx.room.Dao; import androidx.room.Insert; import androidx.room.Query; import androidx.room.Update; -import com.lh.wallpaper2.db.Favorite; + import java.util.List; @Dao diff --git a/app/src/main/res/drawable/_delete.xml b/app/src/main/res/drawable/_delete.xml new file mode 100644 index 0000000..2820e62 --- /dev/null +++ b/app/src/main/res/drawable/_delete.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/frame.xml b/app/src/main/res/drawable/frame.xml new file mode 100644 index 0000000..8e3e1ce --- /dev/null +++ b/app/src/main/res/drawable/frame.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/import_icon.xml b/app/src/main/res/drawable/import_icon.xml new file mode 100644 index 0000000..490c6e9 --- /dev/null +++ b/app/src/main/res/drawable/import_icon.xml @@ -0,0 +1,19 @@ + + + + + + + diff --git a/app/src/main/res/drawable/setting.xml b/app/src/main/res/drawable/setting.xml new file mode 100644 index 0000000..0ec04a6 --- /dev/null +++ b/app/src/main/res/drawable/setting.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 95fbba0..9eb3049 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -3,13 +3,16 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" tools:context=".MainActivity"> + android:layout_height="match_parent" + android:layout_above="@id/bottomNavigation" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_view.xml b/app/src/main/res/layout/activity_view.xml index 7c2a1f9..cdf68a7 100644 --- a/app/src/main/res/layout/activity_view.xml +++ b/app/src/main/res/layout/activity_view.xml @@ -38,6 +38,7 @@ android:layout_marginTop="45dp" android:background="@drawable/round_button" android:padding="5dp"> + - - - - + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toStartOf="@+id/download" + app:layout_constraintHorizontal_bias="0.5"> + android:foreground="@drawable/share_icon" /> - + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toEndOf="@id/share" + app:layout_constraintEnd_toStartOf="@+id/collection_layout" + app:layout_constraintHorizontal_bias="0.5"> + + + + + + + android:foreground="@drawable/dislike" /> - + diff --git a/app/src/main/res/layout/details_vh.xml b/app/src/main/res/layout/details_vh.xml index 30de314..4d65363 100644 --- a/app/src/main/res/layout/details_vh.xml +++ b/app/src/main/res/layout/details_vh.xml @@ -1,15 +1,15 @@ + android:layout_height="match_parent" + android:scaleType="centerCrop"/> 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-hdpi/import_title.png b/app/src/main/res/mipmap-hdpi/import_title.png new file mode 100644 index 0000000000000000000000000000000000000000..b6cef58da64be10f910466922a56e6f34461fe07 GIT binary patch literal 18408 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%0AZq`csJ39Gt4l`q&T&^+0VlpllyoW$mxP|* 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