V1.0.0(1)完成版

This commit is contained in:
lihongwei 2025-03-28 16:19:38 +08:00
parent 2b76217e86
commit 55b2e6d5fc
20 changed files with 566 additions and 404 deletions

BIN
app/NatureWallpaper.jks Normal file

Binary file not shown.

View File

@ -19,3 +19,17 @@
# If you keep the line number information, uncomment this to # If you keep the line number information, uncomment this to
# hide the original source file name. # hide the original source file name.
#-renamesourcefileattribute SourceFile #-renamesourcefileattribute SourceFile
-keepclassmembers class com.nature.wallpaper.naturewallpaper.MyApplication {
public static final java.lang.String DB_NAME;
public static final int DB_VERSION;
}
-keepclassmembers class * {
@androidx.room.Query <methods>;
}
-keep class com.nature.wallpaper.naturewallpaper.room.AppDatabase{ *; }
-keep class com.nature.wallpaper.naturewallpaper.room.NatureData { *; }
-keep class com.nature.wallpaper.naturewallpaper.room.NatureList { *; }
-keep class com.nature.wallpaper.naturewallpaper.room.NatureDataDao { *; }

View File

@ -9,45 +9,71 @@ import com.nature.wallpaper.naturewallpaper.util.JsonParse;
import com.nature.wallpaper.naturewallpaper.util.RoomUtils; import com.nature.wallpaper.naturewallpaper.util.RoomUtils;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
public class MyApplication extends Application { public class MyApplication extends Application {
private static volatile MyApplication instance;
public static MyApplication application;
public static final int DB_VERSION = 1;
public static final String DB_NAME = "cool_database";
private static final String PREF_NAME = "app_preferences"; private static final String PREF_NAME = "app_preferences";
private static final String KEY_INIT = "isInit"; private static final String KEY_DB_INITIALIZED = "is_database_initialized";
private static final String JSON_FILE_NAME = "nature_wallpapers.json";
public static final int DB_VERSION = 1;
public static final String DB_NAME = "nature_database";
private final ExecutorService executor = Executors.newSingleThreadExecutor();
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
initializeInstance();
application = this; initializeDatabaseIfNeeded();
SharedPreferences sharedPreferences = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
boolean isDatabaseInitialized = sharedPreferences.getBoolean(KEY_INIT, false);
if (!isDatabaseInitialized) {
initializeDatabase();
sharedPreferences.edit().putBoolean(KEY_INIT, true).apply();
} }
private void initializeInstance() {
instance = this;
} }
public static Context getContext() { public static Context getContext() {
return application.getApplicationContext(); if (instance == null) {
throw new IllegalStateException("Application not initialized yet");
}
return instance.getApplicationContext();
} }
private void initializeDatabase() { private void initializeDatabaseIfNeeded() {
Executors.newSingleThreadExecutor().execute(() -> { SharedPreferences prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
List<NatureList> natureListList = getCategoryList(); if (!prefs.getBoolean(KEY_DB_INITIALIZED, false)) {
initializeDatabaseAsync();
markDatabaseAsInitialized(prefs);
}
}
private void initializeDatabaseAsync() {
executor.execute(() -> {
List<NatureList> natureLists = loadCategoryList();
RoomUtils roomUtils = new RoomUtils(getContext()); RoomUtils roomUtils = new RoomUtils(getContext());
roomUtils.insertAllImages(natureListList); roomUtils.insertAllImages(natureLists);
}); });
} }
public static List<NatureList> getCategoryList() { private void markDatabaseAsInitialized(SharedPreferences prefs) {
return JsonParse.parseJson("nature_wallpapers.json"); prefs.edit()
.putBoolean(KEY_DB_INITIALIZED, true)
.apply();
}
public static List<NatureList> loadCategoryList() {
return JsonParse.parseJson(JSON_FILE_NAME);
}
@Override
public void onTerminate() {
super.onTerminate();
shutdownExecutor();
}
private void shutdownExecutor() {
executor.shutdown();
} }
} }

View File

@ -20,88 +20,84 @@ import com.nature.wallpaper.naturewallpaper.databinding.TabLayoutBinding;
public class MainActivity extends AppCompatActivity { public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding; private ActivityMainBinding binding;
private static final int[] TAB_TITLES = {R.string.home, R.string.favorite};
private static final int[] TAB_ICONS_UNSELECTED = {R.drawable.un_home, R.drawable.un_favoriteslist};
private static final int[] TAB_ICONS_SELECTED = {R.drawable.home, R.drawable.favoriteslist};
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setupEdgeToEdge();
initializeBinding();
setupWindowInsets();
setupViewPager();
setupTabLayout();
}
private void setupEdgeToEdge() {
EdgeToEdge.enable(this); EdgeToEdge.enable(this);
}
private void initializeBinding() {
binding = ActivityMainBinding.inflate(getLayoutInflater()); binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot()); setContentView(binding.getRoot());
}
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { private void setupWindowInsets() {
ViewCompat.setOnApplyWindowInsetsListener(binding.getRoot(), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets; return insets;
}); });
initData();
initEvent();
} }
private void initData() { private void setupViewPager() {
MainAdapter adapter = new MainAdapter(this); MainAdapter adapter = new MainAdapter(this);
binding.mainViewpager2.setAdapter(adapter); binding.mainViewpager2.setAdapter(adapter);
} }
private void initEvent() { private void setupTabLayout() {
new TabLayoutMediator(binding.mainTabLayout, binding.mainViewpager2, (tab, position) -> { new TabLayoutMediator(binding.mainTabLayout, binding.mainViewpager2,
TabLayoutBinding tabLayoutBinding = TabLayoutBinding.inflate(LayoutInflater.from(this)); this::configureTab).attach();
tab.setCustomView(tabLayoutBinding.getRoot());
setTab(tabLayoutBinding, position);
}).attach();
binding.mainTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { binding.mainTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override @Override
public void onTabSelected(TabLayout.Tab tab) { public void onTabSelected(TabLayout.Tab tab) {
updateTab(tab, true); updateTabState(tab, true);
} }
@Override @Override
public void onTabUnselected(TabLayout.Tab tab) { public void onTabUnselected(TabLayout.Tab tab) {
updateTab(tab, false); updateTabState(tab, false);
} }
@Override @Override
public void onTabReselected(TabLayout.Tab tab) { public void onTabReselected(TabLayout.Tab tab) {}
}
private void updateTab(TabLayout.Tab tab, boolean isSelected) {
if (tab.getCustomView() != null) {
TabLayoutBinding mainCustomBinding = TabLayoutBinding.bind(tab.getCustomView());
int iconResId = getIconResource(tab.getPosition(), isSelected);
mainCustomBinding.image.setImageResource(iconResId);
int textColor = isSelected ? R.color.black : R.color.gray;
mainCustomBinding.text.setTextColor(ContextCompat.getColor(MainActivity.this, textColor));
}
}
}); });
} }
private void setTab(TabLayoutBinding tabLayoutBinding, int position) { private void configureTab(TabLayout.Tab tab, int position) {
int iconResId = getIconResource(position, false); TabLayoutBinding tabBinding = TabLayoutBinding.inflate(LayoutInflater.from(this));
int textColorResId = R.color.gray; tab.setCustomView(tabBinding.getRoot());
switch (position) { boolean isFirstTab = position == 0;
case 0: tabBinding.text.setText(TAB_TITLES[position]);
tabLayoutBinding.text.setText("Home"); tabBinding.image.setImageResource(isFirstTab ? TAB_ICONS_SELECTED[position] : TAB_ICONS_UNSELECTED[position]);
iconResId = R.drawable.home; tabBinding.text.setTextColor(ContextCompat.getColor(this,
textColorResId = R.color.black; isFirstTab ? R.color.black : R.color.gray));
break;
case 1:
tabLayoutBinding.text.setText("Favorite");
break;
} }
tabLayoutBinding.image.setImageResource(iconResId); private void updateTabState(TabLayout.Tab tab, boolean isSelected) {
tabLayoutBinding.text.setTextColor(ContextCompat.getColor(this, textColorResId)); if (tab.getCustomView() == null) return;
}
private int getIconResource(int position, boolean isSelected) { TabLayoutBinding tabBinding = TabLayoutBinding.bind(tab.getCustomView());
if (position == 1) { int position = tab.getPosition();
return isSelected ? R.drawable.favoriteslist : R.drawable.un_favoriteslist;
} tabBinding.image.setImageResource(isSelected
return isSelected ? R.drawable.home : R.drawable.un_home; ? TAB_ICONS_SELECTED[position]
: TAB_ICONS_UNSELECTED[position]);
tabBinding.text.setTextColor(ContextCompat.getColor(this,
isSelected ? R.color.black : R.color.gray));
} }
@Override @Override

View File

@ -25,7 +25,6 @@ public class NatureListActivity extends AppCompatActivity {
private ActivityNatureListBinding binding; private ActivityNatureListBinding binding;
private WallpaperAdapter wallpaperAdapter; private WallpaperAdapter wallpaperAdapter;
private RoomUtils roomUtils; private RoomUtils roomUtils;
private NatureData coolEntity;
private String name; private String name;
@Override @Override
@ -47,9 +46,9 @@ public class NatureListActivity extends AppCompatActivity {
} }
private void initData() { private void initData() {
coolEntity = (NatureData) getIntent().getSerializableExtra("nature"); NatureData data = (NatureData) getIntent().getSerializableExtra("nature");
if (coolEntity != null) { if (data != null) {
name = coolEntity.getName(); name = data.getName();
} else { } else {
Toast.makeText(this, "The picture does not exist", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "The picture does not exist", Toast.LENGTH_SHORT).show();
finish(); finish();
@ -62,8 +61,7 @@ public class NatureListActivity extends AppCompatActivity {
wallpaperAdapter = new WallpaperAdapter(this, new ArrayList<>(),1); wallpaperAdapter = new WallpaperAdapter(this, new ArrayList<>(),1);
binding.recyclerView.setAdapter(wallpaperAdapter); binding.recyclerView.setAdapter(wallpaperAdapter);
ItemDecoration itemDecoration = new ItemDecoration(25, 15, 10); binding.recyclerView.addItemDecoration(new ItemDecoration(25, 15, 10));
binding.recyclerView.addItemDecoration(itemDecoration);
} }
@ -72,10 +70,10 @@ public class NatureListActivity extends AppCompatActivity {
binding.back.setOnClickListener(v -> finish()); binding.back.setOnClickListener(v -> finish());
binding.text.setText(name); binding.text.setText(name);
loadImage(); loadAllCategory();
} }
private void loadImage() { private void loadAllCategory() {
roomUtils roomUtils
.getAllCategory(name) .getAllCategory(name)
.observe(this, new Observer<List<NatureData>>() { .observe(this, new Observer<List<NatureData>>() {

View File

@ -2,7 +2,6 @@ package com.nature.wallpaper.naturewallpaper.activity;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.CountDownTimer;
import androidx.activity.EdgeToEdge; import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
@ -18,48 +17,70 @@ import com.nature.wallpaper.naturewallpaper.databinding.ActivityStartBinding;
public class StartActivity extends AppCompatActivity { public class StartActivity extends AppCompatActivity {
private ActivityStartBinding binding; private ActivityStartBinding binding;
private static final long TOTAL_TIME = 1000; private static final long TOTAL_TIME_MS = 1000;
private CountDownTimer countDownTimer; private static final long COUNTDOWN_INTERVAL_MS = 100;
private android.os.CountDownTimer countDownTimer;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
EdgeToEdge.enable(this); setupEdgeToEdge();
initializeBinding();
setupWindowInsets();
loadSplashImage();
startCountdown();
}
private void setupEdgeToEdge() {
EdgeToEdge.enable(this);
}
private void initializeBinding() {
binding = ActivityStartBinding.inflate(getLayoutInflater()); binding = ActivityStartBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot()); setContentView(binding.getRoot());
}
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { private void setupWindowInsets() {
ViewCompat.setOnApplyWindowInsetsListener(binding.getRoot(), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets; return insets;
}); });
}
private void loadSplashImage() {
Glide.with(this) Glide.with(this)
.load(R.mipmap.placeholder) .load(R.mipmap.placeholder)
.transform(new CenterCrop(), new RoundedCorners(32)) .transform(new CenterCrop(), new RoundedCorners(32))
.into(binding.image); .into(binding.image);
}
countDownTimer = new CountDownTimer(TOTAL_TIME, 100) { private void startCountdown() {
countDownTimer = new android.os.CountDownTimer(TOTAL_TIME_MS, COUNTDOWN_INTERVAL_MS) {
@Override @Override
public void onTick(long millisUntilFinished) { public void onTick(long millisUntilFinished) {
int percentage = (int) (100 - (float) millisUntilFinished / TOTAL_TIME * 100); updateProgress(millisUntilFinished);
binding.progressBar.setProgress(percentage);
} }
@Override @Override
public void onFinish() { public void onFinish() {
startMain(); navigateToMain();
} }
}; }.start();
countDownTimer.start();
} }
private void startMain() { private void updateProgress(long millisUntilFinished) {
int progress = calculateProgress(millisUntilFinished);
binding.progressBar.setProgress(progress);
}
private int calculateProgress(long millisUntilFinished) {
return (int) (100 - ((float) millisUntilFinished / TOTAL_TIME_MS * 100));
}
private void navigateToMain() {
binding.progressBar.setProgress(100); binding.progressBar.setProgress(100);
Intent intent = new Intent(this, MainActivity.class);
Intent intent = new Intent(StartActivity.this, MainActivity.class);
startActivity(intent); startActivity(intent);
finish(); finish();
} }
@ -67,9 +88,14 @@ public class StartActivity extends AppCompatActivity {
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
if (countDownTimer != null) { cleanupResources();
countDownTimer.cancel();
}
binding = null; binding = null;
} }
private void cleanupResources() {
if (countDownTimer != null) {
countDownTimer.cancel();
countDownTimer = null;
}
}
} }

View File

@ -1,7 +1,5 @@
package com.nature.wallpaper.naturewallpaper.activity; package com.nature.wallpaper.naturewallpaper.activity;
import static com.nature.wallpaper.naturewallpaper.util.SetAndDownloadUtils.REQUEST_CODE_WRITE_EXTERNAL_STORAGE;
import android.app.WallpaperManager; import android.app.WallpaperManager;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.graphics.Bitmap; import android.graphics.Bitmap;
@ -19,7 +17,6 @@ import androidx.activity.EdgeToEdge;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat; import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat; import androidx.core.view.WindowInsetsCompat;
@ -31,159 +28,168 @@ import com.nature.wallpaper.naturewallpaper.R;
import com.nature.wallpaper.naturewallpaper.databinding.ActivityWallpaperBinding; import com.nature.wallpaper.naturewallpaper.databinding.ActivityWallpaperBinding;
import com.nature.wallpaper.naturewallpaper.room.NatureData; import com.nature.wallpaper.naturewallpaper.room.NatureData;
import com.nature.wallpaper.naturewallpaper.util.RoomUtils; import com.nature.wallpaper.naturewallpaper.util.RoomUtils;
import com.nature.wallpaper.naturewallpaper.util.SetAndDownloadUtils; import com.nature.wallpaper.naturewallpaper.util.SetDownloadUtil;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
public class WallpaperActivity extends AppCompatActivity implements SetAndDownloadUtils.DownloadCallback { public class WallpaperActivity extends AppCompatActivity implements SetDownloadUtil.DownloadCallback {
private static final int REQUEST_CODE_WRITE_EXTERNAL_STORAGE = SetDownloadUtil.REQUEST_CODE_WRITE_EXTERNAL_STORAGE;
private ActivityWallpaperBinding binding; private ActivityWallpaperBinding binding;
private NatureData data;
private String original; private String original;
private String source; private String source;
private NatureData coolEntity;
private RoomUtils roomUtils;
private String name; private String name;
private Bitmap bitmap; private Bitmap bitmap;
private SetAndDownloadUtils setAndDownloadUtils; private SetDownloadUtil setDownloadUtil;
private RoomUtils roomUtils;
private ExecutorService executorService; private ExecutorService executorService;
private Handler handler; private Handler mainHandler;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setupUI();
if (initializeData()) {
setupEvents();
}
}
private void setupUI() {
EdgeToEdge.enable(this); EdgeToEdge.enable(this);
binding = ActivityWallpaperBinding.inflate(getLayoutInflater()); binding = ActivityWallpaperBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot()); setContentView(binding.getRoot());
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { applyWindowInsets();
int navigationBars = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom; }
v.setPadding(0, 0, 0, navigationBars);
private void applyWindowInsets() {
ViewCompat.setOnApplyWindowInsetsListener(binding.getRoot(), (v, insets) -> {
int navigationBarsHeight = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom;
v.setPadding(0, 0, 0, navigationBarsHeight);
return insets; return insets;
}); });
initData();
initEvent();
} }
private void initData() { private boolean initializeData() {
coolEntity = (NatureData) getIntent().getSerializableExtra("nature"); data = (NatureData) getIntent().getSerializableExtra("nature");
if (coolEntity != null) { if (data == null) {
original = coolEntity.getOriginal(); showToast("Error loading wallpaper data");
source = coolEntity.getSource();
name = coolEntity.getName();
} else {
Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
finish(); finish();
return false;
} }
setAndDownloadUtils = new SetAndDownloadUtils(); original = data.getOriginal();
source = data.getSource();
name = data.getName();
setDownloadUtil = new SetDownloadUtil();
roomUtils = new RoomUtils(this); roomUtils = new RoomUtils(this);
mainHandler = new Handler(Looper.getMainLooper());
handler = new Handler(Looper.getMainLooper());
executorService = Executors.newSingleThreadExecutor(); executorService = Executors.newSingleThreadExecutor();
return true;
} }
private void initEvent() { private void setupEvents() {
showProgress(); showProgress();
binding.backButton.setOnClickListener(v -> finish()); binding.backButton.setOnClickListener(v -> finish());
binding.likeButton.setOnClickListener(v -> toggleLikeStatus());
binding.likeButton.setOnClickListener(v -> { binding.setWallpaperContainer.setOnClickListener(v -> showWallpaperOptions());
boolean newStatus = !coolEntity.getLike(); binding.downloadContainer.setOnClickListener(v -> downloadWallpaper());
coolEntity.setLike(newStatus);
executorService.submit(() -> roomUtils.update(coolEntity));
});
binding.setWallpaperContainer.setOnClickListener(v -> {
showCustomBottomSheet();
});
binding.downloadContainer.setOnClickListener(v -> {
showProgress();
setAndDownloadUtils.setAsWallpaper(WallpaperActivity.this, source, WallpaperActivity.this);
});
loadImage(); loadImage();
loadFavorite(); loadFavoriteStatus();
} }
@Override private void toggleLikeStatus() {
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { boolean newStatus = !data.getLike();
super.onRequestPermissionsResult(requestCode, permissions, grantResults); data.setLike(newStatus);
if (requestCode == REQUEST_CODE_WRITE_EXTERNAL_STORAGE) { executorService.submit(() -> roomUtils.update(data));
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { updateLikeButton();
setAndDownloadUtils.setAsWallpaper(this, source, this);
} else {
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show();
}
}
} }
private void showCustomBottomSheet() { private void downloadWallpaper() {
BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(this);
View bottomSheetView = LayoutInflater.from(this).inflate(R.layout.set_wallpaper_dialog, null);
bottomSheetView.findViewById(R.id.both).setOnClickListener(v -> {
disableButtons(bottomSheetView);
applyWallpaper(bitmap, WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK, bottomSheetDialog);
bottomSheetDialog.dismiss();
});
bottomSheetView.findViewById(R.id.lock).setOnClickListener(v -> {
disableButtons(bottomSheetView);
applyWallpaper(bitmap, WallpaperManager.FLAG_LOCK, bottomSheetDialog);
bottomSheetDialog.dismiss();
});
bottomSheetView.findViewById(R.id.desktop).setOnClickListener(v -> {
disableButtons(bottomSheetView);
applyWallpaper(bitmap, WallpaperManager.FLAG_SYSTEM, bottomSheetDialog);
bottomSheetDialog.dismiss();
});
bottomSheetDialog.setContentView(bottomSheetView);
bottomSheetDialog.show();
}
private void disableButtons(View bottomSheetView) {
bottomSheetView.findViewById(R.id.both).setEnabled(false);
bottomSheetView.findViewById(R.id.lock).setEnabled(false);
bottomSheetView.findViewById(R.id.desktop).setEnabled(false);
}
private void applyWallpaper(Bitmap bitmap, int flag, BottomSheetDialog bottomSheetDialog) {
showProgress(); showProgress();
setDownloadUtil.setAsWallpaper(this, source, this);
}
executorService.submit(() -> { private void showWallpaperOptions() {
boolean success = false; BottomSheetDialog dialog = new BottomSheetDialog(this);
try { View sheetView = LayoutInflater.from(this).inflate(R.layout.set_wallpaper_dialog, null);
success = setWallpaperImage(bitmap, flag);
} catch (Exception e) { setupBottomSheetListeners(sheetView, dialog);
e.printStackTrace();
} finally { dialog.setContentView(sheetView);
boolean finalSuccess = success; dialog.show();
handler.post(() -> { }
private void setupBottomSheetListeners(View sheetView, BottomSheetDialog dialog) {
sheetView.findViewById(R.id.both).setOnClickListener(v ->
setWallpaperAndDismiss(WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK, sheetView, dialog));
sheetView.findViewById(R.id.lock).setOnClickListener(v ->
setWallpaperAndDismiss(WallpaperManager.FLAG_LOCK, sheetView, dialog));
sheetView.findViewById(R.id.desktop).setOnClickListener(v ->
setWallpaperAndDismiss(WallpaperManager.FLAG_SYSTEM, sheetView, dialog));
}
private void setWallpaperAndDismiss(int flag, View sheetView, BottomSheetDialog dialog) {
disableSheetButtons(sheetView);
applyWallpaperAsync(bitmap, flag, dialog);
dialog.dismiss();
}
private void disableSheetButtons(View sheetView) {
setButtonEnabled(sheetView, R.id.both, false);
setButtonEnabled(sheetView, R.id.lock, false);
setButtonEnabled(sheetView, R.id.desktop, false);
}
private void applyWallpaperAsync(Bitmap bitmap, int flag, BottomSheetDialog dialog) {
if (bitmap == null) {
showToast("No image available to set as wallpaper");
hideProgress(); hideProgress();
bottomSheetDialog.findViewById(R.id.both).setEnabled(true); return;
bottomSheetDialog.findViewById(R.id.lock).setEnabled(true); }
bottomSheetDialog.findViewById(R.id.desktop).setEnabled(true);
String message = finalSuccess ? "Wallpaper set successfully" : "Failed to set wallpaper"; showProgress();
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show(); executorService.submit(() -> {
boolean success = setWallpaperImage(bitmap, flag);
mainHandler.post(() -> {
hideProgress();
enableSheetButtons(dialog);
showToast(success ? "Wallpaper set successfully" : "Failed to set wallpaper");
});
}); });
} }
});
private void enableSheetButtons(BottomSheetDialog dialog) {
View sheetView = dialog.getCurrentFocus() != null ? dialog.getCurrentFocus().getRootView() : null;
if (sheetView != null) {
setButtonEnabled(sheetView, R.id.both, true);
setButtonEnabled(sheetView, R.id.lock, true);
setButtonEnabled(sheetView, R.id.desktop, true);
}
}
private void setButtonEnabled(View view, int id, boolean enabled) {
View button = view.findViewById(id);
if (button != null) {
button.setEnabled(enabled);
}
} }
private boolean setWallpaperImage(Bitmap bitmap, int flag) { private boolean setWallpaperImage(Bitmap bitmap, int flag) {
WallpaperManager wallpaperManager = WallpaperManager.getInstance(getApplicationContext()); WallpaperManager manager = WallpaperManager.getInstance(this);
try { try {
binding.wallpaperImage.setDrawingCacheEnabled(true); binding.wallpaperImage.setDrawingCacheEnabled(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
wallpaperManager.setBitmap(bitmap, null, true, flag); manager.setBitmap(bitmap, null, true, flag);
} else { } else {
wallpaperManager.setBitmap(bitmap); manager.setBitmap(bitmap);
} }
return true; return true;
} catch (IOException e) { } catch (IOException e) {
@ -194,7 +200,6 @@ public class WallpaperActivity extends AppCompatActivity implements SetAndDownlo
} }
} }
private void loadImage() { private void loadImage() {
Glide.with(this) Glide.with(this)
.asBitmap() .asBitmap()
@ -227,16 +232,39 @@ public class WallpaperActivity extends AppCompatActivity implements SetAndDownlo
return ContextCompat.getDrawable(this, R.mipmap.placeholder); return ContextCompat.getDrawable(this, R.mipmap.placeholder);
} }
private void loadFavorite() { private void loadFavoriteStatus() {
roomUtils.getWallpaperLike(source, name).observe(this, wallpaper -> setFavoriteButton()); roomUtils.getWallpaperLike(source, name).observe(this, wallpaper -> updateLikeButton());
} }
private void setFavoriteButton() { private void updateLikeButton() {
binding.likeButton.setImageResource( binding.likeButton.setImageResource(
coolEntity.getLike() ? R.drawable.like : R.drawable.un_like data.getLike() ? R.drawable.like : R.drawable.un_like
); );
} }
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE_WRITE_EXTERNAL_STORAGE && grantResults.length > 0) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
downloadWallpaper();
} else {
showToast("Permission denied");
hideProgress();
}
}
}
private void showToast(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
private void showProgress() {
binding.progressBar.setVisibility(View.VISIBLE);
binding.view.setVisibility(View.VISIBLE);
}
private void hideProgress() { private void hideProgress() {
if (binding != null) { if (binding != null) {
binding.progressBar.setVisibility(View.GONE); binding.progressBar.setVisibility(View.GONE);
@ -244,11 +272,6 @@ public class WallpaperActivity extends AppCompatActivity implements SetAndDownlo
} }
} }
private void showProgress() {
binding.progressBar.setVisibility(View.VISIBLE);
binding.view.setVisibility(View.VISIBLE);
}
@Override @Override
public void onDownloadStart() { public void onDownloadStart() {
showProgress(); showProgress();
@ -257,22 +280,31 @@ public class WallpaperActivity extends AppCompatActivity implements SetAndDownlo
@Override @Override
public void onDownloadComplete(Uri uri) { public void onDownloadComplete(Uri uri) {
hideProgress(); hideProgress();
showToast("Download completed");
} }
@Override @Override
public void onDownloadFailed() { public void onDownloadFailed() {
hideProgress(); hideProgress();
showToast("Download failed");
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
if (handler != null) { cleanupResources();
handler.removeCallbacksAndMessages(null);
} }
if (executorService != null) {
private void cleanupResources() {
if (mainHandler != null) {
mainHandler.removeCallbacksAndMessages(null);
}
if (executorService != null && !executorService.isShutdown()) {
executorService.shutdown(); executorService.shutdown();
} }
if (setDownloadUtil != null) {
setDownloadUtil.shutdown();
}
binding = null; binding = null;
} }
} }

View File

@ -29,7 +29,7 @@ public class WallpaperAdapter extends RecyclerView.Adapter<WallpaperAdapter.View
private List<NatureData> natureDataList; private List<NatureData> natureDataList;
private final Context context; private final Context context;
private final Executor executor; private final Executor executor;
private final int displayMode; // 0: 显示标题跳转NatureList, 其他: 隐藏标题跳转Wallpaper private final int displayMode;
private static final int MODE_WITH_TITLE = 0; private static final int MODE_WITH_TITLE = 0;
public WallpaperAdapter(Context context, List<NatureData> natureDataList, int displayMode) { public WallpaperAdapter(Context context, List<NatureData> natureDataList, int displayMode) {

View File

@ -43,18 +43,17 @@ public class FavoriteFragment extends Fragment {
adapter = new WallpaperAdapter(requireContext(), new ArrayList<>(),1); adapter = new WallpaperAdapter(requireContext(), new ArrayList<>(),1);
binding.recyclerView.setAdapter(adapter); binding.recyclerView.setAdapter(adapter);
ItemDecoration itemDecoration = new ItemDecoration(25, 15, 10); binding.recyclerView.addItemDecoration(new ItemDecoration(25, 15, 10));
binding.recyclerView.addItemDecoration(itemDecoration);
} }
private void initEvent() { private void initEvent() {
loadCategoryImage(); loadAllFavoriteList();
} }
private void loadCategoryImage() { private void loadAllFavoriteList() {
roomUtils roomUtils
.getAllFavoriteList() .getAllFavorite()
.observe(getViewLifecycleOwner(), new Observer<List<NatureData>>() { .observe(getViewLifecycleOwner(), new Observer<List<NatureData>>() {
@Override @Override
public void onChanged(List<NatureData> natureDataList) { public void onChanged(List<NatureData> natureDataList) {

View File

@ -10,9 +10,7 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.nature.wallpaper.naturewallpaper.R;
import com.nature.wallpaper.naturewallpaper.adapter.WallpaperAdapter; import com.nature.wallpaper.naturewallpaper.adapter.WallpaperAdapter;
import com.nature.wallpaper.naturewallpaper.databinding.FragmentFavoriteBinding;
import com.nature.wallpaper.naturewallpaper.databinding.FragmentNatureBinding; import com.nature.wallpaper.naturewallpaper.databinding.FragmentNatureBinding;
import com.nature.wallpaper.naturewallpaper.room.NatureData; import com.nature.wallpaper.naturewallpaper.room.NatureData;
import com.nature.wallpaper.naturewallpaper.util.ItemDecoration; import com.nature.wallpaper.naturewallpaper.util.ItemDecoration;
@ -45,18 +43,16 @@ public class NatureFragment extends Fragment {
adapter = new WallpaperAdapter(requireContext(), new ArrayList<>(), 0); adapter = new WallpaperAdapter(requireContext(), new ArrayList<>(), 0);
binding.recyclerView.setAdapter(adapter); binding.recyclerView.setAdapter(adapter);
ItemDecoration itemDecoration = new ItemDecoration(25, 15, 10); binding.recyclerView.addItemDecoration(new ItemDecoration(25, 15, 10));
binding.recyclerView.addItemDecoration(itemDecoration);
} }
private void initEvent() { private void initEvent() {
loadCategoryImage(); loadCategoryFirst();
} }
private void loadCategoryImage() { private void loadCategoryFirst() {
roomUtils roomUtils
.getCategoryFirst() .getFirstCategory()
.observe(getViewLifecycleOwner(), new Observer<List<NatureData>>() { .observe(getViewLifecycleOwner(), new Observer<List<NatureData>>() {
@Override @Override
public void onChanged(List<NatureData> natureDataList) { public void onChanged(List<NatureData> natureDataList) {

View File

@ -19,12 +19,12 @@ public interface NatureDataDao {
@Query("SELECT * FROM NatureData WHERE isLike = 1 ") @Query("SELECT * FROM NatureData WHERE isLike = 1 ")
LiveData<List<NatureData>> getAllFavoriteLive(); LiveData<List<NatureData>> getAllFavoriteLive();
@Query("SELECT * FROM NatureData WHERE id IN (SELECT MIN(id) FROM NatureData GROUP BY name)") @Query("SELECT * FROM NatureData WHERE id IN (SELECT MAX(id) FROM NatureData GROUP BY name) ORDER BY id DESC")
LiveData<List<NatureData>> getFirstRecordOfEachName(); LiveData<List<NatureData>> getFirstCategoryByFirst();
@Query("SELECT * FROM NatureData WHERE name = :name") @Query("SELECT * FROM NatureData WHERE name = :name ORDER BY id DESC")
LiveData<List<NatureData>> getAllCategoryLive(String name); LiveData<List<NatureData>> getAllCategoryByName(String name);
@Query("SELECT isLIKE FROM NatureData WHERE source = :source AND name = :name") @Query("SELECT isLIKE FROM NatureData WHERE source = :source AND name = :name ORDER BY id DESC")
LiveData<Boolean> getWallpaperLike(String source, String name); LiveData<Boolean> getWallpaperLikeBySourceAndName(String source, String name);
} }

View File

@ -1,7 +1,5 @@
package com.nature.wallpaper.naturewallpaper.util; package com.nature.wallpaper.naturewallpaper.util;
import android.util.Log;
import com.nature.wallpaper.naturewallpaper.MyApplication; import com.nature.wallpaper.naturewallpaper.MyApplication;
import com.nature.wallpaper.naturewallpaper.room.NatureData; import com.nature.wallpaper.naturewallpaper.room.NatureData;
import com.nature.wallpaper.naturewallpaper.room.NatureList; import com.nature.wallpaper.naturewallpaper.room.NatureList;
@ -13,58 +11,70 @@ import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
public class JsonParse { public class JsonParse {
private static String loadJsonFromAsset(String fileName) throws IOException {
private static String loadJSONFromAsset(String fileName) {
StringBuilder jsonString = new StringBuilder(); StringBuilder jsonString = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(MyApplication.getContext().getAssets().open(fileName)))) { try (BufferedReader reader = new BufferedReader(
new InputStreamReader(MyApplication.getContext().getAssets().open(fileName)))) {
String line; String line;
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
jsonString.append(line); jsonString.append(line);
} }
} catch (IOException e) {
e.printStackTrace();
} }
Log.d("JsonParse", "Loaded JSON: " + jsonString.toString());
return jsonString.toString(); return jsonString.toString();
} }
public static List<NatureList> parseJson(String fileName) { public static List<NatureList> parseJson(String fileName) {
List<NatureList> categoryList = new ArrayList<>();
try { try {
String jsonString = loadJSONFromAsset(fileName); String jsonString = loadJsonFromAsset(fileName);
if (jsonString.isEmpty()) { if (jsonString.isEmpty()) {
throw new IllegalArgumentException("JSON file is empty or invalid."); return Collections.emptyList();
}
return parseJsonArray(new JSONArray(jsonString));
} catch (Exception e) {
return Collections.emptyList();
}
} }
JSONArray jsonArray = new JSONArray(jsonString); private static List<NatureList> parseJsonArray(JSONArray jsonArray) throws org.json.JSONException {
List<NatureList> categoryList = new ArrayList<>();
for (int i = 0; i < jsonArray.length(); i++) { for (int i = 0; i < jsonArray.length(); i++) {
JSONObject categoryObject = jsonArray.getJSONObject(i); JSONObject categoryObject = jsonArray.getJSONObject(i);
String name = categoryObject.getString("name"); String categoryName = categoryObject.getString("name");
JSONArray dataArray = categoryObject.getJSONArray("data");
JSONArray listArray = categoryObject.getJSONArray("data"); List<NatureData> natureDataList = parseNatureDataList(dataArray, categoryName);
List<NatureData> natureDataList = new ArrayList<>(); categoryList.add(new NatureList(categoryName, natureDataList));
for (int j = 0; j < listArray.length(); j++) {
JSONObject imageObject = listArray.getJSONObject(j);
String original = imageObject.getString("original");
String previewThumb = imageObject.getString("previewThumb");
String source = imageObject.getString("source");
natureDataList.add(new NatureData(original, previewThumb, source, name, false));
}
categoryList.add(new NatureList(name, natureDataList));
}
} catch (Exception e) {
e.printStackTrace();
} }
return categoryList; return categoryList;
} }
private static List<NatureData> parseNatureDataList(JSONArray dataArray, String categoryName)
throws org.json.JSONException {
List<NatureData> natureDataList = new ArrayList<>();
for (int j = 0; j < dataArray.length(); j++) {
JSONObject imageObject = dataArray.getJSONObject(j);
String original = getStringSafe(imageObject, "original");
String previewThumb = getStringSafe(imageObject, "previewThumb");
String source = getStringSafe(imageObject, "source");
natureDataList.add(new NatureData(original, previewThumb, source, categoryName, false));
}
return natureDataList;
}
private static String getStringSafe(JSONObject jsonObject, String key) {
try {
return jsonObject.getString(key);
} catch (org.json.JSONException e) {
return "";
}
}
} }

View File

@ -22,29 +22,29 @@ public class RoomUtils {
} }
public void insertAllImages(List<NatureList> categoryList) { public void insertAllImages(List<NatureList> categoryList) {
List<NatureData> coolEntities = new ArrayList<>(); List<NatureData> dataList = new ArrayList<>();
for (NatureList category : categoryList) { for (NatureList category : categoryList) {
coolEntities.addAll(category.getList()); dataList.addAll(category.getList());
} }
natureDataDao.insertAll(coolEntities); natureDataDao.insertAll(dataList);
} }
public LiveData<List<NatureData>> getAllFavoriteList() { public LiveData<List<NatureData>> getAllFavorite() {
return natureDataDao.getAllFavoriteLive(); return natureDataDao.getAllFavoriteLive();
} }
public LiveData<List<NatureData>> getCategoryFirst() { public LiveData<List<NatureData>> getFirstCategory() {
return natureDataDao.getFirstRecordOfEachName(); return natureDataDao.getFirstCategoryByFirst();
} }
public LiveData<List<NatureData>> getAllCategory(String name) { public LiveData<List<NatureData>> getAllCategory(String name) {
return natureDataDao.getAllCategoryLive(name); return natureDataDao.getAllCategoryByName(name);
} }
public LiveData<Boolean> getWallpaperLike(String source, String name) { public LiveData<Boolean> getWallpaperLike(String source, String name) {
return natureDataDao.getWallpaperLike(source, name); return natureDataDao.getWallpaperLikeBySourceAndName(source, name);
} }
public void update(NatureData imageEntry) { public void update(NatureData imageEntry) {

View File

@ -1,114 +0,0 @@
package com.nature.wallpaper.naturewallpaper.util;
import android.app.Activity;
import android.content.ContentValues;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class SetAndDownloadUtils {
public static final int REQUEST_CODE_WRITE_EXTERNAL_STORAGE = 111;
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
public void setAsWallpaper(Activity activity, String imageUrl,DownloadCallback callback) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
startDownload(activity, imageUrl,callback);
} else {
if (ContextCompat.checkSelfPermission(activity, android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity,
new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_CODE_WRITE_EXTERNAL_STORAGE);
} else {
startDownload(activity, imageUrl,callback);
}
}
}
private void startDownload(Activity activity, String imageUrl, DownloadCallback callback) {
callback.onDownloadStart();
executorService.submit(() -> {
Uri uri = downloadImage(activity, imageUrl);
activity.runOnUiThread(() -> {
if (uri != null) {
callback.onDownloadComplete(uri);
} else {
callback.onDownloadFailed();
}
});
});
}
private Uri downloadImage(Activity activity, String imageUrl) {
String displayName = UUID.randomUUID().toString() + ".jpg";
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, displayName);
contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
contentValues.put(MediaStore.Images.Media.IS_PENDING, 1);
}
Uri collectionUri;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
collectionUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
} else {
collectionUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
}
Uri imageUri = activity.getContentResolver().insert(collectionUri, contentValues);
if (imageUri != null) {
try {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(imageUrl).build();
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
InputStream inputStream = response.body().byteStream();
try (OutputStream outputStream = activity.getContentResolver().openOutputStream(imageUri)) {
if (outputStream != null) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
contentValues.clear();
contentValues.put(MediaStore.Images.Media.IS_PENDING, 0);
activity.getContentResolver().update(imageUri, contentValues, null, null);
}
return imageUri;
} catch (IOException e) {
activity.getContentResolver().delete(imageUri, null, null);
}
}
return null;
}
public interface DownloadCallback {
void onDownloadStart();
void onDownloadComplete(Uri uri);
void onDownloadFailed();
}
}

View File

@ -0,0 +1,174 @@
package com.nature.wallpaper.naturewallpaper.util;
import android.Manifest;
import android.app.Activity;
import android.content.ContentValues;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class SetDownloadUtil {
public static final int REQUEST_CODE_WRITE_EXTERNAL_STORAGE = 111;
private static final int BUFFER_SIZE = 4096;
private final ExecutorService executorService;
private final OkHttpClient httpClient;
public SetDownloadUtil() {
this.executorService = Executors.newSingleThreadExecutor();
this.httpClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
}
public void setAsWallpaper(Activity activity, String imageUrl, DownloadCallback callback) {
if (activity == null || imageUrl == null || callback == null) {
if (callback != null) callback.onDownloadFailed();
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
downloadWallpaperAsync(activity, imageUrl, callback);
} else if (hasWritePermission(activity)) {
downloadWallpaperAsync(activity, imageUrl, callback);
} else {
requestWritePermission(activity);
}
}
private boolean hasWritePermission(Activity activity) {
return ContextCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED;
}
private void requestWritePermission(Activity activity) {
ActivityCompat.requestPermissions(activity,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_CODE_WRITE_EXTERNAL_STORAGE);
}
private void downloadWallpaperAsync(Activity activity, String imageUrl, DownloadCallback callback) {
callback.onDownloadStart();
executorService.submit(() -> {
try {
Uri imageUri = downloadImage(activity, imageUrl);
notifyResultOnMainThread(activity, callback, imageUri);
} catch (Exception e) {
notifyFailureOnMainThread(activity, callback);
}
});
}
private Uri downloadImage(Activity activity, String imageUrl) throws IOException {
String fileName = generateUniqueFileName();
Uri imageUri = createMediaStoreEntry(activity, fileName);
if (imageUri == null) return null;
try {
downloadToMediaStore(activity, imageUrl, imageUri);
markAsComplete(activity, imageUri);
return imageUri;
} catch (IOException e) {
cleanupFailedDownload(activity, imageUri);
throw e;
}
}
private String generateUniqueFileName() {
return UUID.randomUUID().toString() + ".jpg";
}
private Uri createMediaStoreEntry(Activity activity, String fileName) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
values.put(MediaStore.Images.Media.IS_PENDING, 1);
}
Uri collectionUri = getMediaStoreCollectionUri();
return activity.getContentResolver().insert(collectionUri, values);
}
private Uri getMediaStoreCollectionUri() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
return MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
}
return MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
}
private void downloadToMediaStore(Activity activity, String imageUrl, Uri imageUri) throws IOException {
Request request = new Request.Builder().url(imageUrl).build();
try (Response response = httpClient.newCall(request).execute();
InputStream inputStream = response.body().byteStream();
OutputStream outputStream = activity.getContentResolver().openOutputStream(imageUri)) {
if (!response.isSuccessful() || outputStream == null) {
throw new IOException("Download failed: " + response.code());
}
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
}
private void markAsComplete(Activity activity, Uri imageUri) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.IS_PENDING, 0);
activity.getContentResolver().update(imageUri, values, null, null);
}
}
private void cleanupFailedDownload(Activity activity, Uri imageUri) {
activity.getContentResolver().delete(imageUri, null, null);
}
private void notifyResultOnMainThread(Activity activity, DownloadCallback callback, Uri imageUri) {
activity.runOnUiThread(() -> {
if (imageUri != null) {
callback.onDownloadComplete(imageUri);
} else {
callback.onDownloadFailed();
}
});
}
private void notifyFailureOnMainThread(Activity activity, DownloadCallback callback) {
activity.runOnUiThread(callback::onDownloadFailed);
}
public void shutdown() {
if (!executorService.isShutdown()) {
executorService.shutdown();
}
}
public interface DownloadCallback {
void onDownloadStart();
void onDownloadComplete(Uri uri);
void onDownloadFailed();
}
}

View File

@ -27,7 +27,7 @@
android:textSize="25sp" android:textSize="25sp"
android:textStyle="bold" android:textStyle="bold"
android:gravity="center" android:gravity="center"
android:textColor="@color/white" android:textColor="@color/black"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/image" /> app:layout_constraintTop_toBottomOf="@+id/image" />

View File

@ -13,18 +13,15 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="4dp"> android:padding="4dp">
<!-- 图片 -->
<ImageView <ImageView
android:id="@+id/image_view" android:id="@+id/image_view"
android:layout_width="0dp" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="250dp"
android:adjustViewBounds="true" android:adjustViewBounds="true"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" /> app:layout_constraintEnd_toEndOf="parent" />
<!-- 标题 -->
<TextView <TextView
android:id="@+id/title_text" android:id="@+id/title_text"
android:layout_width="0dp" android:layout_width="0dp"
@ -40,13 +37,12 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" /> app:layout_constraintEnd_toEndOf="parent" />
<!-- 收藏按钮 -->
<ImageView <ImageView
android:id="@+id/favorite" android:id="@+id/favorite"
android:layout_width="24dp" android:layout_width="24dp"
android:layout_height="24dp" android:layout_height="24dp"
android:src="@drawable/un_like" android:src="@drawable/un_like"
android:layout_margin="4dp" android:layout_margin="8dp"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" /> app:layout_constraintEnd_toEndOf="parent" />

View File

@ -4,6 +4,7 @@
android:layout_width="250dp" android:layout_width="250dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:id="@+id/set_wallpaper_dialog"
android:background="@drawable/rounded_control_bar_background"> android:background="@drawable/rounded_control_bar_background">
<TextView <TextView

View File

@ -2,4 +2,6 @@
<string name="app_name">Nature Wallpaper</string> <string name="app_name">Nature Wallpaper</string>
<!-- TODO: Remove or change this placeholder text --> <!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string> <string name="hello_blank_fragment">Hello blank fragment</string>
<string name="home">Home</string>
<string name="favorite">Favorite</string>
</resources> </resources>

6
keystore.properties Normal file
View File

@ -0,0 +1,6 @@
app_name=Nature Wallpaper
package_name=com.nature.wallpaper.naturewallpaper
keystoreFile=app/NatureWallpaper.jks
key_alias=NatureWallpaperkey0
key_store_password=NatureWallpaper
key_password=NatureWallpaper