This commit is contained in:
litingting 2025-12-26 14:12:53 +08:00
commit 4be8421f21
136 changed files with 171476 additions and 0 deletions

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

66
app/build.gradle.kts Normal file
View File

@ -0,0 +1,66 @@
import java.util.Date
import java.text.SimpleDateFormat
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("io.objectbox")
kotlin("kapt")
}
// 生成时间戳(保持原有格式,但后续文件名中不包含特殊字符)
val timestamp = SimpleDateFormat("MM_dd_HH_mm").format(Date())
android {
namespace = "com.snap.wall"
compileSdk = 36
defaultConfig {
applicationId = "com.snap.wall"
minSdk = 24
targetSdk = 36
versionCode = 1
versionName = "1.0"
setProperty("archivesBaseName", "SnapWall_V" + versionName + "(${versionCode})_$timestamp")
testInstrumentationRunner = "androidx.live.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
buildFeatures {
viewBinding = true
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
implementation("com.google.code.gson:gson:2.10.1")
implementation("com.github.bumptech.glide:glide:5.0.5")
implementation("androidx.activity:activity:1.12.0")
kapt("com.github.bumptech.glide:compiler:4.16.0")
implementation("androidx.appcompat:appcompat:1.7.1")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.2.1")
implementation("androidx.test:monitor:1.8.0")
implementation("androidx.test.ext:junit:1.3.0")
testImplementation("junit:junit:4.13.2")
implementation("jp.wasabeef:glide-transformations:4.3.0") // Glide图片变换库
implementation("com.squareup.okhttp3:okhttp:5.3.1")
}

View File

@ -0,0 +1,164 @@
{
"_note1": "KEEP THIS FILE! Check it into a version control system (VCS) like git.",
"_note2": "ObjectBox manages crucial IDs for your object model. See docs for details.",
"_note3": "If you have VCS merge conflicts, you must resolve them according to ObjectBox docs.",
"entities": [
{
"id": "7:4481900207338271736",
"lastPropertyId": "13:747315404376095562",
"name": "Information",
"properties": [
{
"id": "1:2213421576691773001",
"name": "id",
"type": 6,
"flags": 1
},
{
"id": "2:1761374873324963391",
"name": "categoryName",
"type": 9
},
{
"id": "3:7035223913750449698",
"name": "imId",
"type": 9
},
{
"id": "4:2778534831751310584",
"name": "description",
"type": 9
},
{
"id": "5:1554807725758930901",
"name": "fullUrl",
"type": 9
},
{
"id": "6:2143075629380316240",
"name": "previewUrl1080",
"type": 9
},
{
"id": "7:8257544604178079575",
"name": "previewUrl400",
"type": 9
},
{
"id": "8:1294040731405970998",
"name": "previewUrl200",
"type": 9
},
{
"id": "9:7311149724354485262",
"name": "authorName",
"type": 9
},
{
"id": "10:1320180233997561822",
"name": "authorHeader",
"type": 9
},
{
"id": "11:1539880221357131326",
"name": "authorHtml",
"type": 9
},
{
"id": "12:1463781112302159019",
"name": "isLike",
"type": 1
},
{
"id": "13:747315404376095562",
"name": "isDownload",
"type": 1
}
],
"relations": []
}
],
"lastEntityId": "8:168243408024271179",
"lastIndexId": "0:0",
"lastRelationId": "0:0",
"lastSequenceId": "0:0",
"modelVersion": 5,
"modelVersionParserMinimum": 5,
"retiredEntityUids": [
8119453540460508569,
8776066878034520742,
817335537070466014,
5374318059423987080,
6686897826437564736,
8653997226256447908,
168243408024271179
],
"retiredIndexUids": [],
"retiredPropertyUids": [
8848640050018073106,
4870222079156330783,
4966768060561274983,
8892036187720267027,
1670319685727744805,
3855211567189961055,
7567671966987007993,
2590164264280025677,
8912833100894718986,
7138929457594592554,
3957870060050722570,
2943285943884558608,
7262008615134929676,
7105947400861196483,
1954934496493857304,
8582031355111471002,
8410380097928190493,
3380197792593924336,
5750724995960958985,
5907193265594068445,
7643711915014989832,
5454072153734548882,
8866886314389627366,
6647852625511577303,
8481286751506557167,
615207224772228883,
2114128640869665061,
4004858028833616093,
1649948666606108567,
4925649389754620618,
6869613325061909824,
1127054227079914732,
7583347258203607289,
1874919077310718019,
3560534746373995189,
5323174779797549688,
6493016523726214639,
6241934991596178294,
697564122644877580,
5123147135686386853,
8153050789414477927,
4430301556301172703,
7683657851560967678,
2111285075400493750,
2037948162911967828,
5013578949085393547,
5408284309630409396,
6635766303651707557,
4342422943730370041,
3298743955069977105,
5371327495060669283,
6709632424885529838,
2706347311073356734,
5663009972863482096,
6923322785802132231,
650891216213941689,
5056695340226012049,
8775201763186517130,
1673271081833415640,
4790845058238099810,
8332671798479419574,
9011866236080522704,
222725623302087760
],
"retiredRelationUids": [],
"version": 1
}

32
app/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,32 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-keep class com.snap.wall.bean.** { *; }
-keep class com.google.gson.** { *; }
-keep class com.snap.wall.Wallpaper { *; }
-keep class com.google.gson.reflect.TypeToken { *; }
-keep class * extends com.google.gson.reflect.TypeToken
-keepattributes Signature
-keepattributes AnnotationDefault,RuntimeVisibleAnnotations

BIN
app/sapwall.jks Normal file

Binary file not shown.

View File

@ -0,0 +1,21 @@
package com.hd.wallpaper.free.walls;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under live.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.hd.kwallpapers.wallpapers.live", appContext.getPackageName());
}
}

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission
android:name="android.permission.BLUETOOTH"
tools:node="remove" />
<uses-permission
android:name="android.permission.BLUETOOTH_ADMIN"
tools:node="remove" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<application
android:name=".App"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/logo_snap"
android:label="@string/app_name"
android:roundIcon="@mipmap/logo_snap"
android:supportsRtl="true"
android:theme="@style/Theme.Wallpaper"
tools:targetApi="31">
<activity
android:name=".activity.RencentActivity"
android:exported="false" />
<activity
android:name=".activity.MySearchActivity"
android:exported="false" />
<activity
android:name=".activity.TabActivity"
android:exported="false" />
<activity
android:name=".activity.PreviewActivity"
android:exported="false" />
<activity
android:name=".activity.PrimaryActivity"
android:exported="false" />
<activity
android:name=".activity.OneActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

20703
app/src/main/assets/Film.json Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 KiB

View File

@ -0,0 +1,120 @@
package com.snap.wall;
import android.app.Application;
import android.content.Context;
import android.graphics.Typeface;
import android.util.Log;
import com.snap.wall.bean.Information;
import com.snap.wall.mytool.Comutils;
import com.snap.wall.mytool.ObectManager;
import com.snap.wall.mytool.JsonData;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
// 移除ObjectBox的import避免手动创建
// import io.objectbox.BoxStore;
// import com.snap.wall.mybean.MyObjectBox;
// import com.snap.wall.mybean.History;
public class App extends Application {
public static Context mAppContext;
public static String TAG = "-------MyApp---------";
public static Typeface defaultFont;
private String animasName = "Animals.json";
private String exName = "Experimental.json";
private String filmName = "Film.json";
private String natureName = "Nature.json";
private String pattName = "Patterns.json";
private String streetName = "Street.json";
private String travelName = "Travel.json";
private String wallpaperName = "Featured.json";
private ExecutorService executor;
private static List<String> CategoryNames = new ArrayList<>();
private int i = 0;
@Override
public void onCreate() {
super.onCreate();
mAppContext = this;
defaultFont = Typeface.createFromAsset(getAssets(), "custfont.ttf");
ObectManager.init(this);
executor = Executors.newFixedThreadPool(8);
String[] names = {wallpaperName, animasName, exName, filmName, natureName, pattName, streetName, travelName};
try {
for (String name : names) {
InputStream open = getAssets().open(name);
String covertStr = Comutils.getCovertStr(open);
if (!covertStr.isEmpty()) {
String realName = name.substring(0, name.indexOf("."));
CategoryNames.add(realName);
executor.execute(new Runnable() {
@Override
public void run() {
i++;
Log.d(App.TAG, "------------111");
List<Information> data = JsonData.INSTANCE.getData(covertStr, realName);
Collections.shuffle(data);
for (Information data1:data){
ObectManager.addData(data1);
}
// if (i == 8) {
// executor.shutdown();
// Log.d(MyWallpaper.TAG, "------------data complete");
// }
}
});
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static List<String> getCategoryNames() {
return CategoryNames;
}
// private void initTop(){
// ATSDK.checkIsEuTraffic(this, new NetTrafficeCallback() {
//
// @Override
// public void onResultCallback(boolean isEU) {
// Log.e(TAG, "onResultCallback:" + isEU);
// if (isEU && ATSDK.getGDPRDataLevel( MyApp.mAppContext) == ATSDK.UNKNOWN) {
// ATSDK.showGdprAuth(MyApp.mAppContext);
// }
//
// }
//
// @Override
// public void onErrorCallback(String errorMsg) {
// Log.e(TAG, "onErrorCallback:" + errorMsg);
// }
// });
//
// ATSDK.init( this, APPId, AppKey);
// //测试工具
//// ATDebuggerUITest.showDebuggerUI(this,debug_Key);
// AdManager.loadAllAd();
//
// }
}

View File

@ -0,0 +1,99 @@
package com.snap.wall;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import com.bumptech.glide.RequestManager;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import java.util.List;
public class RecentWallpaperAdapter extends BaseAdapter {
private Context context;
private List<Wallpaper> wallpaperList;
private final int cornerRadius = 12; // 圆角大小dp
private OnItemClickListener onItemClickListener;
private RequestManager glideRequestManager;
// 点击回调接口
public interface OnItemClickListener {
void onItemClick(Wallpaper wallpaper);
}
// 构造方法
public RecentWallpaperAdapter(Context context, List<Wallpaper> wallpaperList, RequestManager glideManager, OnItemClickListener listener) {
this.context = context;
this.wallpaperList = wallpaperList;
this.glideRequestManager = glideManager;
this.onItemClickListener = listener;
}
@Override
public int getCount() {
return wallpaperList.size();
}
@Override
public Object getItem(int position) {
return wallpaperList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.item_wallpaper, parent, false);
holder = new ViewHolder();
holder.ivWallpaper = convertView.findViewById(R.id.iv_wallpaper);
// 强制设置ScaleType确保圆角生效
holder.ivWallpaper.setScaleType(ImageView.ScaleType.CENTER_CROP);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Wallpaper wallpaper = wallpaperList.get(position);
// 核心修复Glide组合变换CenterCrop + 圆角强制生效
if (glideRequestManager != null) {
RequestOptions options = new RequestOptions()
.transform(new CenterCrop(), new RoundedCorners(dp2px(cornerRadius)))
.dontAnimate();
glideRequestManager
.load(wallpaper.getImageUrl())
.apply(options)
.into(holder.ivWallpaper);
}
// Item点击事件
convertView.setOnClickListener(v -> {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(wallpaper);
}
});
return convertView;
}
// dp转px精确计算避免圆角大小偏差
private int dp2px(int dp) {
float density = context.getResources().getDisplayMetrics().density;
return Math.round(dp * density);
}
static class ViewHolder {
ImageView ivWallpaper;
}
}

View File

@ -0,0 +1,80 @@
package com.snap.wall;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.snap.wall.Wallpaper;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
public class RecentWallpaperManager {
private static final String TAG = "RecentWallpaperManager";
private static final String PREF_NAME = "RecentWallpapers";
private static final String KEY_RECENT_LIST = "recent_wallpaper_list";
private static final int MAX_RECENT_COUNT = 20;
private static RecentWallpaperManager instance;
private SharedPreferences sp;
private Gson gson;
private RecentWallpaperManager(Context context) {
sp = context.getApplicationContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
gson = new Gson();
}
public static synchronized RecentWallpaperManager getInstance(Context context) {
if (instance == null) {
instance = new RecentWallpaperManager(context);
}
return instance;
}
// 添加浏览记录核心确保添加成功
public void addRecentWallpaper(Wallpaper wallpaper) {
if (wallpaper == null || wallpaper.getId() == null) {
Log.e(TAG, "添加失败:壁纸对象/ID为空");
return;
}
List<Wallpaper> list = getRecentWallpapers();
// 移除重复项
list.removeIf(w -> w.getId().equals(wallpaper.getId()));
// 添加到顶部
list.add(0, wallpaper);
// 限制数量
if (list.size() > MAX_RECENT_COUNT) {
list = list.subList(0, MAX_RECENT_COUNT);
}
// 保存到SP
String json = gson.toJson(list);
sp.edit().putString(KEY_RECENT_LIST, json).commit(); // 用commit确保立即保存
Log.d(TAG, "添加成功:" + wallpaper.getTitle() + ",当前总数:" + list.size());
}
// 获取浏览记录核心确保读取成功
public List<Wallpaper> getRecentWallpapers() {
String json = sp.getString(KEY_RECENT_LIST, "");
Type type = new TypeToken<ArrayList<Wallpaper>>() {}.getType();
List<Wallpaper> list = gson.fromJson(json, type);
if (list == null) {
list = new ArrayList<>();
Log.d(TAG, "读取到空列表,初始化新列表");
} else {
Log.d(TAG, "读取到记录数:" + list.size());
}
return list;
}
// 清空记录用于测试
public void clear() {
sp.edit().remove(KEY_RECENT_LIST).commit();
Log.d(TAG, "已清空所有记录");
}
}

View File

@ -0,0 +1,32 @@
package com.snap.wall;
import java.io.Serializable;
public class Wallpaper implements Serializable {
private String id;
private String title;
private String imageUrl;
private long viewTime; // 浏览时间戳
public Wallpaper() {}
public Wallpaper(String id, String title, String imageUrl, long viewTime) {
this.id = id;
this.title = title;
this.imageUrl = imageUrl;
this.viewTime = viewTime;
}
// Getter和Setter方法
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getImageUrl() { return imageUrl; }
public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; }
public long getViewTime() { return viewTime; }
public void setViewTime(long viewTime) { this.viewTime = viewTime; }
}

View File

@ -0,0 +1,105 @@
package com.snap.wall.activity
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.TextView.OnEditorActionListener
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.GridLayoutManager
import com.snap.wall.R
import com.snap.wall.adapter.OnItemclick
import com.snap.wall.databinding.ActivitySearchBinding
import com.snap.wall.myitem.ItemTab
import com.snap.wall.bean.Information
import com.snap.wall.mytool.Comutils
import com.snap.wall.mytool.Itemhelper
import com.snap.wall.mytool.ObectManager
class MySearchActivity : AppCompatActivity() ,
OnItemclick {
private lateinit var adapterWallapper: ItemTab
private lateinit var binding:ActivitySearchBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySearchBinding.inflate(layoutInflater)
setContentView(binding.root)
Comutils.initFull(this, false)
initList()
binding.imageviewBack.setOnClickListener {
finish()
}
}
private fun initList() {
val height = Comutils.dp2Px(180)
adapterWallapper =
ItemTab(this, height, true)
adapterWallapper.setInfoWallpaperListener(this)
val recyclerItemHelper = Itemhelper(10, 10, 15)
val gridLayoutManager = GridLayoutManager(this, 2)
binding.resultRecycler.run {
layoutManager = gridLayoutManager
addItemDecoration(recyclerItemHelper)
adapter = adapterWallapper
}
binding.et.setOnEditorActionListener(OnEditorActionListener { v, actionId, event ->
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
startSearch()
return@OnEditorActionListener true
}
false
})
binding.btnSearch.setOnClickListener { startSearch() }
}
private fun closeKeyboard() {
val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(binding.et.windowToken, 0)
}
private fun startSearch() {
closeKeyboard()
binding.searchPb.visibility = View.VISIBLE
val string: String = binding.et.text.toString()
if (string.isNotEmpty()) {
val search = ObectManager.search(string)
if (search.size > 0) {
showEmpty(false)
adapterWallapper.setDataInfo(search)
binding.searchPb.visibility = View.GONE
} else {
binding.searchPb.visibility = View.GONE
showEmpty(true)
}
} else {
binding.searchPb.visibility = View.GONE
Toast.makeText(
this,
getString(R.string.please_input_keyword),
Toast.LENGTH_SHORT
).show()
}
}
private fun showEmpty(showEmpty: Boolean) {
if (showEmpty) {
binding.emptyLayout.visibility = View.VISIBLE
binding.resultRecycler.visibility = View.GONE
} else {
binding.emptyLayout.visibility = View.GONE
binding.resultRecycler.visibility = View.VISIBLE
}
}
override fun onItemClickAction(info: Information?) {
val intent = Intent(this, PreviewActivity::class.java)
intent.putExtra(Comutils.key_info, info)
startActivity(intent)
}
}

View File

@ -0,0 +1,60 @@
package com.snap.wall.activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.snap.wall.R;
import com.snap.wall.mytool.Comutils;
import android.os.CountDownTimer;
public class OneActivity extends AppCompatActivity {
private static final long TOTAL_TIME = 2000;
// 进度更新间隔50毫秒
private static final long UPDATE_INTERVAL = 50;
private ProgressBar progressBar;
private TextView tvProgress;
private CountDownTimer countDownTimer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Comutils.initFull(this, false);
setContentView(R.layout.activity_one);
progressBar = findViewById(R.id.progressbar);
tvProgress = findViewById(R.id.tv_progress);
progressBar.setMax(100);
startCountDown();
}
private void startCountDown() {
countDownTimer = new CountDownTimer(TOTAL_TIME, UPDATE_INTERVAL) {
@Override
public void onTick(long millisUntilFinished) {
long elapsedTime = TOTAL_TIME - millisUntilFinished;
int progress = (int) (elapsedTime * 100 / TOTAL_TIME);
progressBar.setProgress(progress);
tvProgress.setText(progress + "%");
}
@Override
public void onFinish() {
progressBar.setProgress(100);
tvProgress.setText("100%");
Intent intent = new Intent(OneActivity.this, PrimaryActivity.class);
startActivity(intent);
finish();
}
}.start();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (countDownTimer != null) {
countDownTimer.cancel();
}
}
}

View File

@ -0,0 +1,344 @@
package com.snap.wall.activity;
import android.app.WallpaperManager;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.DecodeFormat;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
import com.snap.wall.Wallpaper;
import com.snap.wall.adapter.OnSelecttype;
import com.snap.wall.databinding.ActivityPreviewBinding;
import com.snap.wall.bean.Information;
import com.snap.wall.fragment.Mydialog;
import com.snap.wall.mytool.Comutils;
import com.snap.wall.mytool.ObectManager;
import com.snap.wall.R;
import com.snap.wall.mytool.JsonData;
import java.io.File;
import java.io.FileInputStream;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
import okhttp3.Call;
public class PreviewActivity extends AppCompatActivity implements OnSelecttype {
private Information data;
private WallpaperManager wallpaperManager;
private final int permissionCode = 1;
private String mSavePath;
private String imId;
private String fullUrl;
private Mydialog dialogType;
private File downloadFile;
private Call call;
private ActivityPreviewBinding vb;
private Timer clockTimer;
private Handler mainHandler;
private final SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm", Locale.CHINA);
private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd EEEE", Locale.ENGLISH);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
vb = ActivityPreviewBinding.inflate(getLayoutInflater());
Comutils.initFull(this, true);
setContentView(vb.getRoot());
data = (Information) getIntent().getSerializableExtra(Comutils.key_info);
if (data == null) {
finish();
return;
}
imId = data.getImId();
mSavePath = JsonData.INSTANCE.getSaveFilePath(this, imId);
fullUrl = data.getFullUrl();
wallpaperManager = WallpaperManager.getInstance(this);
mainHandler = new Handler(Looper.getMainLooper());
addToRecentWallpapers();
initClick();
loadDetail();
vb.tvContent.setText(data.getDescription());
initClockWeather();
startClockRefresh();
}
private void addToRecentWallpapers() {
if (data == null) return;
Wallpaper wallpaper = new Wallpaper();
wallpaper.setId(data.getImId());
wallpaper.setTitle(data.getDescription() != null ? data.getDescription() : "Wallpaper " + data.getImId());
wallpaper.setImageUrl(data.getFullUrl() != null ? data.getFullUrl() : data.getPreviewUrl1080());
wallpaper.setViewTime(System.currentTimeMillis());
}
private void initClockWeather() {
updateClockWeather();
vb.tvWeather.setText("晴 25℃");
}
private void startClockRefresh() {
if (clockTimer != null) {
clockTimer.cancel();
}
clockTimer = new Timer();
clockTimer.schedule(new TimerTask() {
@Override
public void run() {
if (!isDestroyed() && mainHandler != null) {
mainHandler.post(PreviewActivity.this::updateClockWeather);
}
}
}, 0, 1000);
}
private void updateClockWeather() {
Date currentTime = new Date();
vb.tvClock.setText(timeFormat.format(currentTime));
vb.tvDate.setText(dateFormat.format(currentTime));
int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
if (hour >= 18 || hour < 6) {
vb.tvWeather.setText("Night 18℃");
} else if (hour >= 12 && hour < 18) {
vb.tvWeather.setText("Sunny 28℃");
} else {
vb.tvWeather.setText("Sunny 25℃");
}
}
private void loadDetail() {
String previewUrl400 = data.getPreviewUrl400();
String previewUrl1080 = data.getPreviewUrl1080();
File file = new File(mSavePath);
RequestOptions options = new RequestOptions().format(DecodeFormat.PREFER_RGB_565);
if (file.exists()) {
Glide.with(this)
.load(file)
.apply(options)
.placeholder(R.mipmap.im_placeholder)
.transition(DrawableTransitionOptions.withCrossFade(500))
.fitCenter()
.into(vb.imageviewPreview);
} else {
Glide.with(this)
.asDrawable()
.load(previewUrl1080)
.apply(options)
.skipMemoryCache(true)
.placeholder(R.mipmap.im_placeholder)
.thumbnail(Glide.with(this)
.asDrawable()
.load(previewUrl400)
.apply(options)
.placeholder(R.mipmap.im_placeholder)
.fitCenter())
.transition(DrawableTransitionOptions.withCrossFade(500))
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<Drawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target<Drawable> target, @NonNull DataSource dataSource, boolean isFirstResource) {
return false;
}
})
.fitCenter()
.into(vb.imageviewPreview);
}
vb.imageFavorite.setSelected(ObectManager.queryIsLike(imId));
}
private void initClick() {
vb.imageviewBack.setOnClickListener(v -> finish());
vb.buttonSet.setOnClickListener(v -> {
if (dialogType == null) {
dialogType = new Mydialog();
dialogType.setListener(this);
}
if (!dialogType.isAdded()) {
dialogType.show(getSupportFragmentManager(), "");
}
});
vb.imageFavorite.setOnClickListener(v -> {
boolean isSelected = vb.imageFavorite.isSelected();
vb.imageFavorite.setSelected(!isSelected);
data.setLike(!isSelected);
ObectManager.updateLike(data);
});
vb.layoutDownload.setOnClickListener(v -> {
if (JsonData.INSTANCE.requestPermission(this, permissionCode)) {
startSaveToAlbum();
}
});
}
private void startSaveToAlbum() {
showDownloadLoading(true);
if (downloadFile != null && downloadFile.exists()) {
startSave(downloadFile);
return;
}
doDownload(true, true);
}
private void doDownload(boolean showMsg, boolean save) {
call = JsonData.INSTANCE.downloadFile(fullUrl, mSavePath, (aBoolean, inputStream) -> {
File file = new File(mSavePath);
if (aBoolean && file.exists()) {
downloadFile = file;
if (save) {
startSave(downloadFile);
}
} else if (showMsg) {
runOnUiThread(() -> {
showDownloadLoading(false);
Toast.makeText(PreviewActivity.this, getString(R.string.download_fail), Toast.LENGTH_SHORT).show();
});
}
return null;
});
}
private void showDownloadLoading(boolean show) {
vb.pbDownload.setVisibility(show ? View.VISIBLE : View.GONE);
vb.imageDownload.setVisibility(show ? View.GONE : View.VISIBLE);
}
private void showSetWallpaperLoading(boolean show) {
vb.pbSet.setVisibility(show ? View.VISIBLE : View.GONE);
vb.buttonSet.setVisibility(show ? View.GONE : View.VISIBLE);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == permissionCode && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startSaveToAlbum();
}
}
private void startSave(File file) {
ObectManager.insertOrUpdateDownload(data);
Uri uri = JsonData.INSTANCE.saveToGallery(this, file);
runOnUiThread(() -> {
showDownloadLoading(false);
Toast.makeText(this, uri == null ? R.string.save_fail : R.string.save_success,
uri == null ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG).show();
});
}
@Override
public void onSelectType(int type) {
showSetWallpaperLoading(true);
if (downloadFile != null && downloadFile.exists()) {
new Thread(() -> setWallpaper(downloadFile, type)).start();
} else {
call = JsonData.INSTANCE.downloadFile(fullUrl, mSavePath, (aBoolean, inputStream) -> {
File file = new File(mSavePath);
if (aBoolean && file.exists()) {
downloadFile = file;
setWallpaper(downloadFile, type);
} else {
runOnUiThread(() -> {
showSetWallpaperLoading(false);
Toast.makeText(PreviewActivity.this, R.string.set_fail, Toast.LENGTH_SHORT).show();
});
}
return null;
});
}
}
private void setWallpaper(File file, int type) {
try (FileInputStream fis = new FileInputStream(file)) {
switch (type) {
case Mydialog.type_home:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
wallpaperManager.setStream(fis, null, true, WallpaperManager.FLAG_SYSTEM);
} else {
wallpaperManager.setStream(fis);
}
break;
case Mydialog.type_lock:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
wallpaperManager.setStream(fis, null, true, WallpaperManager.FLAG_LOCK);
} else {
wallpaperManager.setStream(fis);
}
break;
case Mydialog.type_both:
wallpaperManager.setStream(fis);
break;
}
if (file.exists()) {
file.delete();
}
runOnUiThread(() -> {
showSetWallpaperLoading(false);
Toast.makeText(this, R.string.set_success, Toast.LENGTH_SHORT).show();
});
} catch (Exception e) {
runOnUiThread(() -> {
showSetWallpaperLoading(false);
Toast.makeText(this, R.string.set_fail, Toast.LENGTH_SHORT).show();
});
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (clockTimer != null) {
clockTimer.cancel();
clockTimer = null;
}
if (mainHandler != null) {
mainHandler.removeCallbacksAndMessages(null);
}
if (call != null) {
call.cancel();
}
if (dialogType != null && dialogType.isAdded()) {
dialogType.dismiss();
}
}
}

View File

@ -0,0 +1,184 @@
package com.snap.wall.activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.snap.wall.R;
import com.snap.wall.databinding.ActivityPrimaryBinding;
import com.snap.wall.fragment.FragmentPrefer;
import com.snap.wall.fragment.FragmentPrimary;
import com.snap.wall.fragment.FragmentSetting;
import com.snap.wall.mytool.Comutils;
import java.util.ArrayList;
import java.util.List;
public class PrimaryActivity extends AppCompatActivity implements View.OnClickListener {
private ActivityPrimaryBinding vb;
private static final int[] TAB_TITLES = {R.string.home_name, R.string.collections, R.string.setting};
private int currentTabPosition = 0;
private static final int HOME_TAB_POSITION = 0;
private TextView tabHome;
private TextView tabLike;
private TextView tabSetting;
private List<TextView> tabList = new ArrayList<>();
private List<Fragment> fragmentList = new ArrayList<>();
// 修复4保存ViewPager2回调对象用于注销
private ViewPager2.OnPageChangeCallback pageChangeCallback;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Comutils.initFull(this, false);
vb = ActivityPrimaryBinding.inflate(getLayoutInflater());
setContentView(vb.getRoot());
initFragments();
initTabViews();
initViewPager2();
initSearchClickListener();
updateTabState(currentTabPosition);
updateTitle(currentTabPosition);
updateSearchVisibility(currentTabPosition);
}
private void initFragments() {
fragmentList.add(FragmentPrimary.newInstance(0)); // 首页保留newInstance需传递参数
fragmentList.add(new FragmentPrefer()); // 直接创建实例
fragmentList.add(new FragmentSetting()); // 直接创建实例
}
private void initTabViews() {
tabHome = findViewById(R.id.tab_home);
tabLike = findViewById(R.id.tab_like);
tabSetting = findViewById(R.id.tab_setting);
tabList.add(tabHome);
tabList.add(tabLike);
tabList.add(tabSetting);
for (int i = 0; i < tabList.size(); i++) {
TextView tab = tabList.get(i);
tab.setText(TAB_TITLES[i]);
tab.setOnClickListener(this);
}
}
private void initViewPager2() {
vb.viewpager2.setAdapter(new FragmentStateAdapter(this) {
@NonNull
@Override
public Fragment createFragment(int position) {
return fragmentList.get(position);
}
@Override
public int getItemCount() {
return fragmentList.size();
}
});
vb.viewpager2.setUserInputEnabled(true);
vb.viewpager2.setOffscreenPageLimit(2);
// 修复4创建并保存回调对象
pageChangeCallback = new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
currentTabPosition = position;
updateTabState(position);
updateTitle(position);
updateSearchVisibility(position);
}
};
vb.viewpager2.registerOnPageChangeCallback(pageChangeCallback);
}
/**
* 优化2修改未选中Tab文字颜色提高可读性
*/
private void updateTabState(int selectedPosition) {
for (int i = 0; i < tabList.size(); i++) {
TextView tab = tabList.get(i);
boolean isSelected = (i == selectedPosition);
if (isSelected) {
tab.setBackgroundResource(R.drawable.tab_selected_bg1);
tab.setTextColor(getResources().getColor(R.color.white));
} else {
tab.setBackgroundResource(R.drawable.bg_purple_round);
tab.setTextColor(getResources().getColor(R.color.sub_title_color));
}
}
}
private void updateTitle(int position) {
if (position < TAB_TITLES.length) {
String title = getString(TAB_TITLES[position]);
vb.textviewWallpaper.setText(title);
}
}
private void updateSearchVisibility(int currentPosition) {
if (currentPosition == HOME_TAB_POSITION) {
vb.imSearch.setVisibility(View.VISIBLE);
} else {
vb.imSearch.setVisibility(View.GONE);
}
}
private void initSearchClickListener() {
vb.imSearch.setOnClickListener(v -> {
Intent intent = new Intent(PrimaryActivity.this, MySearchActivity.class);
startActivity(intent);
});
}
@Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.tab_home) {
currentTabPosition = 0;
vb.viewpager2.setCurrentItem(0, true);
} else if (id == R.id.tab_like) {
currentTabPosition = 1;
vb.viewpager2.setCurrentItem(1, true);
} else if (id == R.id.tab_setting) {
currentTabPosition = 2;
vb.viewpager2.setCurrentItem(2, true);
}
updateTabState(currentTabPosition);
updateTitle(currentTabPosition);
updateSearchVisibility(currentTabPosition);
}
/**
* 修复4注销保存的回调对象避免内存泄漏
*/
@Override
protected void onDestroy() {
super.onDestroy();
vb.viewpager2.unregisterOnPageChangeCallback(pageChangeCallback);
vb = null;
}
public void switchToPreviousFragment() {
if (currentTabPosition > 0) {
currentTabPosition--;
vb.viewpager2.setCurrentItem(currentTabPosition, true);
} else {
// 如需退出App取消注释下面一行
// finish();
}
}
}

View File

@ -0,0 +1,103 @@
package com.snap.wall.activity;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.view.Window;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import com.snap.wall.R;
public class RateDialog extends Dialog {
private ImageView star1, star2, star3, star4, star5;
private int selectedStars = 0;
private String packageName;
public RateDialog(@NonNull Context context) {
// 关键修改1指定透明主题避免系统默认背景干扰
super(context, android.R.style.Theme_Translucent_NoTitleBar);
this.packageName = context.getPackageName();
initView();
}
private void initView() {
setContentView(R.layout.activity_rate_dialog);
Window window = getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
window.getDecorView().setPadding(0, 0, 0, 0);
window.setLayout(
(int) (getContext().getResources().getDisplayMetrics().widthPixels * 0.8),
android.view.WindowManager.LayoutParams.WRAP_CONTENT
);
}
// 可选修改恢复点击外部可关闭弹窗提升交互体验
setCanceledOnTouchOutside(true);
// 保留点击返回键可关闭弹窗默认true可显式声明
setCancelable(true);
// 绑定星级控件
star1 = findViewById(R.id.iv_star1);
star2 = findViewById(R.id.iv_star2);
star3 = findViewById(R.id.iv_star3);
star4 = findViewById(R.id.iv_star4);
star5 = findViewById(R.id.iv_star5);
// 星级点击事件保留原有逻辑
star1.setOnClickListener(v -> setStars(1));
star2.setOnClickListener(v -> setStars(2));
star3.setOnClickListener(v -> setStars(3));
star4.setOnClickListener(v -> setStars(4));
star5.setOnClickListener(v -> setStars(5));
// 取消按钮事件保留原有逻辑
findViewById(R.id.btn_cancel).setOnClickListener(v -> dismiss());
// 关键修改4完善评分按钮的跳转逻辑跳转到应用商店
findViewById(R.id.btn_rate).setOnClickListener(v -> {
if (selectedStars > 0) {
dismiss();
} else {
// 未选择星级时提示用户
Toast.makeText(getContext(), "Please select a star rating first!", Toast.LENGTH_SHORT).show();
}
});
}
// 星级选中逻辑保留原有逻辑无修改
private void setStars(int count) {
selectedStars = count;
// 重置所有星级为未选中
star1.setImageResource(R.drawable.star_unselected);
star2.setImageResource(R.drawable.star_unselected);
star3.setImageResource(R.drawable.star_unselected);
star4.setImageResource(R.drawable.star_unselected);
star5.setImageResource(R.drawable.star_unselected);
// 根据选中数量设置星级为选中
for (int i = 1; i <= count; i++) {
switch (i) {
case 1:
star1.setImageResource(R.drawable.star_selected);
break;
case 2:
star2.setImageResource(R.drawable.star_selected);
break;
case 3:
star3.setImageResource(R.drawable.star_selected);
break;
case 4:
star4.setImageResource(R.drawable.star_selected);
break;
case 5:
star5.setImageResource(R.drawable.star_selected);
break;
}
}
}
}

View File

@ -0,0 +1,62 @@
package com.snap.wall.activity;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentTransaction;
import com.snap.wall.R;
import com.snap.wall.RecentWallpaperManager;
import com.snap.wall.fragment.RecentWallpaperFragment;
import com.snap.wall.mytool.Comutils;
public class RencentActivity extends AppCompatActivity {
private RecentWallpaperManager recentManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rencent);
Comutils.initFull(this, false);
recentManager = RecentWallpaperManager.getInstance(this);
ImageView ivBack = findViewById(R.id.iv_back);
if (ivBack != null) {
ivBack.setOnClickListener(v -> {
finish();
});
}
// 清除按钮点击
TextView tvClearAll = findViewById(R.id.tv_clear_all);
tvClearAll.setOnClickListener(v -> {
recentManager.clear();
Toast.makeText(this, "All recent browsing history has been cleared", Toast.LENGTH_SHORT).show();
reloadRecentFragment();
});
// 加载Fragment
if (savedInstanceState == null) {
loadRecentFragment();
}
}
private void loadRecentFragment() {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, new RecentWallpaperFragment());
transaction.commit();
}
private void reloadRecentFragment() {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, new RecentWallpaperFragment());
transaction.commit();
}
@Override
protected void onDestroy() {
super.onDestroy();
// 仅保留super调用删除所有Glide相关代码
}
}

View File

@ -0,0 +1,64 @@
package com.snap.wall.activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import com.snap.wall.adapter.OnItemclick;
import com.snap.wall.databinding.ActivityTabBinding;
import com.snap.wall.bean.Information;
import com.snap.wall.myitem.ItemTab;
import com.snap.wall.mytool.Comutils;
import com.snap.wall.mytool.Itemhelper;
import com.snap.wall.mytool.ObectManager;
import java.util.List;
public class TabActivity extends AppCompatActivity implements OnItemclick {
private ActivityTabBinding vb;
private String categoryName;
public static final String key_index = "index";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
vb = ActivityTabBinding.inflate(getLayoutInflater());
setContentView(vb.getRoot());
Comutils.initFull(this, false);
categoryName = getIntent().getStringExtra(key_index);
vb.name.setText(categoryName);
initList();
vb.imageviewBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
private void initList() {
List<Information> data = ObectManager.queryCategoryAll(categoryName);
Itemhelper itemHelper = new Itemhelper(10, 10, 0);
// StaggeredGridLayoutManager gridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);
vb.list.addItemDecoration(itemHelper);
vb.list.setLayoutManager(gridLayoutManager);
int height = Comutils.dp2Px(180);
ItemTab itemList = new ItemTab(this, height,false);
itemList.setDataInfo(data);
itemList.setInfoWallpaperListener(this);
vb.list.setAdapter(itemList);
}
@Override
public void onItemClickAction(Information info) {
Intent intent = new Intent(this, PreviewActivity.class);
intent.putExtra(Comutils.key_info, info);
startActivity(intent);
}
}

View File

@ -0,0 +1,10 @@
package com.snap.wall.adapter;
import com.snap.wall.bean.Information;
public interface OnItemclick {
void onItemClickAction(Information info);
default void onClickMore(String name){}
}

View File

@ -0,0 +1,9 @@
package com.snap.wall.adapter;
import com.snap.wall.bean.Information;
import java.util.List;
public interface OnLikelist {
void onLikeList(List<Information> dataList);
}

View File

@ -0,0 +1,6 @@
package com.snap.wall.adapter;
public interface OnSelecttype {
void onSelectType(int type);
}

View File

@ -0,0 +1,8 @@
package com.snap.wall.adapter;
import com.snap.wall.bean.Information;
public interface OnUpdatelike {
void onAdd(Information data);
void onRemove(Information data);
}

View File

@ -0,0 +1,150 @@
package com.snap.wall.bean;
import androidx.annotation.Nullable;
import java.io.Serializable;
import io.objectbox.annotation.Entity;
import io.objectbox.annotation.Id;
@Entity
public class Information implements Serializable {
@Id
private long id;
private String categoryName;
private String imId;
private String description;
private String fullUrl;
private String previewUrl1080;
private String previewUrl400;
private String previewUrl200;
private String authorName;
private String authorHeader;
private String authorHtml;
private boolean isLike;
private boolean isDownload;
public boolean isLike() {
return isLike;
}
public void setLike(boolean like) {
isLike = like;
}
public boolean isDownload() {
return isDownload;
}
public void setDownload(boolean download) {
isDownload = download;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getImId() {
return imId;
}
public void setImId(String imId) {
this.imId = imId;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getFullUrl() {
return fullUrl;
}
public void setFullUrl(String fullUrl) {
this.fullUrl = fullUrl;
}
public String getPreviewUrl1080() {
return previewUrl1080;
}
public void setPreviewUrl1080(String previewUrl1080) {
this.previewUrl1080 = previewUrl1080;
}
public String getPreviewUrl400() {
return previewUrl400;
}
public void setPreviewUrl400(String previewUrl400) {
this.previewUrl400 = previewUrl400;
}
public String getPreviewUrl200() {
return previewUrl200;
}
public void setPreviewUrl200(String previewUrl200) {
this.previewUrl200 = previewUrl200;
}
public String getAuthorName() {
return authorName;
}
public void setAuthorName(String authorName) {
this.authorName = authorName;
}
public String getAuthorHeader() {
return authorHeader;
}
public void setAuthorHeader(String authorHeader) {
this.authorHeader = authorHeader;
}
public String getAuthorHtml() {
return authorHtml;
}
public void setAuthorHtml(String authorHtml) {
this.authorHtml = authorHtml;
}
@Override
public boolean equals(@Nullable Object obj) {
if (obj instanceof Information) {
Information obj1 = (Information) obj;
return obj1.getImId() != null && obj1.getImId().equals(imId);
}
return false;
}
}

View File

@ -0,0 +1,124 @@
package com.snap.wall.fragment;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import com.snap.wall.App;
import com.snap.wall.databinding.FragmentPreferBinding;
import com.snap.wall.activity.PreviewActivity;
import com.snap.wall.adapter.OnItemclick;
import com.snap.wall.adapter.OnLikelist;
import com.snap.wall.bean.Information;
import com.snap.wall.myitem.ItemPrefer;
import com.snap.wall.mytool.Comutils;
import com.snap.wall.mytool.Itemhelper;
import com.snap.wall.mytool.ObectManager;
import com.snap.wall.R;
import java.util.List;
import java.util.WeakHashMap;
import io.objectbox.reactive.DataSubscription;
public class FragmentPrefer extends Fragment implements OnItemclick {
private FragmentPreferBinding vb;
private DataSubscription dataSubscription;
private ItemPrefer itemLike;
private static class LikeListListener implements OnLikelist {
private final WeakHashMap<FragmentPrefer, Object> fragmentRef;
public LikeListListener(FragmentPrefer fragment) {
fragmentRef = new WeakHashMap<>();
fragmentRef.put(fragment, null);
}
@Override
public void onLikeList(List<Information> dataList) {
FragmentPrefer fragment = fragmentRef.keySet().iterator().next();
if (fragment == null || fragment.isDetached() || fragment.getView() == null) {
return;
}
Log.d(App.TAG, "收藏列表数据量: " + (dataList == null ? 0 : dataList.size()));
fragment.updateListUi(dataList);
}
}
public FragmentPrefer() {
}
public static FragmentPrefer newInstance() {
return new FragmentPrefer();
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
vb = FragmentPreferBinding.inflate(inflater, container, false);
initList();
return vb.getRoot();
}
private void initList() {
if (!isAdded() || getContext() == null) {
return;
}
itemLike = new ItemPrefer(getContext());
itemLike.setInfoWallpaperListener(this);
int spanCount = 2;
GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), spanCount);
vb.listRecycler.setLayoutManager(gridLayoutManager);
vb.listRecycler.addItemDecoration(new Itemhelper(10, 10, 15));
vb.listRecycler.setAdapter(itemLike);
LikeListListener listener = new LikeListListener(this);
dataSubscription = ObectManager.setLikeDataListener(listener);
}
private void updateListUi(List<Information> dataList) {
if (dataList == null || dataList.isEmpty()) {
vb.layoutNoData.setVisibility(View.VISIBLE);
vb.listRecycler.setVisibility(View.GONE);
vb.tvTitle.setText(getString(R.string.no_like_data));
} else {
vb.layoutNoData.setVisibility(View.GONE);
vb.listRecycler.setVisibility(View.VISIBLE);
vb.tvTitle.setText("");
itemLike.setDataInfo(dataList);
}
}
@Override
public void onItemClickAction(Information info) {
if (info == null || !isAdded() || getContext() == null) {
return;
}
Intent intent = new Intent(getContext(), PreviewActivity.class);
intent.putExtra(Comutils.key_info, info);
startActivity(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
if (dataSubscription != null) {
dataSubscription.cancel();
dataSubscription = null;
}
Log.d(App.TAG, "FragmentFavorite onDestroy: 订阅已取消");
}
@Override
public void onDestroyView() {
super.onDestroyView();
vb = null;
}
}

View File

@ -0,0 +1,167 @@
package com.snap.wall.fragment;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.graphics.Rect;
import android.util.Log;
import android.widget.ProgressBar;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.snap.wall.App;
import com.snap.wall.R;
import com.snap.wall.databinding.FragmentPrimaryBinding;
import com.snap.wall.activity.TabActivity;
import com.snap.wall.adapter.OnItemclick;
import com.snap.wall.bean.Information;
import com.snap.wall.myitem.ItemPrimary;
import com.snap.wall.mytool.Comutils;
import java.util.ArrayList;
import java.util.List;
public class FragmentPrimary extends Fragment implements OnItemclick {
private FragmentPrimaryBinding vb; // 与布局文件 fragment_main.xml 绑定
private ItemPrimary categoryAdapter; // RecyclerView 适配器
private ProgressBar loadingPb; // 加载进度条布局中 id=loading_pb
private RecyclerView classRecycler; // 分类列表 RecyclerView布局中 id=class_recycler
private static final String TAG = "FragmentMain_Debug";
public static FragmentPrimary newInstance(int type) {
FragmentPrimary fragment = new FragmentPrimary();
Bundle bundle = new Bundle();
bundle.putInt(Comutils.key_index, type);
fragment.setArguments(bundle);
return fragment;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.d(TAG, "onCreateView创建视图");
vb = FragmentPrimaryBinding.inflate(inflater, container, false);
loadingPb = vb.getRoot().findViewById(R.id.loading_pb);
classRecycler = vb.getRoot().findViewById(R.id.class_recycler);
return vb.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Log.d(TAG, "onViewCreated初始化分类数据");
initCategoryData();
}
private void initCategoryData() {
// 显示加载进度条
if (loadingPb != null) {
loadingPb.setVisibility(View.VISIBLE);
}
// MyApp 获取全局分类列表
List<String> categoryNames = App.getCategoryNames();
Log.d(TAG, "从 MyApp 获取分类:" + categoryNames);
if (categoryNames == null || categoryNames.isEmpty()) {
categoryNames = new ArrayList<>();
categoryNames.add("Featured");
categoryNames.add("Animals");
categoryNames.add("Experimental");
categoryNames.add("Film");
categoryNames.add("Nature");
categoryNames.add("Patterns");
categoryNames.add("Street");
categoryNames.add("Travel");
Log.d(TAG, "使用兜底分类:" + categoryNames);
}
if (loadingPb != null) {
loadingPb.setVisibility(View.GONE);
}
initRecyclerView(categoryNames);
}
private void initRecyclerView(List<String> categoryNames) {
Context context = getContext();
if (context == null || classRecycler == null) {
Log.e(TAG, "context 为空或 RecyclerView 未绑定");
return;
}
classRecycler.setLayoutManager(new GridLayoutManager(context, 2));
int recyclerPadding = dpToPx(context, 8);
classRecycler.setPadding(recyclerPadding, recyclerPadding, recyclerPadding, recyclerPadding);
classRecycler.setClipToPadding(false);
int spacing = dpToPx(context, 5);
classRecycler.addItemDecoration(new GridSpacingItemDecoration(2, spacing, true));
classRecycler.setOverScrollMode(View.OVER_SCROLL_NEVER);
categoryAdapter = new ItemPrimary();
categoryAdapter.setData(categoryNames);
categoryAdapter.setInfoWallpaperListener(this);
classRecycler.setAdapter(categoryAdapter);
Log.d(TAG, "RecyclerView 初始化完成:内边距=" + recyclerPadding + "pxItem间距=" + spacing + "pxItem数量=" + categoryNames.size());
}
private int dpToPx(Context context, float dpValue) {
return (int) (dpValue * context.getResources().getDisplayMetrics().density + 0.5f);
}
@Override
public void onItemClickAction(Information info) {
Context context = getContext();
if (context != null && info != null && info.getCategoryName() != null) {
Log.d(TAG, "点击分类:" + info.getCategoryName());
Intent intent = new Intent(context, TabActivity.class);
intent.putExtra(TabActivity.key_index, info.getCategoryName());
startActivity(intent);
}
}
public static class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
private int spanCount; // 列数
private int spacing;
private boolean includeEdge; // 是否包含边缘间距
public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
this.spanCount = spanCount;
this.spacing = spacing;
this.includeEdge = includeEdge;
}
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
if (position == RecyclerView.NO_POSITION) return;
int column = position % spanCount;
if (includeEdge) {
outRect.left = spacing - column * spacing / spanCount;
outRect.right = (column + 1) * spacing / spanCount;
} else {
outRect.left = column * spacing / spanCount;
outRect.right = spacing - (column + 1) * spacing / spanCount;
}
if (position < spanCount && includeEdge) {
outRect.top = spacing;
}
outRect.bottom = spacing;
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (classRecycler != null) {
classRecycler.setAdapter(null);
classRecycler.setLayoutManager(null);
}
vb = null;
loadingPb = null;
classRecycler = null;
categoryAdapter = null;
}
}

View File

@ -0,0 +1,81 @@
package com.snap.wall.fragment;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.snap.wall.activity.RateDialog;
import com.snap.wall.databinding.FragmentSettingBinding;
public class FragmentSetting extends Fragment {
private FragmentSettingBinding vb;
public static FragmentSetting newInstance() {
return new FragmentSetting();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
vb = FragmentSettingBinding.inflate(inflater, container, false);
initEdgeToEdge();
initVersionName();
initClickListeners();
return vb.getRoot();
}
private void initVersionName() {
try {
PackageInfo packageInfo = requireContext().getPackageManager()
.getPackageInfo(requireContext().getPackageName(), 0);
vb.tvVersion.setText("v" + packageInfo.versionName);
} catch (PackageManager.NameNotFoundException e) {
vb.tvVersion.setText("v1.0.0");
}
}
private void initEdgeToEdge() {
if (getActivity() != null) {
ViewCompat.setOnApplyWindowInsetsListener(vb.main, (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
}
}
private void initClickListeners() {
// 评分按钮点击事件
vb.tvRateUs.setOnClickListener(v -> {
if (getActivity() != null) {
new RateDialog(getActivity()).show();
}
});
vb.llRateUs.setOnClickListener(v -> {
if (getActivity() != null) {
new RateDialog(getActivity()).show();
}
});
}
@Override
public void onDestroyView() {
super.onDestroyView();
vb = null;
}
}

View File

@ -0,0 +1,89 @@
package com.snap.wall.fragment;
import android.app.Dialog;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import com.snap.wall.adapter.OnSelecttype;
import com.snap.wall.databinding.MyDialogBinding;
public class Mydialog extends DialogFragment {
private MyDialogBinding vb;
private OnSelecttype listener;
public static final int type_home =0;
public static final int type_lock =1;
public static final int type_both =2;
public void setListener(OnSelecttype listener) {
this.listener = listener;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
vb = MyDialogBinding.inflate(getLayoutInflater());
init();
return vb.getRoot();
}
@Override
public void onStart() {
super.onStart();
Dialog dialog = getDialog();
if (dialog != null) {
dialog.setCanceledOnTouchOutside(true);
Window window = dialog.getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
}
}
}
private void init(){
vb.layoutHome.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(listener!= null){
listener.onSelectType(type_home);
dismiss();
}
}
});
vb.layoutLock.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(listener!= null){
listener.onSelectType(type_lock);
dismiss();
}
}
});
vb.layoutBoth.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(listener!= null){
listener.onSelectType(type_both);
dismiss();
}
}
});
}
}

View File

@ -0,0 +1,106 @@
package com.snap.wall.fragment;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.GridView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;
import com.snap.wall.R;
import com.snap.wall.RecentWallpaperManager;
import com.snap.wall.RecentWallpaperAdapter;
import com.snap.wall.Wallpaper;
import com.snap.wall.activity.PreviewActivity;
import com.snap.wall.bean.Information;
import java.util.List;
public class RecentWallpaperFragment extends Fragment {
private GridView gvRecent;
private TextView tvEmpty;
private RequestManager glideRequestManager;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_recent_wallpaper, container, false);
gvRecent = view.findViewById(R.id.gv_recent_wallpapers);
tvEmpty = view.findViewById(R.id.tv_empty);
glideRequestManager = Glide.with(this);
if (gvRecent == null) {
TextView errorTv = new TextView(requireContext());
errorTv.setText("Failed to load control");
errorTv.setTextSize(16);
errorTv.setPadding(20, 20, 20, 20);
return errorTv;
}
loadRecentWallpapers();
return view;
}
private void loadRecentWallpapers() {
// 核心校验Fragment是否已销毁
if (isDetached() || requireContext() == null || gvRecent == null) return;
List<Wallpaper> wallpaperList = RecentWallpaperManager.getInstance(requireContext()).getRecentWallpapers();
if (wallpaperList.isEmpty()) {
gvRecent.setVisibility(View.GONE);
if (tvEmpty != null) {
tvEmpty.setVisibility(View.VISIBLE);
tvEmpty.setText("No recent browsing history");
}
return;
}
gvRecent.setVisibility(View.VISIBLE);
if (tvEmpty != null) tvEmpty.setVisibility(View.GONE);
// 初始化适配器传递Glide请求管理器
RecentWallpaperAdapter adapter = new RecentWallpaperAdapter(requireContext(), wallpaperList, glideRequestManager, wallpaper -> {
// 跳转前校验Fragment状态
if (!isDetached()) {
gotoDetailPage(wallpaper);
}
});
gvRecent.setAdapter(adapter);
gvRecent.setClickable(false);
gvRecent.setFocusable(false);
}
// 跳转到详情页
private void gotoDetailPage(Wallpaper wallpaper) {
Information data = new Information();
data.setImId(wallpaper.getId());
data.setFullUrl(wallpaper.getImageUrl());
data.setDescription(wallpaper.getTitle());
data.setPreviewUrl1080(wallpaper.getImageUrl());
Intent intent = new Intent(requireContext(), PreviewActivity.class);
intent.putExtra("key_info", data);
startActivity(intent);
}
// Fragment销毁时清理Glide请求修正方法名错误
@Override
public void onDestroyView() {
super.onDestroyView();
if (glideRequestManager != null) {
// 正确的Glide请求清理方法
glideRequestManager.pauseRequests(); // 暂停所有请求
glideRequestManager.clear(gvRecent); // 清除GridView中所有图片请求
}
gvRecent = null;
tvEmpty = null;
glideRequestManager = null;
}
}

View File

@ -0,0 +1,164 @@
package com.snap.wall.myitem;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
import com.snap.wall.R;
import com.snap.wall.App;
import com.snap.wall.bean.Information;
import com.snap.wall.databinding.ItemHomeBinding;
import com.snap.wall.adapter.OnItemclick;
import com.snap.wall.mytool.Comutils;
import com.snap.wall.mytool.JsonData;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ItemHome extends RecyclerView.Adapter<ItemHome.MainViewHolder> {
private List<String> categoryNames = new ArrayList<>();
private OnItemclick listener;
// 缓存每个分类的第一条数据避免重复解析JSON
private final List<Information> categoryFirstDataCache = new ArrayList<>();
private RequestOptions imageOptions; // 延迟初始化需Context
private void initImageOptions(Context context) {
if (imageOptions == null) {
int cornerDp = 12;
// 动态将dp转为px适配不同屏幕密度
int cornerPx = (int) (cornerDp * context.getResources().getDisplayMetrics().density + 0.5f);
imageOptions = new RequestOptions()
.transform(new CenterCrop(), new RoundedCorners(cornerPx)) // 用px值保证适配
.placeholder(R.mipmap.im_placeholder) // 加载中占位图
.error(R.mipmap.im_placeholder); // 加载失败占位图
}
}
/**
* 设置分类列表仅英文名称
*/
public void setData(List<String> categoryNames) {
if (categoryNames != null) {
this.categoryNames.clear();
this.categoryNames.addAll(categoryNames);
// 初始化缓存按分类顺序解析JSON
initCategoryFirstDataCache();
notifyDataSetChanged();
}
}
/**
* 初始化缓存解析每个分类的JSON获取第一条数据
* 逻辑与 MyApp 一致避免依赖 ObectBox
*/
private void initCategoryFirstDataCache() {
categoryFirstDataCache.clear();
Context context = App.mAppContext;
if (context == null) return;
// 初始化Glide图片配置首次调用时初始化
initImageOptions(context);
for (String categoryName : categoryNames) {
Information firstData = null;
try {
// 拼接JSON文件名 MyApp 一致分类名.json
String jsonFileName = categoryName + ".json";
// 读取assets中的JSON文件
InputStream open = context.getAssets().open(jsonFileName);
String jsonStr = Comutils.getCovertStr(open);
if (!jsonStr.isEmpty()) {
// 解析JSON获取数据复用 JsonData 工具类
List<Information> data = JsonData.INSTANCE.getData(jsonStr, categoryName);
if (!data.isEmpty()) {
Collections.shuffle(data); // 打乱顺序 MyApp 一致
firstData = data.get(0); // 取第一条
}
}
} catch (IOException e) {
// JSON文件不存在或读取失败时用占位图
firstData = null;
}
categoryFirstDataCache.add(firstData);
}
}
public void setInfoWallpaperListener(OnItemclick listener) {
this.listener = listener;
}
@NonNull
@Override
public MainViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// ViewBinding 加载 Item 布局
ItemHomeBinding binding = ItemHomeBinding.inflate(
LayoutInflater.from(parent.getContext()),
parent,
false
);
// 初始化图片配置防止App.mAppContext为空时未初始化
initImageOptions(parent.getContext());
return new MainViewHolder(binding);
}
@Override
public void onBindViewHolder(@NonNull MainViewHolder holder, int position) {
if (position >= categoryNames.size() || position >= categoryFirstDataCache.size()) {
return;
}
String categoryName = categoryNames.get(position);
Information firstData = categoryFirstDataCache.get(position);
Context context = holder.binding.getRoot().getContext();
holder.binding.tvCategoryName.setText(categoryName);
if (firstData != null) {
String imageUrl = firstData.getPreviewUrl400();
if (imageUrl != null && !imageUrl.isEmpty()) {
Glide.with(context)
.load(imageUrl)
.apply(imageOptions)
.into(holder.binding.ivCategory);
} else {
holder.binding.ivCategory.setImageResource(R.mipmap.im_placeholder);
}
} else {
holder.binding.ivCategory.setImageResource(R.mipmap.im_placeholder);
}
holder.binding.getRoot().setOnClickListener(v -> {
if (listener != null) {
Information myData = new Information();
myData.setCategoryName(categoryName);
myData.setImId(categoryName + "_" + position);
if (firstData != null) {
myData.setPreviewUrl400(firstData.getPreviewUrl400());
}
listener.onItemClickAction(myData);
}
});
}
@Override
public int getItemCount() {
return categoryNames.size();
}
static class MainViewHolder extends RecyclerView.ViewHolder {
ItemHomeBinding binding;
public MainViewHolder(@NonNull ItemHomeBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
}
}

View File

@ -0,0 +1,177 @@
package com.snap.wall.myitem;
import android.content.Context;
import android.graphics.Bitmap;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.MultiTransformation;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.snap.wall.App;
import com.snap.wall.adapter.OnItemclick;
import com.snap.wall.bean.Information;
import com.snap.wall.mytool.Comutils;
import com.snap.wall.mytool.ObectManager;
import com.snap.wall.R;
import java.util.ArrayList;
import java.util.List;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
public class ItemPrefer extends RecyclerView.Adapter<ItemPrefer.LikeVh> {
// 全局复用的图片变换对象圆角+居中裁剪
private static final MultiTransformation<Bitmap> TRANSFORMATION = new MultiTransformation<>(
new CenterCrop(),
new RoundedCornersTransformation(Comutils.dp2Px(12), 0)
);
private List<Information> mWallpaperList = new ArrayList<>();
private Context mContext;
private OnItemclick mOnItemClick;
private int mItemWidth; // 新增保存Item的1:1宽度
public void setInfoWallpaperListener(OnItemclick onItemClick) {
this.mOnItemClick = onItemClick;
}
public ItemPrefer(Context context) {
mContext = context;
setHasStableIds(true); // 开启稳定ID避免滑动闪烁
// 初始化Item宽度屏幕宽度/2 - 间距适配2列GridLayout
initItemWidth();
}
// 新增计算1:1的Item宽度核心
private void initItemWidth() {
if (mContext == null) return;
WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(dm);
int screenWidth = dm.widthPixels;
// 减去RecyclerView的ItemDecoration间距15dp左右根据你的实际间距调整
int spacing = Comutils.dp2Px(30); // 左右各15dp适配Itemhelper(10,10,15)
mItemWidth = (screenWidth - spacing) / 2; // 2列平分保证1:1
}
public void setDataInfo(List<Information> dataInfo) {
if (dataInfo != null) {
this.mWallpaperList.clear();
this.mWallpaperList.addAll(dataInfo);
notifyDataSetChanged();
}
}
@NonNull
@Override
public LikeVh onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(mContext).inflate(R.layout.item_prefer, parent, false);
return new LikeVh(itemView);
}
@Override
public void onBindViewHolder(@NonNull LikeVh holder, int position) {
if (position < 0 || position >= mWallpaperList.size()) {
return;
}
Information info = mWallpaperList.get(position);
// 处理底部间距View
if (holder.spaceView != null) {
holder.spaceView.setVisibility(position == mWallpaperList.size() - 1 ? View.VISIBLE : View.GONE);
}
// 核心修改强制设置Item布局为1:1正方形
if (holder.layout != null && mItemWidth > 0) {
ViewGroup.LayoutParams params = holder.layout.getLayoutParams();
params.width = mItemWidth;
params.height = mItemWidth; // 高度=宽度实现1:1
holder.layout.setLayoutParams(params);
}
// 初始化收藏按钮状态读取真实数据状态
if (holder.ivFavorite != null) {
holder.ivFavorite.setSelected(info.isLike());
holder.ivFavorite.setOnClickListener(v -> {
boolean newState = !holder.ivFavorite.isSelected();
holder.ivFavorite.setSelected(newState);
info.setLike(newState);
ObectManager.updateLike(info);
int adapterPosition = holder.getAdapterPosition();
if (adapterPosition != RecyclerView.NO_POSITION) {
mWallpaperList.remove(adapterPosition);
notifyItemRemoved(adapterPosition);
// 计算需要更新的item数量避免索引越界
int newSize = mWallpaperList.size();
if (adapterPosition < newSize) {
notifyItemRangeChanged(adapterPosition, newSize - adapterPosition);
}
Log.d(App.TAG, "----------notifyItemRemoved-adapterPosition=" + adapterPosition);
}
});
}
// 加载图片处理空URL + 避免内存泄漏 + 圆角1:1
String imgUrl = info.getPreviewUrl400();
if (imgUrl == null || imgUrl.isEmpty()) {
holder.ivWallpaper.setImageResource(R.mipmap.im_placeholder);
} else {
Glide.with(holder.ivWallpaper) // 使用View上下文绑定生命周期
.load(imgUrl)
.placeholder(R.mipmap.im_placeholder)
.error(R.mipmap.im_placeholder)
.transform(TRANSFORMATION) // 圆角+居中裁剪适配1:1
.dontAnimate() // 关闭动画避免滑动闪烁
.into(holder.ivWallpaper);
}
// 整个Item的点击事件
if (holder.layout != null) {
holder.layout.setOnClickListener(v -> {
if (mOnItemClick != null) {
mOnItemClick.onItemClickAction(info);
}
});
}
}
@Override
public int getItemCount() {
return mWallpaperList.size();
}
// 重写getItemId提供稳定ID
@Override
public long getItemId(int position) {
// 替换为Information的唯一标识字段比如id
return mWallpaperList.get(position).getId();
}
public class LikeVh extends RecyclerView.ViewHolder {
ImageView ivWallpaper;
RelativeLayout layout;
ImageView ivFavorite;
View spaceView;
public LikeVh(@NonNull View itemView) {
super(itemView);
ivWallpaper = itemView.findViewById(R.id.wallpaper);
layout = itemView.findViewById(R.id.layout);
ivFavorite = itemView.findViewById(R.id.image_favorite);
spaceView = itemView.findViewById(R.id.space_view);
}
}
}

View File

@ -0,0 +1,164 @@
package com.snap.wall.myitem;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
import com.snap.wall.R;
import com.snap.wall.App;
import com.snap.wall.adapter.OnItemclick;
import com.snap.wall.databinding.ItemPrimaryBinding;
import com.snap.wall.bean.Information;
import com.snap.wall.mytool.Comutils;
import com.snap.wall.mytool.JsonData;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ItemPrimary extends RecyclerView.Adapter<ItemPrimary.MainViewHolder> {
private List<String> categoryNames = new ArrayList<>();
private OnItemclick listener;
// 缓存每个分类的第一条数据避免重复解析JSON
private final List<Information> categoryFirstDataCache = new ArrayList<>();
private RequestOptions imageOptions; // 延迟初始化需Context
private void initImageOptions(Context context) {
if (imageOptions == null) {
int cornerDp = 12;
// 动态将dp转为px适配不同屏幕密度
int cornerPx = (int) (cornerDp * context.getResources().getDisplayMetrics().density + 0.5f);
imageOptions = new RequestOptions()
.transform(new CenterCrop(), new RoundedCorners(cornerPx)) // 用px值保证适配
.placeholder(R.mipmap.im_placeholder) // 加载中占位图
.error(R.mipmap.im_placeholder); // 加载失败占位图
}
}
/**
* 设置分类列表仅英文名称
*/
public void setData(List<String> categoryNames) {
if (categoryNames != null) {
this.categoryNames.clear();
this.categoryNames.addAll(categoryNames);
// 初始化缓存按分类顺序解析JSON
initCategoryFirstDataCache();
notifyDataSetChanged();
}
}
/**
* 初始化缓存解析每个分类的JSON获取第一条数据
* 逻辑与 MyApp 一致避免依赖 ObectBox
*/
private void initCategoryFirstDataCache() {
categoryFirstDataCache.clear();
Context context = App.mAppContext;
if (context == null) return;
// 初始化Glide图片配置首次调用时初始化
initImageOptions(context);
for (String categoryName : categoryNames) {
Information firstData = null;
try {
// 拼接JSON文件名 MyApp 一致分类名.json
String jsonFileName = categoryName + ".json";
// 读取assets中的JSON文件
InputStream open = context.getAssets().open(jsonFileName);
String jsonStr = Comutils.getCovertStr(open);
if (!jsonStr.isEmpty()) {
// 解析JSON获取数据复用 JsonData 工具类
List<Information> data = JsonData.INSTANCE.getData(jsonStr, categoryName);
if (!data.isEmpty()) {
Collections.shuffle(data); // 打乱顺序 MyApp 一致
firstData = data.get(0); // 取第一条
}
}
} catch (IOException e) {
// JSON文件不存在或读取失败时用占位图
firstData = null;
}
categoryFirstDataCache.add(firstData);
}
}
public void setInfoWallpaperListener(OnItemclick listener) {
this.listener = listener;
}
@NonNull
@Override
public MainViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// ViewBinding 加载 Item 布局
ItemPrimaryBinding binding = ItemPrimaryBinding.inflate(
LayoutInflater.from(parent.getContext()),
parent,
false
);
// 初始化图片配置防止App.mAppContext为空时未初始化
initImageOptions(parent.getContext());
return new MainViewHolder(binding);
}
@Override
public void onBindViewHolder(@NonNull MainViewHolder holder, int position) {
if (position >= categoryNames.size() || position >= categoryFirstDataCache.size()) {
return;
}
String categoryName = categoryNames.get(position);
Information firstData = categoryFirstDataCache.get(position);
Context context = holder.binding.getRoot().getContext();
holder.binding.tvCategoryName.setText(categoryName);
if (firstData != null) {
String imageUrl = firstData.getPreviewUrl400();
if (imageUrl != null && !imageUrl.isEmpty()) {
Glide.with(context)
.load(imageUrl)
.apply(imageOptions)
.into(holder.binding.ivCategory);
} else {
holder.binding.ivCategory.setImageResource(R.mipmap.im_placeholder);
}
} else {
holder.binding.ivCategory.setImageResource(R.mipmap.im_placeholder);
}
holder.binding.getRoot().setOnClickListener(v -> {
if (listener != null) {
Information myData = new Information();
myData.setCategoryName(categoryName);
myData.setImId(categoryName + "_" + position);
if (firstData != null) {
myData.setPreviewUrl400(firstData.getPreviewUrl400());
}
listener.onItemClickAction(myData);
}
});
}
@Override
public int getItemCount() {
return categoryNames.size();
}
static class MainViewHolder extends RecyclerView.ViewHolder {
ItemPrimaryBinding binding;
public MainViewHolder(@NonNull ItemPrimaryBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
}
}

View File

@ -0,0 +1,229 @@
package com.snap.wall.myitem;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.DecodeFormat;
import com.bumptech.glide.load.MultiTransformation;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
import com.snap.wall.adapter.OnItemclick;
import com.snap.wall.bean.Information;
import com.snap.wall.mytool.Comutils;
import com.snap.wall.R;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
public class ItemTab extends RecyclerView.Adapter<ItemTab.MyViewHolder> {
private List<Information> dataInfo = new ArrayList<>();
private OnItemclick onItemClick;
private WeakReference<Context> weakReference;
private int itemHeight;
private boolean showSpace = false;
public void setInfoWallpaperListener(OnItemclick onItemClick) {
this.onItemClick = onItemClick;
}
public ItemTab(Context myCon, int itemHeight, boolean show) {
weakReference = new WeakReference<>(myCon);
this.itemHeight = itemHeight;
showSpace = show;
}
public void setDataInfo(List<Information> dataInfo) {
this.dataInfo = dataInfo;
notifyDataSetChanged();
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Context context = weakReference.get();
if (context != null) {
View itemView = LayoutInflater.from(context).inflate(R.layout.item_tab, parent, false);
ImageView imageView = itemView.findViewById(R.id.wallpaper);
ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams();
layoutParams.height = itemHeight;
imageView.setLayoutParams(layoutParams);
return new MyViewHolder(itemView);
}
return null;
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
Information info = dataInfo.get(position);
ImageView imageView = holder.getImageView();
String previewUrl400 = info.getPreviewUrl400();
String previewUrl200 = info.getPreviewUrl200();
RelativeLayout item = holder.getLayout();
String imId = info.getImId();
int curheight;
View spaceView = holder.getSpaceView();
if (showSpace && position == dataInfo.size() - 1) {
spaceView.setVisibility(View.VISIBLE);
} else {
spaceView.setVisibility(View.GONE);
}
MultiTransformation<Bitmap> multiTransformation = new MultiTransformation<>(
new CenterCrop(),
new RoundedCornersTransformation(Comutils.dp2Px(12), 0) // 圆角效果
);
RequestOptions options = new RequestOptions()
.format(DecodeFormat.PREFER_RGB_565);
Context context = weakReference.get();
if (context != null) {
Glide.with(context)
.asDrawable()
.skipMemoryCache(true)
.apply(options)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.load(previewUrl400)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<Drawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target<Drawable> target, @NonNull DataSource dataSource, boolean isFirstResource) {
return false;
}
})
.placeholder(R.mipmap.im_placeholder)
.transform(multiTransformation)
.into(imageView);
}
item.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onItemClick != null) {
onItemClick.onItemClickAction(info);
}
}
});
}
@Override
public int getItemCount() {
return dataInfo.size();
}
@Override
public void onViewRecycled(@NonNull MyViewHolder holder) {
super.onViewRecycled(holder);
}
private static DiffUtil.ItemCallback<Information> diff = new DiffUtil.ItemCallback<Information>() {
@Override
public boolean areItemsTheSame(@NonNull Information oldItem, @NonNull Information newItem) {
return oldItem.getImId().equals(newItem.getImId());
}
@Override
public boolean areContentsTheSame(@NonNull Information oldItem, @NonNull Information newItem) {
return oldItem.getImId().equals(newItem.getImId());
}
};
private static class MyCallback extends DiffUtil.Callback {
private List<Information> mOldList;
private List<Information> mNewList;
public MyCallback(List<Information> oldList, List<Information> newList) {
mOldList = oldList;
mNewList = newList;
}
@Override
public int getOldListSize() {
return mOldList.size();
}
@Override
public int getNewListSize() {
return mNewList.size();
}
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return mOldList.get(oldItemPosition).getImId().equals(mNewList.get(newItemPosition).getImId());
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return mOldList.get(oldItemPosition).getImId().equals(mNewList.get(newItemPosition).getImId());
}
}
static class MyViewHolder extends RecyclerView.ViewHolder {
private ImageView imageView;
private RelativeLayout layout;
private View spaceView;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.wallpaper);
layout = itemView.findViewById(R.id.layout);
spaceView = itemView.findViewById(R.id.space_view);
}
// public ImageView getImFavorite() {
// return imFavorite;
// }
public RelativeLayout getLayout() {
return layout;
}
public ImageView getImageView() {
return imageView;
}
public View getSpaceView() {
return spaceView;
}
}
}

View File

@ -0,0 +1,229 @@
package com.snap.wall.myitem;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.DecodeFormat;
import com.bumptech.glide.load.MultiTransformation;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
import com.snap.wall.adapter.OnItemclick;
import com.snap.wall.bean.Information;
import com.snap.wall.mytool.Comutils;
import com.snap.wall.R;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
public class Itemlist extends RecyclerView.Adapter<Itemlist.MyViewHolder> {
private List<Information> dataInfo = new ArrayList<>();
private OnItemclick onItemClick;
private WeakReference<Context> weakReference;
private int itemHeight;
private boolean showSpace = false;
public void setInfoWallpaperListener(OnItemclick onItemClick) {
this.onItemClick = onItemClick;
}
public Itemlist(Context myCon, int itemHeight, boolean show) {
weakReference = new WeakReference<>(myCon);
this.itemHeight = itemHeight;
showSpace = show;
}
public void setDataInfo(List<Information> dataInfo) {
this.dataInfo = dataInfo;
notifyDataSetChanged();
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Context context = weakReference.get();
if (context != null) {
View itemView = LayoutInflater.from(context).inflate(R.layout.item_list, parent, false);
ImageView imageView = itemView.findViewById(R.id.wallpaper);
ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams();
layoutParams.height = itemHeight;
imageView.setLayoutParams(layoutParams);
return new MyViewHolder(itemView);
}
return null;
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
Information info = dataInfo.get(position);
ImageView imageView = holder.getImageView();
String previewUrl400 = info.getPreviewUrl400();
String previewUrl200 = info.getPreviewUrl200();
RelativeLayout item = holder.getLayout();
String imId = info.getImId();
int curheight;
View spaceView = holder.getSpaceView();
if (showSpace && position == dataInfo.size() - 1) {
spaceView.setVisibility(View.VISIBLE);
} else {
spaceView.setVisibility(View.GONE);
}
MultiTransformation<Bitmap> multiTransformation = new MultiTransformation<>(
new CenterCrop(),
new RoundedCornersTransformation(Comutils.dp2Px(12), 0) // 圆角效果
);
RequestOptions options = new RequestOptions()
.format(DecodeFormat.PREFER_RGB_565);
Context context = weakReference.get();
if (context != null) {
Glide.with(context)
.asDrawable()
.skipMemoryCache(true)
.apply(options)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.load(previewUrl400)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<Drawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target<Drawable> target, @NonNull DataSource dataSource, boolean isFirstResource) {
return false;
}
})
.placeholder(R.mipmap.im_placeholder)
.transform(multiTransformation)
.into(imageView);
}
item.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onItemClick != null) {
onItemClick.onItemClickAction(info);
}
}
});
}
@Override
public int getItemCount() {
return dataInfo.size();
}
@Override
public void onViewRecycled(@NonNull MyViewHolder holder) {
super.onViewRecycled(holder);
}
private static DiffUtil.ItemCallback<Information> diff = new DiffUtil.ItemCallback<Information>() {
@Override
public boolean areItemsTheSame(@NonNull Information oldItem, @NonNull Information newItem) {
return oldItem.getImId().equals(newItem.getImId());
}
@Override
public boolean areContentsTheSame(@NonNull Information oldItem, @NonNull Information newItem) {
return oldItem.getImId().equals(newItem.getImId());
}
};
private static class MyCallback extends DiffUtil.Callback {
private List<Information> mOldList;
private List<Information> mNewList;
public MyCallback(List<Information> oldList, List<Information> newList) {
mOldList = oldList;
mNewList = newList;
}
@Override
public int getOldListSize() {
return mOldList.size();
}
@Override
public int getNewListSize() {
return mNewList.size();
}
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return mOldList.get(oldItemPosition).getImId().equals(mNewList.get(newItemPosition).getImId());
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return mOldList.get(oldItemPosition).getImId().equals(mNewList.get(newItemPosition).getImId());
}
}
static class MyViewHolder extends RecyclerView.ViewHolder {
private ImageView imageView;
private RelativeLayout layout;
private View spaceView;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.wallpaper);
layout = itemView.findViewById(R.id.layout);
spaceView = itemView.findViewById(R.id.space_view);
}
// public ImageView getImFavorite() {
// return imFavorite;
// }
public RelativeLayout getLayout() {
return layout;
}
public ImageView getImageView() {
return imageView;
}
public View getSpaceView() {
return spaceView;
}
}
}

View File

@ -0,0 +1,144 @@
package com.snap.wall.mytool;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Debug;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import com.snap.wall.App;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
public class Comutils {
public static final String key_info = "key_info";
public static final String key_index = "key_index";
public static String getCovertStr(InputStream stream) {
String covertStr = "";
try {
StringWriter writer = new StringWriter();
char[] buffer = new char[stream.available()];
Reader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8));
int a = 0;
while ((a = reader.read(buffer)) != -1) {
writer.write(buffer, 0, a);
}
covertStr = writer.toString();
} catch (IOException e) {
return covertStr;
}
return covertStr;
}
public static int dp2Px(int dp) {
float scale = App.mAppContext.getResources().getDisplayMetrics().density;
return (int) (dp * scale + 0.5f);
}
public static void initFull(Activity activity, boolean light) {
Window window = activity.getWindow();
View decorView = window.getDecorView();
View rootView = decorView.getRootView();
if (light) {
} else {
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
private static Bitmap getBitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
// 创建一个空白的 Bitmap
Bitmap bitmap = Bitmap.createBitmap(
drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(),
Bitmap.Config.ARGB_8888);
// Canvas 上绘制 Drawable
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
public static String saveDrawableToFile( Drawable drawable,String saveFilePath) {
// Drawable 转换为 Bitmap
Bitmap bitmap = getBitmap(drawable);
// 创建要保存的文件
File file = new File(saveFilePath);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
// Bitmap 写入文件 (使用 PNG 格式可改为 JPEG)
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return file.getAbsolutePath();
}
public static void printUsedMemory(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(new int[]{android.os.Process.myPid()});
for (Debug.MemoryInfo memoryInfo : memoryInfoArray) {
int totalPss = memoryInfo.getTotalPss();
int totalPrivateDirty = memoryInfo.getTotalPrivateDirty();
int totalSharedDirty = memoryInfo.getTotalSharedDirty();
Log.d("MemoryInfo", "Total PSS: " + totalPss + " KB");
Log.d("MemoryInfo", "Total Private Dirty: " + totalPrivateDirty + " KB");
Log.d("MemoryInfo", "Total Shared Dirty: " + totalSharedDirty + " KB");
}
}
public static int[] getScreenWidthHeight(Context context) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
int width = metrics.widthPixels;
int height = metrics.heightPixels;
return new int[]{width, height};
}
}

View File

@ -0,0 +1,56 @@
package com.snap.wall.mytool;
import android.graphics.Rect;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class Itemhelper extends RecyclerView.ItemDecoration {
private int ex_space = 0;
private int v_space = 0;
private int h_space = 0;
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
int spanSize = 1;
int spanIndex = 0;
int spanCount = 1;
RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
GridLayoutManager layoutManager1 = (GridLayoutManager) layoutManager;
GridLayoutManager.LayoutParams layoutParams = (GridLayoutManager.LayoutParams) view.getLayoutParams();
spanCount = layoutManager1.getSpanCount();
spanSize = layoutManager1.getSpanSizeLookup().getSpanSize(position);
spanIndex = layoutParams.getSpanIndex();
}
if (spanSize == spanCount) {
outRect.left = v_space + ex_space;
outRect.right = v_space + ex_space;
outRect.bottom = h_space;
} else {
int itemAllSpacing = (v_space * (spanCount + 1) + ex_space * 2) / spanCount;
int left = v_space * (spanIndex + 1) - itemAllSpacing * spanIndex + ex_space;
int right = itemAllSpacing - left;
outRect.left = left;
outRect.right = right;
outRect.bottom = h_space;
}
}
public Itemhelper(int v_space, int h_space, int ex_space) {
this.ex_space = ex_space;
this.h_space = h_space;
this.v_space = v_space;
}
}

View File

@ -0,0 +1,228 @@
package com.snap.wall.mytool
import android.Manifest
import android.app.Activity
import android.content.ContentValues
import android.content.Context
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import android.util.Log
import androidx.core.app.ActivityCompat
import com.snap.wall.App
import com.snap.wall.bean.Information
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.json.JSONArray
import org.json.JSONObject
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
object JsonData {
fun getData(jsonStr: String, category: String): MutableList<Information> {
val jsonArray = JSONArray(jsonStr)
var data = mutableListOf<Information>()
var get: JSONObject
var text_description: String
var links: JSONObject
var download: String
var urls: JSONObject
var regular: String
var small: String
var thumb: String
var users: JSONObject
var name: String
var header_large: String
var user_html: String
val host = "https://unsplash.com/photos/"
var bean: Information
var indexOf: Int
var substring: String
for (i in 0 until 300) {
get = jsonArray.getJSONObject(i)
text_description = get.getString("alt_description")
links = get.getJSONObject("links")
download = links.getString("download")
// val downloadLocation = links.getString("download_location")
// val html = links.getString("html")
urls = get.getJSONObject("urls")
// val full = urls.getString("full")
// val raw = urls.getString("raw")
regular = urls.getString("regular")
small = urls.getString("small")
thumb = urls.getString("thumb")
users = get.getJSONObject("user")
// val portfolio_url = users.getString("portfolio_url")
name = users.getString("name")
header_large = users.getString("header_large")
// val header_medium = users.getString("header_medium")
// val header_small = users.getString("header_small")
user_html = users.getString("authorHtml")
indexOf = download.indexOf("/download")
substring = download.substring(host.length, indexOf)
// Log.d(MyApp.TAG, "i=$i----------substring=$substring")
bean = Information().apply {
imId = substring
categoryName = category
description = text_description
fullUrl = download
previewUrl1080 = regular
previewUrl400 = small
previewUrl200 = thumb
authorName = name
authorHeader = header_large
authorHtml = user_html
}
data.add(bean)
}
return data
}
fun downloadFile(
url: String,
savePath: String,
result: (Boolean, input: InputStream?) -> Unit
): Call {
var client = OkHttpClient()
var request = Request.Builder().url(url).build()
var call = client.newCall(request)
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
result.invoke(false, null)
}
override fun onResponse(call: Call, response: Response) {
response.body?.run {
val byteStream = byteStream()
val writeFile = writeFile(byteStream, savePath)
result.invoke(writeFile, byteStream)
} ?: run {
result.invoke(false, null)
}
}
})
return call
}
fun writeFile(input: InputStream, filePath: String): Boolean {
try {
val byte = ByteArray(4096)
val output = ByteArrayOutputStream()
var l: Int
while (input.read(byte).also { l = it } != -1) {
output.write(byte, 0, l)
}
val fileDe = File(filePath)
if (!fileDe.exists()) {
fileDe.createNewFile()
}
val fileOutputStream = FileOutputStream(filePath)
fileOutputStream.write(output.toByteArray())
output.close()
fileOutputStream.close()
return true
} catch (ex: Exception) {
Log.d("-----------", "---------ex=" + ex.message)
return false
}
}
fun saveToGallery(context: Context, photoFile: File): Uri? {
val displayName = "${System.currentTimeMillis()}.jpg"
val contentValues = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, displayName)
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
put(MediaStore.Images.Media.IS_PENDING, 1)
}
}
val contentResolver = context.contentResolver
val collectionUri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
} else {
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
}
val imageUri = contentResolver.insert(collectionUri, contentValues)
imageUri?.let { uri ->
try {
contentResolver.openOutputStream(uri)?.use { outputStream ->
val inputStream = FileInputStream(photoFile)
inputStream.copyTo(outputStream)
inputStream.close()
outputStream.close()
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
contentValues.clear()
contentValues.put(MediaStore.Images.Media.IS_PENDING, 0)
contentResolver.update(uri, contentValues, null, null)
} else {
}
return uri
} catch (e: IOException) {
Log.d(App.TAG, "-----------------e=${e.printStackTrace()}")
return null
}
} ?: run {
Log.d(App.TAG, "----------------false")
return null
}
}
fun requestPermission(context: Activity, requestCode: Int): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
return true
}
return if (context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
context,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
requestCode
)
false
} else {
true
}
}
fun getSaveFilePath(context: Context, imId: String): String {
return "${context.cacheDir}/${imId}.jpg"
}
}

View File

@ -0,0 +1,34 @@
package com.snap.wall.mytool;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import androidx.annotation.Nullable;
import com.snap.wall.App;
import com.snap.wall.R;
public class Mytext extends androidx.appcompat.widget.AppCompatTextView {
public Mytext(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initAttrs(context,attrs);
}
private void initAttrs(Context context, AttributeSet attrs){
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomeTv);
boolean aBoolean = typedArray.getBoolean(R.styleable.CustomeTv_apply_font,false);
if(aBoolean){
setTypeface(App.defaultFont);
}
typedArray.recycle();
}
}

View File

@ -0,0 +1,158 @@
package com.snap.wall.mytool;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import com.snap.wall.App;
import com.snap.wall.adapter.OnLikelist;
import com.snap.wall.adapter.OnUpdatelike;
import com.snap.wall.bean.Information;
import com.snap.wall.bean.Information_;
import com.snap.wall.bean.MyObjectBox;
import java.util.ArrayList;
import java.util.List;
import io.objectbox.Box;
import io.objectbox.BoxStore;
import io.objectbox.android.AndroidScheduler;
import io.objectbox.query.Query;
import io.objectbox.query.QueryBuilder;
import io.objectbox.reactive.DataObserver;
import io.objectbox.reactive.DataSubscription;
import io.objectbox.reactive.DataSubscriptionList;
public class ObectManager {
private static BoxStore boxStore;
private static Box<Information> LikeBox;
private static List<OnUpdatelike> list = new ArrayList<>();
public static void init(Context context) {
boxStore = MyObjectBox.builder().androidContext(context).build();
}
public static Box<Information> getObjectBoxLike() {
if (LikeBox == null) {
LikeBox = boxStore.boxFor(Information.class);
}
return LikeBox;
}
public static void addData(Information data) {
Box<Information> objectBoxLike = getObjectBoxLike();
String imId = data.getImId();
Information first = objectBoxLike.query()
.equal(Information_.imId, imId, QueryBuilder.StringOrder.CASE_SENSITIVE)
.build()
.findFirst();
if (first == null) {
Log.d(App.TAG, "-----------addData " + imId);
objectBoxLike.put(data);
}else {
Log.d(App.TAG, "-----------忽略添加 ");
}
}
public static DataSubscription setLikeDataListener(OnLikelist listener) {
Query<Information> build = getObjectBoxLike().query()
.equal(Information_.isLike, true)
.build();
return build.subscribe(new DataSubscriptionList())
.on(AndroidScheduler.mainThread())
.observer(new DataObserver<List<Information>>() {
@Override
public void onData(@NonNull List<Information> data) {
Log.d(App.TAG, "------data=" + data.size());
listener.onLikeList(data);
}
});
}
public static void updateLike(Information boxLike) {
Box<Information> objectBoxLike = getObjectBoxLike();
String imId = boxLike.getImId();
objectBoxLike.put(boxLike);
for (OnUpdatelike listener : list) {
listener.onAdd(boxLike);
}
}
public static void insertOrUpdateDownload(Information boxLike) {
Box<Information> objectBoxLike = getObjectBoxLike();
String imId = boxLike.getImId();
Information first = objectBoxLike.query()
.equal(Information_.imId, imId, QueryBuilder.StringOrder.CASE_SENSITIVE)
.build()
.findFirst();
if (first == null) {
Log.d(App.TAG, "-----------添加11 Download=" + imId);
boxLike.setDownload(true);
objectBoxLike.put(boxLike);
} else {
first.setDownload(true);
objectBoxLike.put(first);
Log.d(App.TAG, "-----------已经存在添加22 Download=" + imId);
}
}
public static List<Information> search(String name) {
Box<Information> objectBoxLike = getObjectBoxLike();
List<Information> data = objectBoxLike.query()
.contains(Information_.description, name, QueryBuilder.StringOrder.CASE_SENSITIVE)
.build()
.find();
return data;
}
public static List<Information> queryHome(String name) {
Box<Information> objectBoxLike = getObjectBoxLike();
List<Information> data = objectBoxLike.query()
.equal(Information_.categoryName, name, QueryBuilder.StringOrder.CASE_SENSITIVE)
.build()
.find(10, 1);
return data;
}
public static List<Information> queryCategoryAll(String name) {
Box<Information> objectBoxLike = getObjectBoxLike();
List<Information> data = objectBoxLike.query()
.equal(Information_.categoryName, name, QueryBuilder.StringOrder.CASE_SENSITIVE)
.build()
.find(0, 200);
return data;
}
public static boolean queryIsLike(String imId) {
Box<Information> objectBoxLike = getObjectBoxLike();
Information first = objectBoxLike.query()
.equal(Information_.imId, imId, QueryBuilder.StringOrder.CASE_SENSITIVE)
.build()
.findFirst();
if (first != null && first.isLike()) {
return true;
} else {
return false;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="10dp" />
<solid android:color="#E4F3FB"/>
</shape>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M154.5,469.3H981.3a42.7,42.7 0,1 1,0 85.3H154.5l300.7,266.9a42.7,42.7 0,1 1,-57.1 63.4l-384,-341.3a42.7,42.7 0,0 1,0 -63.4l384,-341.3a42.7,42.7 0,1 1,57.1 63.4L154.5,469.3z"
android:fillColor="@color/black"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="20dp" />
<stroke android:width="1dp" android:color="@color/gray_100" />
</shape>

View File

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M747.2,283.2L54.5,283.2v692.7h692.7v-692.7zM656.8,373.6v512h-512v-512h512z"
android:fillColor="@color/white"/>
<path
android:pathData="M993.3,12.4v692.7h-287.2v-90.4h196.8v-512h-512v224.4h-90.4V12.4z"
android:fillColor="@color/white"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="@color/white"
android:pathData="M776.7,1010.1h-479.9c-28.3,0 -51.3,-23 -51.3,-51.3v-891.1c0,-28.3 23,-51.3 51.3,-51.3h479.9c28.3,0 51.3,23 51.3,51.3v891.1c0,28.3 -23,51.3 -51.3,51.3v0zM536.6,958.8c19.1,0 34.2,-15.4 34.2,-34.2s-15.4,-34.2 -34.2,-34.2 -34.2,15.4 -34.2,34.2 15.4,34.2 34.2,34.2v0zM776.7,119h-479.9v719.7h479.6v-719.7h0.3z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M878.6,337.2a57.8,57.8 0,0 0,-81.7 0L574.6,559.5V173a57.8,57.8 0,0 0,-115.6 0v386.5L236.8,337.2a57.8,57.8 0,0 0,-81.7 0,57.8 57.8,0 0,0 0,81.8l318.7,318.7a57.6,57.6 0,0 0,40.9 16.9c0.7,0 1.5,-0.1 2.2,-0.1 0.7,0 1.5,0.1 2.2,0.1a57.6,57.6 0,0 0,40.9 -16.9L878.6,419a57.8,57.8 0,0 0,0 -81.8zM861,908.4H165.4a57.8,57.8 0,0 1,0 -115.6h695.6a57.8,57.8 0,0 1,0 115.6z"
android:fillColor="@color/white"/>
</vector>

View File

@ -0,0 +1,17 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="256dp"
android:height="256dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M219.8,71c-12.3,0 -21.8,-9.6 -21.8,-21.8S208.9,27.3 219.8,27.3c12.3,0 21.8,9.6 21.8,21.8 0,12.3 -9.6,21.8 -21.8,21.8zM219.8,34.1c-8.2,0 -15,6.8 -15,15s6.8,15 15,15c8.2,0 15,-6.8 15,-15 0,-8.2 -6.8,-15 -15,-15z"
android:strokeAlpha="0.3"
android:fillColor="@color/sub_title_color"
android:fillAlpha="0.3"/>
<path
android:pathData="M935.3,1009L112,1009c-4.1,0 -6.8,2.7 -6.8,6.8s2.7,6.8 6.8,6.8h823.3c4.1,0 6.8,-2.7 6.8,-6.8s-2.7,-6.8 -6.8,-6.8zM84.7,1009h-54.6c-4.1,0 -6.8,2.7 -6.8,6.8s2.7,6.8 6.8,6.8h54.6c4.1,0 6.8,-2.7 6.8,-6.8s-4.1,-6.8 -6.8,-6.8zM994,1009h-27.3c-4.1,0 -6.8,2.7 -6.8,6.8s2.7,6.8 6.8,6.8h27.3c4.1,0 6.8,-2.7 6.8,-6.8s-2.7,-6.8 -6.8,-6.8zM244.4,428.7c4.1,0 6.8,-2.7 6.8,-6.8L251.2,210.3h400v109.2L764.6,319.5l4.1,4.1v379.6c0,4.1 2.7,6.8 6.8,6.8s6.8,-2.7 6.8,-6.8L782.3,318.1l-8.2,-8.2c0,-1.4 -2.7,-4.1 -4.1,-4.1l-107.9,-107.9 -1.4,-1.4h-423.3v225.3c0,4.1 2.7,6.8 6.8,6.8zM663.6,305.8v-86l86,86h-86zM244.4,518.8c4.1,0 6.8,-2.7 6.8,-6.8v-64.2c0,-4.1 -2.7,-6.8 -6.8,-6.8s-6.8,2.7 -6.8,6.8v64.2c0,4.1 2.7,6.8 6.8,6.8zM244.4,558.4c4.1,0 6.8,-2.7 6.8,-6.8L251.2,532.5c0,-4.1 -2.7,-6.8 -6.8,-6.8s-6.8,2.7 -6.8,6.8v19.1c0,4.1 2.7,6.8 6.8,6.8zM782.3,740c0,-4.1 -2.7,-6.8 -6.8,-6.8s-6.8,2.7 -6.8,6.8v84.7L251.2,824.7L251.2,570.7c0,-4.1 -2.7,-6.8 -6.8,-6.8s-6.8,2.7 -6.8,6.8v267.6h544.8v-98.3z"
android:fillColor="@color/sub_title_color"/>
<path
android:pathData="M460.1,434.2c-4.1,-1.4 -6.8,1.4 -8.2,5.5 -2.7,15 -12.3,27.3 -24.6,32.8 -24.6,9.6 -58.7,-8.2 -58.7,-9.6 -2.7,-1.4 -6.8,-1.4 -9.6,2.7 -1.4,2.7 -1.4,6.8 2.7,9.6 15,8.2 31.4,13.7 49.2,13.7 6.8,0 15,-1.4 21.8,-4.1 17.7,-8.2 30,-23.2 32.8,-42.3 0,-4.1 -1.4,-8.2 -5.5,-8.2zM584.4,490.2c5.5,2.7 10.9,2.7 17.7,2.7 16.4,-1.4 31.4,-6.8 45.1,-16.4 2.7,-2.7 4.1,-6.8 1.4,-9.6 -2.7,-2.7 -5.5,-4.1 -9.6,-1.4 -19.1,12.3 -35.5,16.4 -49.2,10.9 -21.8,-8.2 -31.4,-39.6 -31.4,-39.6 -1.4,-4.1 -5.5,-5.5 -8.2,-4.1 -4.1,1.4 -5.5,4.1 -4.1,8.2 0,2.7 9.6,38.2 38.2,49.2zM462.8,617.1c1.4,-1.4 36.9,-34.1 81.9,4.1 1.4,1.4 2.7,1.4 4.1,1.4 4.1,0 6.8,-2.7 6.8,-6.8 0,-2.7 -1.4,-4.1 -2.7,-5.5 -56,-45.1 -99.7,-2.7 -101,-2.7 -2.7,2.7 -2.7,6.8 0,9.6s8.2,2.7 10.9,0zM909.3,148.8c12.3,0 21.8,-9.6 21.8,-21.8s-9.6,-21.8 -21.8,-21.8c-12.3,0 -21.8,9.6 -21.8,21.8 1.4,12.3 10.9,21.8 21.8,21.8zM909.3,113.3c8.2,0 15,6.8 15,15s-6.8,15 -15,15c-8.2,0 -15,-6.8 -15,-15 1.4,-8.2 8.2,-15 15,-15zM73.7,296.3l13.7,8.2 -6.8,13.7c-1.4,2.7 0,5.5 2.7,6.8 2.7,1.4 5.5,0 6.8,-2.7l5.5,-12.3 12.3,8.2c1.4,0 1.4,1.4 2.7,1.4 2.7,0 5.5,-2.7 5.5,-5.5 0,-1.4 -1.4,-4.1 -2.7,-4.1l-13.7,-8.2 6.8,-13.7c1.4,-2.7 0,-5.5 -2.7,-6.8 -2.7,-1.4 -5.5,0 -6.8,2.7l-6.8,12.3 -10.9,-9.6c-2.7,-1.4 -5.5,-1.4 -6.8,1.4 -2.7,2.7 -1.4,6.8 1.4,8.2zM957.1,475.1l-19.1,-10.9 8.2,-20.5c1.4,-4.1 0,-6.8 -4.1,-9.6s-6.8,0 -9.6,4.1l-8.2,19.1 -17.7,-9.6c-2.7,-1.4 -6.8,0 -9.6,2.7 -1.4,2.7 0,6.8 2.7,9.6l19.1,10.9 -8.2,20.5c-1.4,4.1 0,6.8 4.1,9.6s6.8,0 9.6,-4.1l8.2,-19.1 17.7,9.6c2.7,1.4 6.8,0 9.6,-2.7s0,-8.2 -2.7,-9.6z"
android:fillColor="@color/sub_title_color"/>
</vector>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="12dp"/> <!-- 圆角半径(确保足够大,肉眼可见) -->
<!-- 可选:加边框区分背景 -->
<stroke
android:width="1dp"/>
</shape>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M667.8,117.3C832.9,117.3 938.7,249.7 938.7,427.9c0,138.3 -125.1,290.5 -371.6,461.6a96.8,96.8 0,0 1,-110.2 0C210.4,718.4 85.3,566.1 85.3,427.9 85.3,249.7 191.1,117.3 356.2,117.3c59.6,0 100.1,20.8 155.8,68.1C567.7,138.2 608.2,117.3 667.8,117.3z"
android:fillColor="@color/favorite_true"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M667.8,117.3C832.9,117.3 938.7,249.7 938.7,427.9c0,138.3 -125.1,290.5 -371.6,461.6a96.8,96.8 0,0 1,-110.2 0C210.4,718.4 85.3,566.1 85.3,427.9 85.3,249.7 191.1,117.3 356.2,117.3c59.6,0 100.1,20.8 155.8,68.1C567.7,138.2 608.2,117.3 667.8,117.3zM667.8,180.5c-41.4,0 -70.3,15.2 -117,55 -2.2,1.8 -14.4,12.4 -17.9,15.4a32.3,32.3 0,0 1,-41.8 0c-3.5,-3 -15.8,-13.5 -17.9,-15.4 -46.7,-39.9 -75.5,-55 -117,-55C230.2,180.5 149.3,281.3 149.3,426.7 149.3,537.6 262.9,675.2 493.6,834.8a32.4,32.4 0,0 0,36.7 0C761.1,675.3 874.7,537.6 874.7,426.7c0,-145.4 -80.9,-246.2 -206.9,-246.2z"
android:fillColor="@color/white"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="@color/white"
android:pathData="M426.9,683l170.8,0c25.6,0 42.7,-17.1 42.7,-42.7L640.3,512.3c0,-25.6 -17.1,-42.7 -42.7,-42.7l0,-42.7c0,-47 -38.4,-85.4 -85.4,-85.4s-85.4,38.4 -85.4,85.4l0,42.7c-25.6,0 -42.7,17.1 -42.7,42.7l0,128.1C384.2,666 401.3,683 426.9,683zM461,426.9c0,-29.9 21.3,-51.2 51.2,-51.2s51.2,21.3 51.2,51.2l0,42.7 -102.5,0L461,426.9 461,426.9zM725.7,42.7 L298.8,42.7c-47,0 -85.4,38.4 -85.4,85.4l0,768.4c0,47 38.4,85.4 85.4,85.4l426.9,0c47,0 85.4,-38.4 85.4,-85.4L811.1,128.1C811.1,81.1 772.7,42.7 725.7,42.7zM725.7,811.1 L298.8,811.1 298.8,213.4l426.9,0L725.7,811.1z"/>
</vector>

View File

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M271.9,728.1v-412.2c0,-30.7 18.9,-53.8 39.9,-53.8h412.2c21,0 39.9,23.6 39.9,54.3v220.2c0,2 0.5,4.1 1,5.6l14.8,-5.6v-220.2c0,-38.9 -25.1,-70.1 -56.3,-70.1h-412.2c-31.2,0 -56.3,31.2 -56.3,70.1v418.3l16.9,-6.7zM271.9,728.1v-412.2c0,-30.7 18.9,-53.8 39.9,-53.8h412.2c21,0 39.9,23.6 39.9,54.3v220.2c0,2 0.5,4.1 1,5.6l14.8,-5.6v-220.2c0,-38.9 -25.1,-70.1 -56.3,-70.1h-412.2c-31.2,0 -56.3,31.2 -56.3,70.1v418.3l16.9,-6.7zM958.5,800.8c-21.5,-16.9 -45.6,-29.7 -71.7,-38.4 -4.1,-1 -8.7,1.5 -9.7,5.6 -1,4.1 1,8.2 4.6,9.7 24.1,8.2 46.6,20.5 67.1,35.8 3.6,2.6 8.7,1.5 11.3,-2 2,-3.1 1.5,-7.7 -1.5,-10.8zM517.6,817.2c-37.9,0 -75.3,10.2 -108,30.2 -45.6,-61.4 -117.2,-97.3 -194,-97.3 -54.3,0 -107.5,18.4 -150,52.2 -3.1,3.1 -3.6,8.2 -0.5,11.3 2.6,3.1 7.2,3.6 10.2,1 39.9,-31.7 89.1,-48.6 140.3,-48.6 74.8,0 143.4,36.4 185.3,96.8 2.6,3.6 7.2,4.6 11.3,2 31.2,-21 68.1,-31.7 105.5,-31.7 35.8,0 69.6,9.7 99.8,27.6 3.6,2 8.2,1 10.8,-2 13.3,-17.9 29.2,-34.3 47.1,-47.6 3.6,-3.1 4.1,-8.2 1,-11.3 -2.6,-3.1 -7.2,-3.6 -10.8,-1.5 -17.4,12.8 -32.8,28.2 -46.1,45.1 -31.7,-16.9 -66.6,-26.1 -101.9,-26.1zM855.6,846.8c-41,-27.6 -96.3,-16.9 -123.9,23.6l-3.1,4.6c-2,3.6 -1,8.7 3.1,11.3 3.6,2 8.7,1 11.3,-3.1 8.2,-14.3 21.5,-25.1 36.9,-31.2 22.5,-8.7 47.6,-5.6 67.6,7.7 3.6,2.6 8.7,1.5 11.3,-2 1.5,-3.1 0.5,-8.2 -3.1,-10.8zM185.3,248.8c2,1.5 2,4.6 0.5,6.1m-45.1,205.3l-18.9,21c-1,1 -2.6,1 -3.6,0 -1,-1 -1,-2.6 0,-3.6l18.9,-21c1,-1 2.6,-1 3.6,0 1,1 1,2.6 0,3.6zM165.4,460.3l-18.9,21c-1,1 -2.6,1 -3.6,0 -1,-1 -1,-2.6 0,-3.6l18.9,-21c1,-1 2.6,-1 3.6,0 0.5,1 1,2.6 0,3.6zM813.1,146.4l-38.4,43c-2,2.6 -6.1,2.6 -8.2,0.5 -2.6,-2 -2.6,-6.1 -0.5,-8.2l38.4,-43c2,-2.6 6.1,-2.6 8.2,-0.5 2.6,2 2.6,5.6 0.5,8.2zM863.7,146.4l-38.4,43c-2,2.6 -6.1,2.6 -8.2,0.5 -2.6,-2 -2.6,-6.1 -0.5,-8.2l38.4,-43c2,-2.6 6.1,-2.6 8.2,-0.5 2.6,2 3.1,5.6 0.5,8.2z"
android:fillColor="@color/sub_title_color"/>
<path
android:pathData="M390.1,451.6c-17.9,0.5 -32.8,-13.8 -33.3,-31.2 -0.5,-17.9 13.8,-32.8 31.2,-33.3h1.5c17.9,0.5 31.7,15.4 31.2,33.3 0.5,16.9 -13.3,30.7 -30.7,31.2zM382.5,419.3c6.1,0 10.8,-4.6 10.8,-10.8 0,-6.1 -4.6,-10.8 -10.8,-10.8 -6.1,0 -10.8,4.6 -10.8,10.8 0,6.1 4.6,10.8 10.8,10.8zM656.4,451.6c-17.9,0.5 -32.8,-13.8 -33.3,-31.2 -0.5,-17.9 13.8,-32.8 31.2,-33.3h1.5c17.9,0.5 31.7,15.4 31.2,33.3 0.5,16.9 -13.3,30.7 -30.7,31.2zM648.2,419.3c6.1,0 10.8,-4.6 10.8,-10.8 0,-6.1 -4.6,-10.8 -10.8,-10.8s-10.8,4.6 -10.8,10.8c0,6.1 5.1,10.8 10.8,10.8zM596,515.1c-2,0 -4.1,-1 -5.6,-2.6 -11.8,-12.3 -23.6,-17.9 -35.3,-17.4 -11.3,0.5 -21,7.7 -26.1,14.3 -2.6,3.6 -7.7,4.1 -11.3,1.5 -0.5,-0.5 -1,-0.5 -1,-1 -14.3,-16.4 -26.6,-15.9 -36.4,-13.8 -8.2,2 -16.4,6.7 -24.6,14.3 -3.1,3.1 -8.2,2.6 -11.3,-0.5 -3.1,-3.1 -2.6,-8.2 0.5,-11.3 10.2,-9.2 21,-15.4 31.7,-17.9 17.4,-4.6 32.8,-0.5 46.6,12.3 6.7,-6.1 17.4,-12.8 31.7,-13.8 16.4,-1 32.3,6.7 47.6,22.5 3.1,3.1 3.1,8.2 0,11.3 -2.6,1 -4.6,2 -6.7,2zM765.4,798.2c-64.5,0 -116.7,-52.2 -116.7,-116.7 0,-64.5 52.2,-116.7 116.7,-116.7 64.5,0 116.7,52.2 116.7,116.7 0,64.5 -52.2,116.7 -116.7,116.7zM707.6,666.6c-8.7,0 -16.4,7.2 -15.9,16.4 0,8.7 7.2,15.9 15.9,15.9h118.3c8.7,0 16.4,-7.2 15.9,-16.4 0,-8.7 -7.2,-15.9 -15.9,-15.9h-118.3z"
android:fillColor="@color/sub_title_color"/>
</vector>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/color_main_view"/>
</shape>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="16dp" />
<solid android:color="@color/color_main_view" />
</shape>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="19dp"/>
<gradient
android:angle="45"
android:endColor="@color/color_4202cb"
android:startColor="@color/color_4202cb" />
</shape>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="16dp"/>
<stroke android:width="1dp" android:color="@color/black"/>
</shape>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/like_selected_one" android:state_selected="true" />
<item android:drawable="@drawable/like_stoke_white" />
</selector>

View File

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="256dp"
android:height="256dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M222.1,580.4a356.2,356.2 0,0 0,34.1 152.9,357.6 357.6,0 0,0 477.7,-477.7A357.6,357.6 0,0 0,222.1 580.4z"
android:fillColor="@color/color_0"/>
<path
android:pathData="M1009,936.6l-276.1,-276.1a409.5,409.5 0,1 0,-72.3 72.3l276.1,276.1a51.2,51.2 0,0 0,72.3 -72.3zM409.8,716.9a307.1,307.1 0,1 1,307.1 -307.1,307.1 307.1,0 0,1 -307.1,307.1z"
android:fillColor="@color/black"/>
</vector>

View File

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="256dp"
android:height="256dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M222.1,580.4a356.2,356.2 0,0 0,34.1 152.9,357.6 357.6,0 0,0 477.7,-477.7A357.6,357.6 0,0 0,222.1 580.4z"
android:fillColor="@color/color_0"/>
<path
android:pathData="M1009,936.6l-276.1,-276.1a409.5,409.5 0,1 0,-72.3 72.3l276.1,276.1a51.2,51.2 0,0 0,72.3 -72.3zM409.8,716.9a307.1,307.1 0,1 1,307.1 -307.1,307.1 307.1,0 0,1 -307.1,307.1z"
android:fillColor="@color/black"/>
</vector>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<corners android:radius="10dp" />
<solid android:color="@color/sub_color" />
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="10dp" />
<gradient
android:angle="0"
android:endColor="@color/color_fad91d"
android:centerColor="@color/color_fad91d"
android:startColor="@color/color_fad91d" />
</shape>
</clip>
</item>
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/yellow_star"
android:pathData="M12,17.27L18.18,21L16.54,13.97L22,9.24L14.81,8.62L12,2L9.19,8.62L2,9.24L7.45,13.97L5.82,21L12,17.27Z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/gray_100"
android:pathData="M12,17.27L18.18,21L16.54,13.97L22,9.24L14.81,8.62L12,2L9.19,8.62L2,9.24L7.45,13.97L5.82,21L12,17.27Z"/>
</vector>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="#FFFFF8E1"
android:endColor="#FF90CAF9"
android:angle="135" />
<padding
android:left="12dp"
android:top="4dp"
android:right="12dp"
android:bottom="4dp" />
</shape>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="#FFFFF8E1"
android:endColor="#FF90CAF9"
android:angle="135" />
<corners android:radius="10dp" /> <!-- 圆角 -->
<padding
android:left="12dp"
android:top="4dp"
android:right="12dp"
android:bottom="4dp" />
</shape>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 替换渐变为纯色填充(使用你渐变的结束色#FF90CAF9 -->
<solid android:color="#FF90CAF9" />
<!-- 保留原有圆角设置 -->
<corners android:radius="10dp" />
<!-- 保留原有内边距设置 -->
<padding
android:left="12dp"
android:top="4dp"
android:right="12dp"
android:bottom="4dp" />
</shape>

View File

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="256dp"
android:height="256dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="@color/white"
android:pathData="M261.9,492.9c20.6,11.9 46,11.9 66.6,0 20.6,-11.9 33.3,-33.9 33.3,-57.6 0,-36.8 -29.8,-66.5 -66.6,-66.5s-66.5,29.8 -66.5,66.5c0,23.8 12.7,45.7 33.2,57.6z"/>
<path
android:fillColor="@color/white"
android:pathData="M804,153.4L221.4,153.4c-78.3,0 -142,63.7 -142,142v436.9c0,78.3 63.7,142 142,142L804,874.3c78.3,0 142,-63.7 142,-142L946,295.4c-0.1,-78.3 -63.7,-142 -142,-142zM144.9,295.4c0,-42.2 34.3,-76.5 76.4,-76.5L804,218.9c42.1,0 76.4,34.3 76.4,76.5v331.1l-95.3,-86.2 -13.6,-9.7c-71.9,-46.1 -164.2,-45.1 -233.9,1.3l-385,232.6c-4.7,-9.9 -7.7,-20.6 -7.7,-32.2L144.9,295.4zM804,808.8L221.4,808.8c-4.1,0 -7.6,-1.7 -11.4,-2.3l362.8,-219.2c49.5,-32.9 113.6,-33.4 162.8,-1.9l143.7,128.5 1.2,-1.3v19.8c-0.1,42.1 -34.4,76.4 -76.5,76.4z"/>
</vector>

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.snap.wall.activity.OneActivity"
android:background="@drawable/tab_selected">
<androidx.cardview.widget.CardView
android:id="@+id/app_icon"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginTop="150dp"
android:layout_centerHorizontal="true"
app:cardCornerRadius="20dp"
app:cardElevation="0dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/logo_snap"
android:scaleType="centerCrop"
/>
</androidx.cardview.widget.CardView>
<TextView
android:id="@+id/app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:textStyle="italic"
android:textSize="28sp"
android:textColor="#FFFFFF"
android:layout_below="@id/app_icon"
android:layout_centerHorizontal="true"
android:layout_marginTop="30dp"/>
<ProgressBar
android:id="@+id/progressbar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="250dp"
android:layout_height="6dp"
android:layout_below="@id/tv_progress"
android:layout_centerHorizontal="true"
android:layout_marginBottom="40dp"
android:max="100"
android:progress="1"
android:progressDrawable="@drawable/splash_pb"
android:layout_marginTop="1dp"/>
<TextView
android:id="@+id/tv_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0%"
android:layout_centerHorizontal="true"
android:textSize="14sp"
android:layout_below="@id/app_name"
android:layout_marginTop="360dp"
/>
</RelativeLayout>

View File

@ -0,0 +1,185 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.snap.wall.activity.PreviewActivity">
<ImageView
android:id="@+id/imageview_preview"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<LinearLayout
android:id="@+id/ll_clock_weather"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="120dp"
android:orientation="vertical"
android:padding="10dp"
android:gravity="center_horizontal"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/tv_clock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="12:00"
android:textColor="@android:color/white"
android:textSize="72sp"
android:textStyle="bold"
android:shadowColor="@android:color/black"
android:shadowDx="3"
android:shadowDy="3"
android:shadowRadius="5"
android:scaleX="1.2"
android:scaleY="2.0" />
<!-- 日期+天气行 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="12dp"
android:gravity="center_vertical">
<TextView
android:id="@+id/tv_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2025年12月04日 Thursday"
android:textColor="@android:color/white"
android:textSize="18sp"
android:shadowColor="@android:color/black"
android:shadowDx="1.5"
android:shadowDy="1.5"
android:shadowRadius="3"/>
<TextView
android:id="@+id/tv_weather"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:text="晴 25℃"
android:textColor="@android:color/white"
android:textSize="18sp"
android:shadowColor="@android:color/black"
android:shadowDx="1.5"
android:shadowDy="1.5"
android:shadowRadius="3"/>
</LinearLayout>
</LinearLayout>
<!-- 返回按钮(核心功能) -->
<ImageView
android:id="@+id/imageview_back"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_marginStart="15dp"
android:layout_marginTop="52dp"
android:background="@drawable/oval"
android:padding="13dp"
android:src="@drawable/black_back"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!-- 壁纸描述文本(核心功能) -->
<com.snap.wall.mytool.Mytext
android:id="@+id/tv_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="40dp"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
android:background="@drawable/re16"
android:gravity="center"
android:minHeight="40dp"
android:padding="10dp"
android:text="@string/app_name"
android:textColor="@color/white"
android:textSize="13sp"
app:apply_font="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<!-- 设置壁纸按钮(核心功能) -->
<RelativeLayout
android:id="@+id/layout_set"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="15dp"
android:background="@drawable/oval"
app:layout_constraintBottom_toTopOf="@id/tv_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
<ImageView
android:id="@+id/button_set"
android:layout_width="46dp"
android:layout_height="46dp"
android:layout_centerInParent="true"
android:padding="13dp"
android:src="@drawable/wallpaper" />
<ProgressBar
android:id="@+id/pb_set"
android:layout_width="46dp"
android:layout_height="46dp"
android:layout_centerInParent="true"
android:indeterminateTint="@color/white"
android:padding="13dp"
android:visibility="gone" />
</RelativeLayout>
<!-- 下载按钮(核心功能) -->
<RelativeLayout
android:id="@+id/layout_download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="26dp"
android:background="@drawable/oval"
app:layout_constraintBottom_toBottomOf="@id/layout_set"
app:layout_constraintRight_toLeftOf="@id/layout_set"
app:layout_constraintTop_toTopOf="@id/layout_set">
<ImageView
android:id="@+id/image_download"
android:layout_width="46dp"
android:layout_height="46dp"
android:layout_centerInParent="true"
android:padding="13dp"
android:src="@drawable/download_one" />
<ProgressBar
android:id="@+id/pb_download"
android:layout_width="46dp"
android:layout_height="46dp"
android:layout_centerInParent="true"
android:indeterminateTint="@color/white"
android:padding="13dp"
android:visibility="gone" />
</RelativeLayout>
<!-- 收藏按钮(核心功能) -->
<ImageView
android:id="@+id/image_favorite"
android:layout_width="46dp"
android:layout_height="46dp"
android:layout_marginStart="26dp"
android:background="@drawable/oval"
android:padding="13dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:src="@drawable/se_favorite"
app:layout_constraintBottom_toBottomOf="@id/layout_set"
app:layout_constraintLeft_toRightOf="@id/layout_set"
app:layout_constraintTop_toTopOf="@id/layout_set" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="40dp"
android:background="@drawable/tab_selected"
tools:context="com.snap.wall.activity.PrimaryActivity">
<com.snap.wall.mytool.Mytext
android:id="@+id/textview_wallpaper"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:padding="10dp"
android:layout_marginTop="5dp"
android:text="@string/app_name"
android:textColor="@color/black"
android:textSize="17sp"
app:apply_font="true" />
<ImageView
android:layout_width="65dp"
android:layout_height="0dp"
android:paddingEnd="15dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:id="@+id/im_search"
android:paddingStart="12dp"
android:layout_marginEnd="10dp"
android:layout_alignTop="@id/textview_wallpaper"
android:layout_alignBottom="@id/textview_wallpaper"
android:layout_alignParentEnd="true"
android:src="@drawable/search_black"/>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewpager2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="54dp"
android:layout_below="@id/textview_wallpaper" />
<TableLayout
android:id="@+id/tab_layout"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp">
<TextView
android:id="@+id/tab_home"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_margin="4dp"
android:layout_weight="1"
android:background="@drawable/bg_purple_round"
android:gravity="center"
android:padding="6dp"
android:textColor="@android:color/black" />
<TextView
android:id="@+id/tab_like"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_margin="4dp"
android:layout_weight="1"
android:background="@drawable/bg_purple_round"
android:gravity="center"
android:padding="6dp"
android:textColor="@android:color/black" />
<TextView
android:id="@+id/tab_setting"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_margin="4dp"
android:layout_weight="1"
android:background="@drawable/bg_purple_round"
android:gravity="center"
android:padding="6dp"
android:textColor="@android:color/black" />
</TableRow>
</TableLayout>
</RelativeLayout>

View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp"
android:id="@+id/dialog_rate_us"
android:background="@drawable/dialog"
android:backgroundTint="#FFFFFF"
>
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Rate Us"
android:textStyle="italic"
android:textSize="18sp"
android:textColor="@android:color/black"
android:layout_marginBottom="12dp"/>
<TextView
android:id="@+id/tv_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="We hope that this app is useful for you. If it does, would you provide us a 5-star rating ? It really helps!"
android:textSize="14sp"
android:textStyle="italic"
android:textColor="@android:color/darker_gray"
android:layout_marginBottom="16dp"/>
<LinearLayout
android:id="@+id/ll_stars"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center"
android:layout_marginBottom="24dp">
<ImageView
android:id="@+id/iv_star1"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/star_unselected"
android:padding="4dp"/>
<ImageView
android:id="@+id/iv_star2"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/star_unselected"
android:padding="4dp"/>
<ImageView
android:id="@+id/iv_star3"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/star_unselected"
android:padding="4dp"/>
<ImageView
android:id="@+id/iv_star4"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/star_unselected"
android:padding="4dp"/>
<ImageView
android:id="@+id/iv_star5"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/star_unselected"
android:padding="4dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<Button
android:id="@+id/btn_cancel"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:text="CANCEL"
android:textSize="14sp"
android:backgroundTint="@color/gray_100"
android:textColor="@android:color/black"
android:layout_marginRight="24dp"/>
<Button
android:id="@+id/btn_rate"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:text="RATE IT"
android:textSize="14sp"
android:backgroundTint="@color/blue_standard"
android:textColor="@android:color/white"/>
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="40dp"
android:background="@drawable/tab_selected"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:padding="8dp"
android:gravity="center_vertical">
<ImageView
android:id="@+id/iv_back"
android:layout_width="18dp"
android:layout_height="18dp"
android:src="@drawable/black_back"
android:clickable="true"
android:focusable="true"
android:layout_marginRight="16dp"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="Recently Viewed Wallpapers"
android:textStyle="italic"
android:textSize="17sp"/>
<TextView
android:id="@+id/tv_clear_all"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginEnd="10dp"
android:background="@drawable/clean"
android:clickable="true"
android:focusable="true"/>
</LinearLayout>
<FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

View File

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/tab_selected"
android:paddingTop="30dp">
<ImageView
android:id="@+id/imageview_back"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_gravity="center"
android:background="@drawable/oval"
android:padding="13dp"
android:layout_marginStart="7dp"
android:layout_alignTop="@id/title"
android:src="@drawable/black_back"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.snap.wall.mytool.Mytext
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:padding="10dp"
android:layout_marginTop="12dp"
android:text="@string/app_name"
android:textColor="@color/black"
android:textSize="17sp"
app:apply_font="true" />
<RelativeLayout
android:id="@+id/et_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:layout_marginStart="15dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="5dp"
android:layout_toStartOf="@id/btn_search"
android:background="@drawable/re_stoke_16">
<EditText
android:id="@+id/et"
android:layout_width="match_parent"
android:layout_height="41dp"
android:background="@color/color_0"
android:hint="@string/please_input_keyword"
android:imeOptions="actionSearch"
android:inputType="text"
android:maxLines="1"
android:paddingStart="11dp"
android:paddingEnd="10dp"
android:textColorHint="@color/sub_title_color"
android:textSize="16sp" />
</RelativeLayout>
<ImageView
android:id="@+id/btn_search"
android:layout_width="55dp"
android:layout_height="wrap_content"
android:layout_alignTop="@id/et_parent"
android:layout_alignBottom="@id/et_parent"
android:layout_alignParentEnd="true"
android:layout_marginEnd="10dp"
android:paddingStart="15dp"
android:paddingTop="6dp"
android:paddingEnd="15dp"
android:paddingBottom="6dp"
android:src="@drawable/search_white" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/result_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/et_parent"
android:layout_marginTop="10dp" />
<LinearLayout
android:id="@+id/empty_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/empty_result" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/no_search_result"
android:textColor="@color/sub_title_color" />
</LinearLayout>
<ProgressBar
android:id="@+id/search_pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminateTint="@color/color_FEA7F5"
android:visibility="gone" />
</RelativeLayout>

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/tab_selected"
android:paddingTop="40dp"
tools:context="com.snap.wall.activity.TabActivity">
<ImageView
android:id="@+id/imageview_back"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_gravity="center"
android:layout_marginTop="12dp"
android:background="@drawable/oval"
android:padding="13dp"
android:src="@drawable/black_back"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.snap.wall.mytool.Mytext
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/imageview_back"
android:layout_alignBottom="@id/imageview_back"
android:layout_centerHorizontal="true"
android:gravity="center"
android:text="@string/app_name"
android:textColor="@color/black"
android:textSize="17sp"
app:apply_font="true" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:layout_below="@id/imageview_back" />
</RelativeLayout>

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<LinearLayout
android:id="@+id/layout_no_data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical"
android:visibility="gone">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/no_ata" />
<TextView
android:id="@+id/tv_title"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:gravity="center"
android:lineSpacingExtra="4dp"
android:text="@string/no_like_data"
android:textColor="@color/sub_title_color"
android:textSize="14sp" />
</LinearLayout>
</RelativeLayout>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.snap.wall.fragment.FragmentPrimary">
<!-- 关键ProgressBar 的 id 必须是 loading_pb -->
<ProgressBar
android:id="@+id/loading_pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"/>
<!-- RecyclerView 的 id 必须是 class_recycler -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/class_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:padding="10dp" />
</RelativeLayout>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/tv_empty"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="暂无最近浏览记录"
android:textSize="16sp"
android:textColor="#999999"
android:gravity="center"
android:layout_marginTop="50dp"
android:visibility="gone"/>
<GridView
android:id="@+id/gv_recent_wallpapers"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="2"
android:horizontalSpacing="2dp"
android:verticalSpacing="2dp"
android:stretchMode="columnWidth"/>
</LinearLayout>

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
android:gravity="top">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="32dp"
android:layout_marginTop="40dp">
<androidx.cardview.widget.CardView
android:id="@+id/app_icon"
android:layout_width="100dp"
android:layout_height="100dp"
app:cardCornerRadius="20dp"
app:cardElevation="0dp"
app:cardPreventCornerOverlap="false">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/logo_snap"
android:scaleType="centerCrop" />
</androidx.cardview.widget.CardView>
<TextView
android:id="@+id/tv_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="v1.0.0"
android:textColor="@color/white"
android:textSize="14sp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp" />
</LinearLayout>
<!-- 评分选项 -->
<LinearLayout
android:id="@+id/ll_rate_us"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@drawable/tab_selected_bg"
android:padding="16dp"
android:gravity="center_vertical"
android:layout_marginTop="15dp">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/star_one"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Rate us"
android:textStyle="italic"
android:textColor="@color/sub_title_color"
android:textSize="16sp"
android:layout_marginStart="16dp" />
<Button
android:id="@+id/tv_rate_us"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="@drawable/arrow_right"
android:padding="8dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="0dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_category"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@drawable/item_round_bg"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:id="@+id/tv_category_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:textColor="@color/white"
android:textSize="16sp"
android:shadowColor="@color/black"
android:shadowRadius="2"
android:shadowDx="1"
android:shadowDy="1"
app:layout_constraintBottom_toBottomOf="@id/iv_category"
app:layout_constraintStart_toStartOf="@id/iv_category"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/wallpaper"
android:layout_width="match_parent"
android:layout_height="100dp" />
<View
android:id="@+id/space_view"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_below="@id/wallpaper" />
</RelativeLayout>

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- 核心修改外层RelativeLayout限制宽高比为1:1 -->
<RelativeLayout
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:padding="2dp"> <!-- 可选:增加内边距避免圆角被遮挡 -->
<!-- 关键通过layout_alignParentXXX强制ImageView填充1:1的父容器 -->
<ImageView
android:id="@+id/wallpaper"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:scaleType="centerCrop"
android:adjustViewBounds="false" /> <!-- 关闭自适应,强制填充父容器 -->
</RelativeLayout>
<!-- 底部间距View保持不变 -->
<View
android:id="@+id/space_view"
android:layout_width="match_parent"
android:layout_height="22dp"
android:layout_below="@id/layout"
android:visibility="gone" />
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:visibility="invisible"
android:layout_alignTop="@id/layout"
android:layout_alignBottom="@id/layout" />
</RelativeLayout>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="0dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_category"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@drawable/item_round_bg"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:id="@+id/tv_category_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:textColor="@color/white"
android:textSize="16sp"
android:shadowColor="@color/black"
android:shadowRadius="2"
android:shadowDx="1"
android:shadowDy="1"
app:layout_constraintBottom_toBottomOf="@id/iv_category"
app:layout_constraintStart_toStartOf="@id/iv_category"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/wallpaper"
android:layout_width="match_parent"
android:layout_height="100dp" />
<View
android:id="@+id/space_view"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_below="@id/wallpaper" />
</RelativeLayout>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
app:cardCornerRadius="12dp"
app:cardElevation="0dp"
app:cardPreventCornerOverlap="true"
app:cardUseCompatPadding="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv_wallpaper"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>

View File

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp"
android:background="@drawable/re19"
android:orientation="vertical">
<LinearLayout
android:id="@+id/layout_home"
android:layout_width="match_parent"
android:layout_height="54dp"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/dialog_ho" />
<TextView
android:id="@+id/home"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginStart="21dp"
android:text="@string/type_home"
android:textColor="@color/white"
android:textSize="18sp" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginStart="25dp"
android:layout_marginEnd="25dp"
android:background="@color/white" />
<LinearLayout
android:id="@+id/layout_lock"
android:layout_width="match_parent"
android:layout_height="54dp"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/lock" />
<TextView
android:id="@+id/lock"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginStart="22dp"
android:text="@string/type_lock"
android:textColor="@color/white"
android:textSize="18sp" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginStart="25dp"
android:layout_marginEnd="25dp"
android:background="@color/white" />
<LinearLayout
android:id="@+id/layout_both"
android:layout_width="match_parent"
android:layout_height="54dp"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/dialog_bo" />
<TextView
android:id="@+id/both"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginStart="22dp"
android:text="@string/type_both"
android:textColor="@color/white"
android:textSize="18sp" />
</LinearLayout>
</LinearLayout>
</FrameLayout>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/logo_snap_background"/>
<foreground android:drawable="@mipmap/logo_snap_foreground"/>
</adaptive-icon>

Some files were not shown because too many files have changed in this diff Show More