From 55b2e6d5fc342d4c3b0cc691dd813946ee26811f Mon Sep 17 00:00:00 2001 From: lihongwei Date: Fri, 28 Mar 2025 16:19:38 +0800 Subject: [PATCH] =?UTF-8?q?V1.0.0=EF=BC=881=EF=BC=89=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/NatureWallpaper.jks | Bin 0 -> 2578 bytes app/proguard-rules.pro | 16 +- .../naturewallpaper/MyApplication.java | 72 +++-- .../activity/MainActivity.java | 92 +++--- .../activity/NatureListActivity.java | 14 +- .../activity/StartActivity.java | 62 ++-- .../activity/WallpaperActivity.java | 276 ++++++++++-------- .../adapter/WallpaperAdapter.java | 2 +- .../fragment/FavoriteFragment.java | 9 +- .../fragment/NatureFragment.java | 14 +- .../naturewallpaper/room/NatureDataDao.java | 12 +- .../naturewallpaper/util/JsonParse.java | 76 ++--- .../naturewallpaper/util/RoomUtils.java | 16 +- .../util/SetAndDownloadUtils.java | 114 -------- .../naturewallpaper/util/SetDownloadUtil.java | 174 +++++++++++ app/src/main/res/layout/activity_start.xml | 2 +- app/src/main/res/layout/item_nature.xml | 10 +- .../main/res/layout/set_wallpaper_dialog.xml | 1 + app/src/main/res/values/strings.xml | 2 + keystore.properties | 6 + 20 files changed, 566 insertions(+), 404 deletions(-) create mode 100644 app/NatureWallpaper.jks delete mode 100644 app/src/main/java/com/nature/wallpaper/naturewallpaper/util/SetAndDownloadUtils.java create mode 100644 app/src/main/java/com/nature/wallpaper/naturewallpaper/util/SetDownloadUtil.java create mode 100644 keystore.properties diff --git a/app/NatureWallpaper.jks b/app/NatureWallpaper.jks new file mode 100644 index 0000000000000000000000000000000000000000..a84811da24a7d80094276ea2b7f7ad88e1e52685 GIT binary patch literal 2578 zcma)8c{tSj8vl)%!B{7T

IP-)5|1jiH6?%dtc#%h-oVgU~41$|01k=ui@l7+d4G zD3L+-#=h?+BD>+b&%IAQ_pf`O_j$L^`~7_Xdq2;MCb4lbfxu`ItdEx12OEefj|9~{0kzN`KN(O?v^^U8 ztK~q;KoF|ARK^gNbv(r#C)Atcf0Q-6&d0YidK}eA9ThF7T2b)vS*E|_tgKV!1{Q(r*fvc_cy*5tl zVbGZYVnWP0CrX$Y1?S<4BiO0&G`}v^&6dvx7J3AeGf~SCPI?>{PDA9j?IbAujU?n`_efz1a8k7C% z9^}1>RS;|Lxx>d}w23ZXtMV}bXEV?>a94yM^YG8c zgYCOn>+@|-N@pPuKZ9@anmpwtoqRYkBiD!!Nw44#JNa?13Egi=1>FtxhiUST=v$`r zm0*sH=xsc@wj=%eDY4Q=m*Gp)_ELV#SWR^?8=Hn{o1nO&rtJVJQDEcw7Hl}+H~-pQEjx6=B_3Lhy}lH*@@9hxSs2Q( z@3~WK#bqD$MT*m}JIjrZEz@I_&y2L|G~|EKdk~kZq!ziY@4qb-f@G}Upx4BzirO$Z zksnghqr&X|b5nPBf!MS@bqDm;N`J4L7Iwoqdy$CK3jj*BzRHL4>rX;H}kg`Z) z{9SLfmkXcw>1(NnhHaIrM~Se0swPcOQ-w#~vgGUJquMU_Wrkx_Hk&9Vh1<3J=B+Sa zeS&X>DJzVL`*~s;FRHARES?v`NjzP2vwPNmv6*DiFVK}MCV@3O11 zF&uyM)peZXiwv(u@uUJVe)%kk=wSzG0XegKHY(_90T)J&sARd*8BF)#A~`$8Ds$d< z>XtxGgB)UuaknC6RwA4Jv<)a+azYjp(oqRu}}| z6YfZ_sQo%6)RjH-dGvwYUoC@f+&<0)b6p==NA1f69TKP66lx_ERdtHV8&bX3GG08E z@)qwVv9J_wK71%Vcy!ps;VAqNKf2Vv@0`8$l+uxvJJHF-u3~$qTJzJ)yO4pvA9PG2 zbk4HvV}d|pok!8++CK=D1K?wP+IwR!Zck;a80B{Vd~tjz*k{0*cSS{>umLeC**!)? z6`XhbQ+8a+>hY?(c4rIVa|75+`fRxLj>qV!GdMX;KOgQO-0H2dc1kh;YFB%^P z0pYRs@^cr#s3|L9l(FhqWfc`Hngs6o`G|!%j|6T$ff|@Vz)7n4H39uE0UxX^a^3e+ z+%pmNdn4~F6G!d_DF2UuJ3H8o%u8N$FKiECbEpJ-qDf#~oi{y++s_UHyCtwSzBz9P zw-CWJ^Bogi!;A$k?{BFUowaLmk#hd*NnatbW!U(M?Kd&4t!Af>XE7JN5aCl{9@mzR|-s zliT_R%W$G1_GtNO$&``oGhM`m-|<=1LFB^x=_SI(8G`Gr$-Qa`F=dR_r_zN&=~hZT zZ@}3iNY!l36x4mx@n$F{`2OuAt@sSYW2@%MkZ8D}5AsKNzyq=|u483$6zodVPK_|u z4$tk-u9W&d@@mp$NFJWH=(TaRDrg+4&ub+lq>f0z2qn`!(K^IZJv?u+0Cmb-UqN@5 z^?F$RlTM{kwyCLfK_zn7$D!Q=>Jy2}ber^K-P9qp3{lp^tf5a@#hvY|9M z3g>0%M-6i{yH+3Ln34)AJ&5yxe&5@uhVVX9k3ZTI?q6{&zERzCV_@Y1?Y3Nn4)Rk+ zQDS9mwY0DID%`Amn*qG0?j%&@!t6CVl)8o7=yb!D?r+Z}}n)~aI$tk5Wa zgWA#&Ad;CIx%nw^L}wfxxlRd1CJEMw;`&`a(ruCGdK=3{v*J#IH}ZIcU-*=%w!>Fh zmh7=H!;4h64C45(f*qZ7pdb>_)W+E#Trn!@e75lA$ zV@6y%jyh0#tK0s|L)n`g^tZOL-%-_H1~@qL>h3hWPx14FypI3-adQ&0<&@PFbD<=q2CqmamHHj_bHF5Tu8(HdWtGLaA9tCG%bG$4 z*DNOCOC8ek#Pyzmn)ZM<_7((s@dmg*GMa>U;@IC>6!9pT|BK~DiS2~pRdzq73%CW_ zRDmHs>TBfXwHLNn{8Y-ID9d0eK zlqnl;w-Z@o#+FS?O^+`Lchfzt92P8Wb=u3I7dKKVi)*6`fU%I-@S`xMmPMm8W3|z0 zPwpyA(?t_BSzaI38#snrAL8`Pb0qU6g7Scm%_TWQi)a%x2F>~NPGSN<0fS6%4 zNBhyerU1%WQN2dexO#%Zd2U{j0SWI^(O4k}V%FG-o7S}ky_Y>xh7wAZF@VuL{; +} + +-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 { *; } \ No newline at end of file diff --git a/app/src/main/java/com/nature/wallpaper/naturewallpaper/MyApplication.java b/app/src/main/java/com/nature/wallpaper/naturewallpaper/MyApplication.java index b4811c5..2e6499b 100644 --- a/app/src/main/java/com/nature/wallpaper/naturewallpaper/MyApplication.java +++ b/app/src/main/java/com/nature/wallpaper/naturewallpaper/MyApplication.java @@ -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(); + initializeInstance(); + initializeDatabaseIfNeeded(); + } - 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(); - } - + 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 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 natureLists = loadCategoryList(); RoomUtils roomUtils = new RoomUtils(getContext()); - roomUtils.insertAllImages(natureListList); + roomUtils.insertAllImages(natureLists); }); } - public static List getCategoryList() { - return JsonParse.parseJson("nature_wallpapers.json"); + private void markDatabaseAsInitialized(SharedPreferences prefs) { + prefs.edit() + .putBoolean(KEY_DB_INITIALIZED, true) + .apply(); } -} + + public static List loadCategoryList() { + return JsonParse.parseJson(JSON_FILE_NAME); + } + + @Override + public void onTerminate() { + super.onTerminate(); + shutdownExecutor(); + } + + private void shutdownExecutor() { + executor.shutdown(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/nature/wallpaper/naturewallpaper/activity/MainActivity.java b/app/src/main/java/com/nature/wallpaper/naturewallpaper/activity/MainActivity.java index 21afc32..efb6a2e 100644 --- a/app/src/main/java/com/nature/wallpaper/naturewallpaper/activity/MainActivity.java +++ b/app/src/main/java/com/nature/wallpaper/naturewallpaper/activity/MainActivity.java @@ -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; - } - - tabLayoutBinding.image.setImageResource(iconResId); - tabLayoutBinding.text.setTextColor(ContextCompat.getColor(this, textColorResId)); + 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)); } - 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; + private void updateTabState(TabLayout.Tab tab, boolean isSelected) { + if (tab.getCustomView() == null) return; + + 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 diff --git a/app/src/main/java/com/nature/wallpaper/naturewallpaper/activity/NatureListActivity.java b/app/src/main/java/com/nature/wallpaper/naturewallpaper/activity/NatureListActivity.java index 9a390fd..f6c9c57 100644 --- a/app/src/main/java/com/nature/wallpaper/naturewallpaper/activity/NatureListActivity.java +++ b/app/src/main/java/com/nature/wallpaper/naturewallpaper/activity/NatureListActivity.java @@ -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>() { diff --git a/app/src/main/java/com/nature/wallpaper/naturewallpaper/activity/StartActivity.java b/app/src/main/java/com/nature/wallpaper/naturewallpaper/activity/StartActivity.java index 198171c..7fd9dfc 100644 --- a/app/src/main/java/com/nature/wallpaper/naturewallpaper/activity/StartActivity.java +++ b/app/src/main/java/com/nature/wallpaper/naturewallpaper/activity/StartActivity.java @@ -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() { - binding.progressBar.setProgress(100); + private void updateProgress(long millisUntilFinished) { + int progress = calculateProgress(millisUntilFinished); + binding.progressBar.setProgress(progress); + } - Intent intent = new Intent(StartActivity.this, MainActivity.class); + 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(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; + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/nature/wallpaper/naturewallpaper/activity/WallpaperActivity.java b/app/src/main/java/com/nature/wallpaper/naturewallpaper/activity/WallpaperActivity.java index 719b79c..6a86ed0 100644 --- a/app/src/main/java/com/nature/wallpaper/naturewallpaper/activity/WallpaperActivity.java +++ b/app/src/main/java/com/nature/wallpaper/naturewallpaper/activity/WallpaperActivity.java @@ -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 downloadWallpaper() { + showProgress(); + setDownloadUtil.setAsWallpaper(this, source, this); + } + + 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(); + return; + } + + 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 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) { - showProgress(); - - executorService.submit(() -> { - boolean success = false; - try { - success = setWallpaperImage(bitmap, flag); - } catch (Exception e) { - e.printStackTrace(); - } finally { - boolean finalSuccess = success; - handler.post(() -> { - hideProgress(); - bottomSheetDialog.findViewById(R.id.both).setEnabled(true); - bottomSheetDialog.findViewById(R.id.lock).setEnabled(true); - bottomSheetDialog.findViewById(R.id.desktop).setEnabled(true); - - String message = finalSuccess ? "Wallpaper set successfully" : "Failed to set wallpaper"; - Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show(); - }); - } - }); + 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(); + } + + private void cleanupResources() { + if (mainHandler != null) { + mainHandler.removeCallbacksAndMessages(null); } - if (executorService != null) { + if (executorService != null && !executorService.isShutdown()) { executorService.shutdown(); } + if (setDownloadUtil != null) { + setDownloadUtil.shutdown(); + } binding = null; } } \ No newline at end of file diff --git a/app/src/main/java/com/nature/wallpaper/naturewallpaper/adapter/WallpaperAdapter.java b/app/src/main/java/com/nature/wallpaper/naturewallpaper/adapter/WallpaperAdapter.java index 6d44502..cc04feb 100644 --- a/app/src/main/java/com/nature/wallpaper/naturewallpaper/adapter/WallpaperAdapter.java +++ b/app/src/main/java/com/nature/wallpaper/naturewallpaper/adapter/WallpaperAdapter.java @@ -29,7 +29,7 @@ public class WallpaperAdapter extends RecyclerView.Adapter 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 natureDataList, int displayMode) { diff --git a/app/src/main/java/com/nature/wallpaper/naturewallpaper/fragment/FavoriteFragment.java b/app/src/main/java/com/nature/wallpaper/naturewallpaper/fragment/FavoriteFragment.java index 9e98dc9..24341b3 100644 --- a/app/src/main/java/com/nature/wallpaper/naturewallpaper/fragment/FavoriteFragment.java +++ b/app/src/main/java/com/nature/wallpaper/naturewallpaper/fragment/FavoriteFragment.java @@ -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>() { @Override public void onChanged(List natureDataList) { diff --git a/app/src/main/java/com/nature/wallpaper/naturewallpaper/fragment/NatureFragment.java b/app/src/main/java/com/nature/wallpaper/naturewallpaper/fragment/NatureFragment.java index 6a412e8..9c9b005 100644 --- a/app/src/main/java/com/nature/wallpaper/naturewallpaper/fragment/NatureFragment.java +++ b/app/src/main/java/com/nature/wallpaper/naturewallpaper/fragment/NatureFragment.java @@ -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>() { @Override public void onChanged(List natureDataList) { diff --git a/app/src/main/java/com/nature/wallpaper/naturewallpaper/room/NatureDataDao.java b/app/src/main/java/com/nature/wallpaper/naturewallpaper/room/NatureDataDao.java index 84fe355..2c7c4dd 100644 --- a/app/src/main/java/com/nature/wallpaper/naturewallpaper/room/NatureDataDao.java +++ b/app/src/main/java/com/nature/wallpaper/naturewallpaper/room/NatureDataDao.java @@ -19,12 +19,12 @@ public interface NatureDataDao { @Query("SELECT * FROM NatureData WHERE isLike = 1 ") LiveData> getAllFavoriteLive(); - @Query("SELECT * FROM NatureData WHERE id IN (SELECT MIN(id) FROM NatureData GROUP BY name)") - LiveData> getFirstRecordOfEachName(); + @Query("SELECT * FROM NatureData WHERE id IN (SELECT MAX(id) FROM NatureData GROUP BY name) ORDER BY id DESC") + LiveData> getFirstCategoryByFirst(); - @Query("SELECT * FROM NatureData WHERE name = :name") - LiveData> getAllCategoryLive(String name); + @Query("SELECT * FROM NatureData WHERE name = :name ORDER BY id DESC") + LiveData> getAllCategoryByName(String name); - @Query("SELECT isLIKE FROM NatureData WHERE source = :source AND name = :name") - LiveData getWallpaperLike(String source, String name); + @Query("SELECT isLIKE FROM NatureData WHERE source = :source AND name = :name ORDER BY id DESC") + LiveData getWallpaperLikeBySourceAndName(String source, String name); } diff --git a/app/src/main/java/com/nature/wallpaper/naturewallpaper/util/JsonParse.java b/app/src/main/java/com/nature/wallpaper/naturewallpaper/util/JsonParse.java index 50482a2..f4fe3ec 100644 --- a/app/src/main/java/com/nature/wallpaper/naturewallpaper/util/JsonParse.java +++ b/app/src/main/java/com/nature/wallpaper/naturewallpaper/util/JsonParse.java @@ -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 parseJson(String fileName) { - List categoryList = new ArrayList<>(); try { - String jsonString = loadJSONFromAsset(fileName); + String jsonString = loadJsonFromAsset(fileName); if (jsonString.isEmpty()) { - throw new IllegalArgumentException("JSON file is empty or invalid."); - } - - JSONArray jsonArray = new JSONArray(jsonString); - for (int i = 0; i < jsonArray.length(); i++) { - JSONObject categoryObject = jsonArray.getJSONObject(i); - String name = categoryObject.getString("name"); - - JSONArray listArray = categoryObject.getJSONArray("data"); - List 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)); + return Collections.emptyList(); } + return parseJsonArray(new JSONArray(jsonString)); } catch (Exception e) { - e.printStackTrace(); + return Collections.emptyList(); + } + } + + private static List parseJsonArray(JSONArray jsonArray) throws org.json.JSONException { + List categoryList = new ArrayList<>(); + + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject categoryObject = jsonArray.getJSONObject(i); + String categoryName = categoryObject.getString("name"); + JSONArray dataArray = categoryObject.getJSONArray("data"); + + List natureDataList = parseNatureDataList(dataArray, categoryName); + categoryList.add(new NatureList(categoryName, natureDataList)); } return categoryList; } + private static List parseNatureDataList(JSONArray dataArray, String categoryName) + throws org.json.JSONException { + List 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 ""; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/nature/wallpaper/naturewallpaper/util/RoomUtils.java b/app/src/main/java/com/nature/wallpaper/naturewallpaper/util/RoomUtils.java index d2e563a..4d9491b 100644 --- a/app/src/main/java/com/nature/wallpaper/naturewallpaper/util/RoomUtils.java +++ b/app/src/main/java/com/nature/wallpaper/naturewallpaper/util/RoomUtils.java @@ -22,29 +22,29 @@ public class RoomUtils { } public void insertAllImages(List categoryList) { - List coolEntities = new ArrayList<>(); + List dataList = new ArrayList<>(); for (NatureList category : categoryList) { - coolEntities.addAll(category.getList()); + dataList.addAll(category.getList()); } - natureDataDao.insertAll(coolEntities); + natureDataDao.insertAll(dataList); } - public LiveData> getAllFavoriteList() { + public LiveData> getAllFavorite() { return natureDataDao.getAllFavoriteLive(); } - public LiveData> getCategoryFirst() { - return natureDataDao.getFirstRecordOfEachName(); + public LiveData> getFirstCategory() { + return natureDataDao.getFirstCategoryByFirst(); } public LiveData> getAllCategory(String name) { - return natureDataDao.getAllCategoryLive(name); + return natureDataDao.getAllCategoryByName(name); } public LiveData getWallpaperLike(String source, String name) { - return natureDataDao.getWallpaperLike(source, name); + return natureDataDao.getWallpaperLikeBySourceAndName(source, name); } public void update(NatureData imageEntry) { diff --git a/app/src/main/java/com/nature/wallpaper/naturewallpaper/util/SetAndDownloadUtils.java b/app/src/main/java/com/nature/wallpaper/naturewallpaper/util/SetAndDownloadUtils.java deleted file mode 100644 index 5989c8a..0000000 --- a/app/src/main/java/com/nature/wallpaper/naturewallpaper/util/SetAndDownloadUtils.java +++ /dev/null @@ -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(); - } -} diff --git a/app/src/main/java/com/nature/wallpaper/naturewallpaper/util/SetDownloadUtil.java b/app/src/main/java/com/nature/wallpaper/naturewallpaper/util/SetDownloadUtil.java new file mode 100644 index 0000000..e22319b --- /dev/null +++ b/app/src/main/java/com/nature/wallpaper/naturewallpaper/util/SetDownloadUtil.java @@ -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(); + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_start.xml b/app/src/main/res/layout/activity_start.xml index fe91e69..f0c30ce 100644 --- a/app/src/main/res/layout/activity_start.xml +++ b/app/src/main/res/layout/activity_start.xml @@ -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" /> diff --git a/app/src/main/res/layout/item_nature.xml b/app/src/main/res/layout/item_nature.xml index e023370..d90b9a8 100644 --- a/app/src/main/res/layout/item_nature.xml +++ b/app/src/main/res/layout/item_nature.xml @@ -13,18 +13,15 @@ android:layout_height="wrap_content" android:padding="4dp"> - - - diff --git a/app/src/main/res/layout/set_wallpaper_dialog.xml b/app/src/main/res/layout/set_wallpaper_dialog.xml index 7f6198f..5eaa38c 100644 --- a/app/src/main/res/layout/set_wallpaper_dialog.xml +++ b/app/src/main/res/layout/set_wallpaper_dialog.xml @@ -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"> Nature Wallpaper Hello blank fragment + Home + Favorite \ No newline at end of file diff --git a/keystore.properties b/keystore.properties new file mode 100644 index 0000000..19c6dd3 --- /dev/null +++ b/keystore.properties @@ -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 \ No newline at end of file