V1.0.0(1)完成版
This commit is contained in:
parent
2b76217e86
commit
55b2e6d5fc
BIN
app/NatureWallpaper.jks
Normal file
BIN
app/NatureWallpaper.jks
Normal file
Binary file not shown.
14
app/proguard-rules.pro
vendored
14
app/proguard-rules.pro
vendored
@ -19,3 +19,17 @@
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-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 { *; }
|
||||
@ -9,45 +9,71 @@ import com.nature.wallpaper.naturewallpaper.util.JsonParse;
|
||||
import com.nature.wallpaper.naturewallpaper.util.RoomUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class MyApplication extends Application {
|
||||
|
||||
public static MyApplication application;
|
||||
public static final int DB_VERSION = 1;
|
||||
public static final String DB_NAME = "cool_database";
|
||||
private static volatile MyApplication instance;
|
||||
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
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
application = this;
|
||||
|
||||
SharedPreferences sharedPreferences = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
|
||||
boolean isDatabaseInitialized = sharedPreferences.getBoolean(KEY_INIT, false);
|
||||
|
||||
if (!isDatabaseInitialized) {
|
||||
initializeDatabase();
|
||||
sharedPreferences.edit().putBoolean(KEY_INIT, true).apply();
|
||||
initializeInstance();
|
||||
initializeDatabaseIfNeeded();
|
||||
}
|
||||
|
||||
private void initializeInstance() {
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public static Context getContext() {
|
||||
return application.getApplicationContext();
|
||||
if (instance == null) {
|
||||
throw new IllegalStateException("Application not initialized yet");
|
||||
}
|
||||
return instance.getApplicationContext();
|
||||
}
|
||||
|
||||
private void initializeDatabase() {
|
||||
Executors.newSingleThreadExecutor().execute(() -> {
|
||||
List<NatureList> natureListList = getCategoryList();
|
||||
private void initializeDatabaseIfNeeded() {
|
||||
SharedPreferences prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
|
||||
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.insertAllImages(natureListList);
|
||||
roomUtils.insertAllImages(natureLists);
|
||||
});
|
||||
}
|
||||
|
||||
public static List<NatureList> getCategoryList() {
|
||||
return JsonParse.parseJson("nature_wallpapers.json");
|
||||
private void markDatabaseAsInitialized(SharedPreferences prefs) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
@ -20,88 +20,84 @@ import com.nature.wallpaper.naturewallpaper.databinding.TabLayoutBinding;
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
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
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setupEdgeToEdge();
|
||||
initializeBinding();
|
||||
setupWindowInsets();
|
||||
setupViewPager();
|
||||
setupTabLayout();
|
||||
}
|
||||
|
||||
private void setupEdgeToEdge() {
|
||||
EdgeToEdge.enable(this);
|
||||
}
|
||||
|
||||
private void initializeBinding() {
|
||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
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());
|
||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
|
||||
return insets;
|
||||
});
|
||||
|
||||
initData();
|
||||
initEvent();
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
private void setupViewPager() {
|
||||
MainAdapter adapter = new MainAdapter(this);
|
||||
binding.mainViewpager2.setAdapter(adapter);
|
||||
}
|
||||
|
||||
private void initEvent() {
|
||||
new TabLayoutMediator(binding.mainTabLayout, binding.mainViewpager2, (tab, position) -> {
|
||||
TabLayoutBinding tabLayoutBinding = TabLayoutBinding.inflate(LayoutInflater.from(this));
|
||||
tab.setCustomView(tabLayoutBinding.getRoot());
|
||||
setTab(tabLayoutBinding, position);
|
||||
}).attach();
|
||||
private void setupTabLayout() {
|
||||
new TabLayoutMediator(binding.mainTabLayout, binding.mainViewpager2,
|
||||
this::configureTab).attach();
|
||||
|
||||
binding.mainTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
||||
@Override
|
||||
public void onTabSelected(TabLayout.Tab tab) {
|
||||
updateTab(tab, true);
|
||||
updateTabState(tab, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabUnselected(TabLayout.Tab tab) {
|
||||
updateTab(tab, false);
|
||||
updateTabState(tab, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
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));
|
||||
}
|
||||
}
|
||||
public void onTabReselected(TabLayout.Tab tab) {}
|
||||
});
|
||||
}
|
||||
|
||||
private void setTab(TabLayoutBinding tabLayoutBinding, int position) {
|
||||
int iconResId = getIconResource(position, false);
|
||||
int textColorResId = R.color.gray;
|
||||
private void configureTab(TabLayout.Tab tab, int position) {
|
||||
TabLayoutBinding tabBinding = TabLayoutBinding.inflate(LayoutInflater.from(this));
|
||||
tab.setCustomView(tabBinding.getRoot());
|
||||
|
||||
switch (position) {
|
||||
case 0:
|
||||
tabLayoutBinding.text.setText("Home");
|
||||
iconResId = R.drawable.home;
|
||||
textColorResId = R.color.black;
|
||||
break;
|
||||
case 1:
|
||||
tabLayoutBinding.text.setText("Favorite");
|
||||
break;
|
||||
boolean isFirstTab = position == 0;
|
||||
tabBinding.text.setText(TAB_TITLES[position]);
|
||||
tabBinding.image.setImageResource(isFirstTab ? TAB_ICONS_SELECTED[position] : TAB_ICONS_UNSELECTED[position]);
|
||||
tabBinding.text.setTextColor(ContextCompat.getColor(this,
|
||||
isFirstTab ? R.color.black : R.color.gray));
|
||||
}
|
||||
|
||||
tabLayoutBinding.image.setImageResource(iconResId);
|
||||
tabLayoutBinding.text.setTextColor(ContextCompat.getColor(this, textColorResId));
|
||||
}
|
||||
private void updateTabState(TabLayout.Tab tab, boolean isSelected) {
|
||||
if (tab.getCustomView() == null) return;
|
||||
|
||||
private int getIconResource(int position, boolean isSelected) {
|
||||
if (position == 1) {
|
||||
return isSelected ? R.drawable.favoriteslist : R.drawable.un_favoriteslist;
|
||||
}
|
||||
return isSelected ? R.drawable.home : R.drawable.un_home;
|
||||
TabLayoutBinding tabBinding = TabLayoutBinding.bind(tab.getCustomView());
|
||||
int position = tab.getPosition();
|
||||
|
||||
tabBinding.image.setImageResource(isSelected
|
||||
? TAB_ICONS_SELECTED[position]
|
||||
: TAB_ICONS_UNSELECTED[position]);
|
||||
tabBinding.text.setTextColor(ContextCompat.getColor(this,
|
||||
isSelected ? R.color.black : R.color.gray));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -25,7 +25,6 @@ public class NatureListActivity extends AppCompatActivity {
|
||||
private ActivityNatureListBinding binding;
|
||||
private WallpaperAdapter wallpaperAdapter;
|
||||
private RoomUtils roomUtils;
|
||||
private NatureData coolEntity;
|
||||
private String name;
|
||||
|
||||
@Override
|
||||
@ -47,9 +46,9 @@ public class NatureListActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
coolEntity = (NatureData) getIntent().getSerializableExtra("nature");
|
||||
if (coolEntity != null) {
|
||||
name = coolEntity.getName();
|
||||
NatureData data = (NatureData) getIntent().getSerializableExtra("nature");
|
||||
if (data != null) {
|
||||
name = data.getName();
|
||||
} else {
|
||||
Toast.makeText(this, "The picture does not exist", Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
@ -62,8 +61,7 @@ public class NatureListActivity extends AppCompatActivity {
|
||||
wallpaperAdapter = new WallpaperAdapter(this, new ArrayList<>(),1);
|
||||
binding.recyclerView.setAdapter(wallpaperAdapter);
|
||||
|
||||
ItemDecoration itemDecoration = new ItemDecoration(25, 15, 10);
|
||||
binding.recyclerView.addItemDecoration(itemDecoration);
|
||||
binding.recyclerView.addItemDecoration(new ItemDecoration(25, 15, 10));
|
||||
|
||||
}
|
||||
|
||||
@ -72,10 +70,10 @@ public class NatureListActivity extends AppCompatActivity {
|
||||
binding.back.setOnClickListener(v -> finish());
|
||||
binding.text.setText(name);
|
||||
|
||||
loadImage();
|
||||
loadAllCategory();
|
||||
}
|
||||
|
||||
private void loadImage() {
|
||||
private void loadAllCategory() {
|
||||
roomUtils
|
||||
.getAllCategory(name)
|
||||
.observe(this, new Observer<List<NatureData>>() {
|
||||
|
||||
@ -2,7 +2,6 @@ package com.nature.wallpaper.naturewallpaper.activity;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.CountDownTimer;
|
||||
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
@ -18,48 +17,70 @@ import com.nature.wallpaper.naturewallpaper.databinding.ActivityStartBinding;
|
||||
|
||||
public class StartActivity extends AppCompatActivity {
|
||||
private ActivityStartBinding binding;
|
||||
private static final long TOTAL_TIME = 1000;
|
||||
private CountDownTimer countDownTimer;
|
||||
private static final long TOTAL_TIME_MS = 1000;
|
||||
private static final long COUNTDOWN_INTERVAL_MS = 100;
|
||||
private android.os.CountDownTimer countDownTimer;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle 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());
|
||||
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());
|
||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
|
||||
return insets;
|
||||
});
|
||||
}
|
||||
|
||||
private void loadSplashImage() {
|
||||
Glide.with(this)
|
||||
.load(R.mipmap.placeholder)
|
||||
.transform(new CenterCrop(), new RoundedCorners(32))
|
||||
.into(binding.image);
|
||||
}
|
||||
|
||||
countDownTimer = new CountDownTimer(TOTAL_TIME, 100) {
|
||||
private void startCountdown() {
|
||||
countDownTimer = new android.os.CountDownTimer(TOTAL_TIME_MS, COUNTDOWN_INTERVAL_MS) {
|
||||
@Override
|
||||
public void onTick(long millisUntilFinished) {
|
||||
int percentage = (int) (100 - (float) millisUntilFinished / TOTAL_TIME * 100);
|
||||
binding.progressBar.setProgress(percentage);
|
||||
updateProgress(millisUntilFinished);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
startMain();
|
||||
navigateToMain();
|
||||
}
|
||||
};
|
||||
|
||||
countDownTimer.start();
|
||||
}.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);
|
||||
|
||||
Intent intent = new Intent(StartActivity.this, MainActivity.class);
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
@ -67,9 +88,14 @@ public class StartActivity extends AppCompatActivity {
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (countDownTimer != null) {
|
||||
countDownTimer.cancel();
|
||||
}
|
||||
cleanupResources();
|
||||
binding = null;
|
||||
}
|
||||
|
||||
private void cleanupResources() {
|
||||
if (countDownTimer != null) {
|
||||
countDownTimer.cancel();
|
||||
countDownTimer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,5 @@
|
||||
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.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
@ -19,7 +17,6 @@ import androidx.activity.EdgeToEdge;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
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.room.NatureData;
|
||||
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.util.concurrent.ExecutorService;
|
||||
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 NatureData data;
|
||||
private String original;
|
||||
private String source;
|
||||
private NatureData coolEntity;
|
||||
private RoomUtils roomUtils;
|
||||
private String name;
|
||||
private Bitmap bitmap;
|
||||
private SetAndDownloadUtils setAndDownloadUtils;
|
||||
private SetDownloadUtil setDownloadUtil;
|
||||
private RoomUtils roomUtils;
|
||||
private ExecutorService executorService;
|
||||
private Handler handler;
|
||||
private Handler mainHandler;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setupUI();
|
||||
if (initializeData()) {
|
||||
setupEvents();
|
||||
}
|
||||
}
|
||||
|
||||
private void setupUI() {
|
||||
EdgeToEdge.enable(this);
|
||||
binding = ActivityWallpaperBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
|
||||
int navigationBars = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom;
|
||||
v.setPadding(0, 0, 0, navigationBars);
|
||||
applyWindowInsets();
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
|
||||
initData();
|
||||
initEvent();
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
coolEntity = (NatureData) getIntent().getSerializableExtra("nature");
|
||||
if (coolEntity != null) {
|
||||
original = coolEntity.getOriginal();
|
||||
source = coolEntity.getSource();
|
||||
name = coolEntity.getName();
|
||||
} else {
|
||||
Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
|
||||
private boolean initializeData() {
|
||||
data = (NatureData) getIntent().getSerializableExtra("nature");
|
||||
if (data == null) {
|
||||
showToast("Error loading wallpaper data");
|
||||
finish();
|
||||
return false;
|
||||
}
|
||||
|
||||
setAndDownloadUtils = new SetAndDownloadUtils();
|
||||
original = data.getOriginal();
|
||||
source = data.getSource();
|
||||
name = data.getName();
|
||||
|
||||
setDownloadUtil = new SetDownloadUtil();
|
||||
roomUtils = new RoomUtils(this);
|
||||
|
||||
handler = new Handler(Looper.getMainLooper());
|
||||
mainHandler = new Handler(Looper.getMainLooper());
|
||||
executorService = Executors.newSingleThreadExecutor();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void initEvent() {
|
||||
private void setupEvents() {
|
||||
showProgress();
|
||||
|
||||
binding.backButton.setOnClickListener(v -> finish());
|
||||
|
||||
binding.likeButton.setOnClickListener(v -> {
|
||||
boolean newStatus = !coolEntity.getLike();
|
||||
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);
|
||||
});
|
||||
binding.likeButton.setOnClickListener(v -> toggleLikeStatus());
|
||||
binding.setWallpaperContainer.setOnClickListener(v -> showWallpaperOptions());
|
||||
binding.downloadContainer.setOnClickListener(v -> downloadWallpaper());
|
||||
|
||||
loadImage();
|
||||
loadFavorite();
|
||||
loadFavoriteStatus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (requestCode == REQUEST_CODE_WRITE_EXTERNAL_STORAGE) {
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
setAndDownloadUtils.setAsWallpaper(this, source, this);
|
||||
} else {
|
||||
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
private void toggleLikeStatus() {
|
||||
boolean newStatus = !data.getLike();
|
||||
data.setLike(newStatus);
|
||||
executorService.submit(() -> roomUtils.update(data));
|
||||
updateLikeButton();
|
||||
}
|
||||
|
||||
private void showCustomBottomSheet() {
|
||||
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) {
|
||||
private void downloadWallpaper() {
|
||||
showProgress();
|
||||
setDownloadUtil.setAsWallpaper(this, source, this);
|
||||
}
|
||||
|
||||
executorService.submit(() -> {
|
||||
boolean success = false;
|
||||
try {
|
||||
success = setWallpaperImage(bitmap, flag);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
boolean finalSuccess = success;
|
||||
handler.post(() -> {
|
||||
private void showWallpaperOptions() {
|
||||
BottomSheetDialog dialog = new BottomSheetDialog(this);
|
||||
View sheetView = LayoutInflater.from(this).inflate(R.layout.set_wallpaper_dialog, null);
|
||||
|
||||
setupBottomSheetListeners(sheetView, dialog);
|
||||
|
||||
dialog.setContentView(sheetView);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
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();
|
||||
bottomSheetDialog.findViewById(R.id.both).setEnabled(true);
|
||||
bottomSheetDialog.findViewById(R.id.lock).setEnabled(true);
|
||||
bottomSheetDialog.findViewById(R.id.desktop).setEnabled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
String message = finalSuccess ? "Wallpaper set successfully" : "Failed to set wallpaper";
|
||||
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
|
||||
showProgress();
|
||||
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) {
|
||||
WallpaperManager wallpaperManager = WallpaperManager.getInstance(getApplicationContext());
|
||||
WallpaperManager manager = WallpaperManager.getInstance(this);
|
||||
try {
|
||||
binding.wallpaperImage.setDrawingCacheEnabled(true);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
wallpaperManager.setBitmap(bitmap, null, true, flag);
|
||||
manager.setBitmap(bitmap, null, true, flag);
|
||||
} else {
|
||||
wallpaperManager.setBitmap(bitmap);
|
||||
manager.setBitmap(bitmap);
|
||||
}
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
@ -194,7 +200,6 @@ public class WallpaperActivity extends AppCompatActivity implements SetAndDownlo
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void loadImage() {
|
||||
Glide.with(this)
|
||||
.asBitmap()
|
||||
@ -227,16 +232,39 @@ public class WallpaperActivity extends AppCompatActivity implements SetAndDownlo
|
||||
return ContextCompat.getDrawable(this, R.mipmap.placeholder);
|
||||
}
|
||||
|
||||
private void loadFavorite() {
|
||||
roomUtils.getWallpaperLike(source, name).observe(this, wallpaper -> setFavoriteButton());
|
||||
private void loadFavoriteStatus() {
|
||||
roomUtils.getWallpaperLike(source, name).observe(this, wallpaper -> updateLikeButton());
|
||||
}
|
||||
|
||||
private void setFavoriteButton() {
|
||||
private void updateLikeButton() {
|
||||
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() {
|
||||
if (binding != null) {
|
||||
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
|
||||
public void onDownloadStart() {
|
||||
showProgress();
|
||||
@ -257,22 +280,31 @@ public class WallpaperActivity extends AppCompatActivity implements SetAndDownlo
|
||||
@Override
|
||||
public void onDownloadComplete(Uri uri) {
|
||||
hideProgress();
|
||||
showToast("Download completed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDownloadFailed() {
|
||||
hideProgress();
|
||||
showToast("Download failed");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (handler != null) {
|
||||
handler.removeCallbacksAndMessages(null);
|
||||
cleanupResources();
|
||||
}
|
||||
if (executorService != null) {
|
||||
|
||||
private void cleanupResources() {
|
||||
if (mainHandler != null) {
|
||||
mainHandler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
if (executorService != null && !executorService.isShutdown()) {
|
||||
executorService.shutdown();
|
||||
}
|
||||
if (setDownloadUtil != null) {
|
||||
setDownloadUtil.shutdown();
|
||||
}
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@ -29,7 +29,7 @@ public class WallpaperAdapter extends RecyclerView.Adapter<WallpaperAdapter.View
|
||||
private List<NatureData> natureDataList;
|
||||
private final Context context;
|
||||
private final Executor executor;
|
||||
private final int displayMode; // 0: 显示标题跳转NatureList, 其他: 隐藏标题跳转Wallpaper
|
||||
private final int displayMode;
|
||||
private static final int MODE_WITH_TITLE = 0;
|
||||
|
||||
public WallpaperAdapter(Context context, List<NatureData> natureDataList, int displayMode) {
|
||||
|
||||
@ -43,18 +43,17 @@ public class FavoriteFragment extends Fragment {
|
||||
adapter = new WallpaperAdapter(requireContext(), new ArrayList<>(),1);
|
||||
binding.recyclerView.setAdapter(adapter);
|
||||
|
||||
ItemDecoration itemDecoration = new ItemDecoration(25, 15, 10);
|
||||
binding.recyclerView.addItemDecoration(itemDecoration);
|
||||
binding.recyclerView.addItemDecoration(new ItemDecoration(25, 15, 10));
|
||||
|
||||
}
|
||||
|
||||
private void initEvent() {
|
||||
loadCategoryImage();
|
||||
loadAllFavoriteList();
|
||||
}
|
||||
|
||||
private void loadCategoryImage() {
|
||||
private void loadAllFavoriteList() {
|
||||
roomUtils
|
||||
.getAllFavoriteList()
|
||||
.getAllFavorite()
|
||||
.observe(getViewLifecycleOwner(), new Observer<List<NatureData>>() {
|
||||
@Override
|
||||
public void onChanged(List<NatureData> natureDataList) {
|
||||
|
||||
@ -10,9 +10,7 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.nature.wallpaper.naturewallpaper.R;
|
||||
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.room.NatureData;
|
||||
import com.nature.wallpaper.naturewallpaper.util.ItemDecoration;
|
||||
@ -42,21 +40,19 @@ public class NatureFragment extends Fragment {
|
||||
|
||||
binding.recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 1));
|
||||
|
||||
adapter = new WallpaperAdapter(requireContext(), new ArrayList<>(),0);
|
||||
adapter = new WallpaperAdapter(requireContext(), new ArrayList<>(), 0);
|
||||
binding.recyclerView.setAdapter(adapter);
|
||||
|
||||
ItemDecoration itemDecoration = new ItemDecoration(25, 15, 10);
|
||||
binding.recyclerView.addItemDecoration(itemDecoration);
|
||||
|
||||
binding.recyclerView.addItemDecoration(new ItemDecoration(25, 15, 10));
|
||||
}
|
||||
|
||||
private void initEvent() {
|
||||
loadCategoryImage();
|
||||
loadCategoryFirst();
|
||||
}
|
||||
|
||||
private void loadCategoryImage() {
|
||||
private void loadCategoryFirst() {
|
||||
roomUtils
|
||||
.getCategoryFirst()
|
||||
.getFirstCategory()
|
||||
.observe(getViewLifecycleOwner(), new Observer<List<NatureData>>() {
|
||||
@Override
|
||||
public void onChanged(List<NatureData> natureDataList) {
|
||||
|
||||
@ -19,12 +19,12 @@ public interface NatureDataDao {
|
||||
@Query("SELECT * FROM NatureData WHERE isLike = 1 ")
|
||||
LiveData<List<NatureData>> getAllFavoriteLive();
|
||||
|
||||
@Query("SELECT * FROM NatureData WHERE id IN (SELECT MIN(id) FROM NatureData GROUP BY name)")
|
||||
LiveData<List<NatureData>> getFirstRecordOfEachName();
|
||||
@Query("SELECT * FROM NatureData WHERE id IN (SELECT MAX(id) FROM NatureData GROUP BY name) ORDER BY id DESC")
|
||||
LiveData<List<NatureData>> getFirstCategoryByFirst();
|
||||
|
||||
@Query("SELECT * FROM NatureData WHERE name = :name")
|
||||
LiveData<List<NatureData>> getAllCategoryLive(String name);
|
||||
@Query("SELECT * FROM NatureData WHERE name = :name ORDER BY id DESC")
|
||||
LiveData<List<NatureData>> getAllCategoryByName(String name);
|
||||
|
||||
@Query("SELECT isLIKE FROM NatureData WHERE source = :source AND name = :name")
|
||||
LiveData<Boolean> getWallpaperLike(String source, String name);
|
||||
@Query("SELECT isLIKE FROM NatureData WHERE source = :source AND name = :name ORDER BY id DESC")
|
||||
LiveData<Boolean> getWallpaperLikeBySourceAndName(String source, String name);
|
||||
}
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
package com.nature.wallpaper.naturewallpaper.util;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.nature.wallpaper.naturewallpaper.MyApplication;
|
||||
import com.nature.wallpaper.naturewallpaper.room.NatureData;
|
||||
import com.nature.wallpaper.naturewallpaper.room.NatureList;
|
||||
@ -13,58 +11,70 @@ import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class JsonParse {
|
||||
|
||||
private static String loadJSONFromAsset(String fileName) {
|
||||
private static String loadJsonFromAsset(String fileName) throws IOException {
|
||||
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;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
jsonString.append(line);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Log.d("JsonParse", "Loaded JSON: " + jsonString.toString());
|
||||
return jsonString.toString();
|
||||
}
|
||||
|
||||
public static List<NatureList> parseJson(String fileName) {
|
||||
List<NatureList> categoryList = new ArrayList<>();
|
||||
try {
|
||||
String jsonString = loadJSONFromAsset(fileName);
|
||||
String jsonString = loadJsonFromAsset(fileName);
|
||||
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++) {
|
||||
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 = new ArrayList<>();
|
||||
|
||||
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();
|
||||
List<NatureData> natureDataList = parseNatureDataList(dataArray, categoryName);
|
||||
categoryList.add(new NatureList(categoryName, natureDataList));
|
||||
}
|
||||
|
||||
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 "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -22,29 +22,29 @@ public class RoomUtils {
|
||||
}
|
||||
|
||||
public void insertAllImages(List<NatureList> categoryList) {
|
||||
List<NatureData> coolEntities = new ArrayList<>();
|
||||
List<NatureData> dataList = new ArrayList<>();
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
public LiveData<List<NatureData>> getCategoryFirst() {
|
||||
return natureDataDao.getFirstRecordOfEachName();
|
||||
public LiveData<List<NatureData>> getFirstCategory() {
|
||||
return natureDataDao.getFirstCategoryByFirst();
|
||||
}
|
||||
|
||||
public LiveData<List<NatureData>> getAllCategory(String name) {
|
||||
return natureDataDao.getAllCategoryLive(name);
|
||||
return natureDataDao.getAllCategoryByName(name);
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getWallpaperLike(String source, String name) {
|
||||
return natureDataDao.getWallpaperLike(source, name);
|
||||
return natureDataDao.getWallpaperLikeBySourceAndName(source, name);
|
||||
}
|
||||
|
||||
public void update(NatureData imageEntry) {
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -27,7 +27,7 @@
|
||||
android:textSize="25sp"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/white"
|
||||
android:textColor="@color/black"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/image" />
|
||||
|
||||
@ -13,18 +13,15 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="4dp">
|
||||
|
||||
<!-- 图片 -->
|
||||
<ImageView
|
||||
android:id="@+id/image_view"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="250dp"
|
||||
android:adjustViewBounds="true"
|
||||
app:layout_constraintDimensionRatio="16:9"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<!-- 标题 -->
|
||||
<TextView
|
||||
android:id="@+id/title_text"
|
||||
android:layout_width="0dp"
|
||||
@ -40,13 +37,12 @@
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<!-- 收藏按钮 -->
|
||||
<ImageView
|
||||
android:id="@+id/favorite"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/un_like"
|
||||
android:layout_margin="4dp"
|
||||
android:layout_margin="8dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
android:layout_width="250dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:id="@+id/set_wallpaper_dialog"
|
||||
android:background="@drawable/rounded_control_bar_background">
|
||||
|
||||
<TextView
|
||||
|
||||
@ -2,4 +2,6 @@
|
||||
<string name="app_name">Nature Wallpaper</string>
|
||||
<!-- TODO: Remove or change this placeholder text -->
|
||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||
<string name="home">Home</string>
|
||||
<string name="favorite">Favorite</string>
|
||||
</resources>
|
||||
6
keystore.properties
Normal file
6
keystore.properties
Normal 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
|
||||
Loading…
Reference in New Issue
Block a user