This commit is contained in:
litingting 2025-09-02 10:14:26 +08:00
commit 3eb0aadb57
121 changed files with 169163 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

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

@ -0,0 +1,73 @@
import java.text.SimpleDateFormat
import java.util.Date
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
id("kotlin-kapt")
id("kotlin-parcelize")
}
val timeStamp: String = SimpleDateFormat("MM_dd_HH_mm").format(Date())
android {
namespace = "com.apps.pixwall"
compileSdk = 35
defaultConfig {
applicationId = "com.apps.pixwall"
minSdk = 24
targetSdk = 35
versionCode = 1
versionName = "1.0"
setProperty(
"archivesBaseName",
"Pix Wall_V" + versionName + "(${versionCode})_$timeStamp"
)
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
kotlinOptions {
jvmTarget = "21"
}
buildFeatures{
viewBinding=true
}
}
dependencies {
implementation(libs.appcompat)
implementation(libs.material)
implementation(libs.activity)
implementation(libs.constraintlayout)
implementation(libs.annotation)
implementation(libs.lifecycle.livedata.ktx)
implementation(libs.lifecycle.viewmodel.ktx)
implementation(libs.androidx.navigation.fragment.ktx)
implementation(libs.androidx.navigation.ui.ktx)
testImplementation(libs.junit)
androidTestImplementation(libs.ext.junit)
androidTestImplementation(libs.espresso.core)
implementation(libs.room.runtime)
kapt (libs.androidx.room.compiler)
implementation(libs.androidx.room.ktx)
implementation(libs.androidx.lifecycle.viewmodel.ktx.v262)
implementation(libs.androidx.lifecycle.livedata.ktx.v262)
implementation(libs.androidx.activity.ktx) // 可选,简化 ViewModel 获取
implementation(libs.glide)
implementation(libs.okhttp)
}

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

@ -0,0 +1,21 @@
# 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

View File

@ -0,0 +1,26 @@
package com.apps.pixwall;
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.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.apps.pixwall", appContext.getPackageName());
}
}

View File

@ -0,0 +1,46 @@
<?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.INTERNET" />
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<application
android:name=".IApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="@style/Theme.PixWall.Activity"
tools:targetApi="31">
<activity
android:name=".view.MorePaperActivity"
android:exported="false" />
<activity
android:name=".view.LoadActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".view.SearchActivity"
android:exported="false" />
<activity
android:name=".view.MainActivity"
android:exported="false" />
<activity
android:name=".view.PaperActivity"
android:theme="@style/Theme.PixWall.Main"
android:exported="false" />
</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.

After

Width:  |  Height:  |  Size: 229 KiB

View File

@ -0,0 +1,76 @@
package com.apps.pixwall
import android.app.Application
import android.util.Log
import com.apps.pixwall.data.AppDataBase
import com.apps.pixwall.data.PaperDao
import com.apps.pixwall.util.ConvertUtil
import java.io.IOException
class IApplication : Application() {
private val animaLs = "Animals.json"
private val experiment = "Experimental.json"
private val film = "Film.json"
private val nature = "Nature.json"
private val patterns = "Patterns.json"
private val street = "Street.json"
private val travel = "Travel.json"
private val wallpaper = "Featured.json"
companion object {
var categoryList: MutableList<String> = mutableListOf()
var isDataInitialized = false
private set
}
override fun onCreate() {
super.onCreate()
val database = AppDataBase.getDatabase(this)
val paperDao = database.paperDao()
Thread {
initializeData(paperDao)
isDataInitialized = true
}.start()
}
private fun initializeData(paperDao: PaperDao) {
val names = arrayOf(animaLs, travel, experiment, film, nature, patterns, street, wallpaper)
val startTime = System.currentTimeMillis()
for (name in names) {
try {
// 在后台线程读取文件
val inputStream = assets.open(name)
val jsonData = ConvertUtil.getConvert(inputStream)
Log.d("DataInit", "Loaded JSON for $name")
if (jsonData.isNotEmpty()) {
val categoryName = name.substring(0, name.indexOf("."))
// 同步添加分类名称(线程安全)
synchronized(categoryList) {
categoryList.add(categoryName)
}
// 解析数据
val papers = ConvertUtil.getData(jsonData, categoryName)
// 批量插入数据
if (papers.isNotEmpty()) {
// 使用批量插入方法
paperDao.insertAll(papers)
Log.d("DataInit", "[$categoryName] insert ${papers.size} data")
}
}
} catch (e: IOException) {
Log.e("DataInit", " $name error", e)
}
}
val duration = System.currentTimeMillis() - startTime
Log.d("DataInit", "use time: ${duration}ms")
}
}

View File

@ -0,0 +1,58 @@
package com.apps.pixwall.adapter
import android.annotation.SuppressLint
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.apps.pixwall.R
import com.apps.pixwall.data.Paper
import com.apps.pixwall.databinding.ItemDoubleLineBinding
import com.apps.pixwall.listener.MainInListener
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.request.RequestOptions
class DoubleLineAdapter: RecyclerView.Adapter<DoubleLineAdapter.DoubleViewHolder>() {
private lateinit var context:Context
private var list:List<Paper> = emptyList()
private lateinit var listener:MainInListener
class DoubleViewHolder(val binding:ItemDoubleLineBinding): RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DoubleViewHolder {
context=parent.context
val binding=ItemDoubleLineBinding.inflate(LayoutInflater.from(context),parent,false)
return DoubleViewHolder(binding)
}
fun setList(list: List<Paper>){
this.list=list
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: DoubleViewHolder, position: Int) {
val item= list[position]
val previewUrl200 = item.previewUrl200
val previewUrl400 = item.previewUrl400
holder.binding.text.text=item.description
Glide.with(context).load(previewUrl400).placeholder(R.mipmap.bg_placeholder)
.error(R.mipmap.bg_placeholder).thumbnail(
Glide.with(context)
.asDrawable()
.load(previewUrl200)
.apply(
RequestOptions()
.format(DecodeFormat.PREFER_RGB_565)
)
.placeholder(R.mipmap.bg_placeholder)
.centerCrop()
).into(holder.binding.img)
holder.binding.img.setOnClickListener {
listener.inItemClick(item)
}
}
fun setListener(listener: MainInListener){
this.listener=listener
}
}

View File

@ -0,0 +1,61 @@
package com.apps.pixwall.adapter
import android.content.Context
import android.util.Log
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.apps.pixwall.R
import com.apps.pixwall.data.Paper
import com.apps.pixwall.databinding.ItemInBinding
import com.apps.pixwall.listener.MainInListener
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.request.RequestOptions
class MainInAdapter : RecyclerView.Adapter<MainInAdapter.MainInViewHolder>() {
private lateinit var context: Context
private var coverList: List<Paper> = mutableListOf()
private lateinit var listener: MainInListener
class MainInViewHolder(val binding: ItemInBinding) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainInViewHolder {
context = parent.context
val binding = ItemInBinding.inflate(LayoutInflater.from(parent.context), parent, false);
return MainInViewHolder(binding)
}
override fun getItemCount(): Int {
return coverList.size
}
override fun onBindViewHolder(holder: MainInViewHolder, position: Int) {
val previewUrl400 = coverList[position].previewUrl400
val previewUrl200 = coverList[position].previewUrl200
Log.d("MainInAdapter", "previewUrl400 is $previewUrl400 previewUrl200 is $previewUrl200")
Glide.with(context).load(previewUrl400).placeholder(R.mipmap.bg_placeholder)
.error(R.mipmap.bg_placeholder).thumbnail(
Glide.with(context)
.asDrawable()
.load(previewUrl200)
.apply(
RequestOptions()
.format(DecodeFormat.PREFER_RGB_565)
)
.placeholder(R.mipmap.bg_placeholder)
.centerCrop()
).into(holder.binding.inImage)
holder.binding.inImage.setOnClickListener {
listener.inItemClick(coverList[position])
}
}
fun setListener(listener: MainInListener) {
this.listener = listener
}
fun setCoverList(list: List<Paper>) {
this.coverList = list
}
}

View File

@ -0,0 +1,65 @@
package com.apps.pixwall.adapter
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.apps.pixwall.data.Paper
import com.apps.pixwall.databinding.ItemCategoryBinding
import com.apps.pixwall.listener.MainInListener
import com.apps.pixwall.listener.MainItemListener
import com.apps.pixwall.view.MainActivity
import com.apps.pixwall.view.PaperActivity
class MainOutAdapter : RecyclerView.Adapter<MainOutAdapter.CategoryViewHolder>(),MainInListener {
private var nameList:List<String> = mutableListOf()
private var coverAllList:List<List<Paper>> = mutableListOf()
private lateinit var context: Context
private lateinit var listener:MainItemListener
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CategoryViewHolder {
val binding=ItemCategoryBinding.inflate(LayoutInflater.from(parent.context),parent,false)
context=parent.context
return CategoryViewHolder(binding)
}
override fun onBindViewHolder(holder: CategoryViewHolder, position: Int) {
holder.binding.txTitle.text = nameList[position]
val adapter=MainInAdapter()
adapter.setCoverList(coverAllList[position])
adapter.setListener(this)
holder.binding.rvView.adapter=adapter
val linearLayoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
holder.binding.rvView.layoutManager=linearLayoutManager
holder.binding.rvView.setOnClickListener{
listener.more(nameList[position])
}
holder.binding.llView.setOnClickListener {
listener.more(nameList[position])
}
}
override fun getItemCount(): Int {
return nameList.size
}
fun setList(categoryList: MutableList<String>,list:List<List<Paper>>) {
this.nameList=categoryList
this.coverAllList=list
}
fun setListener(listener: MainItemListener){
this.listener=listener
}
class CategoryViewHolder(val binding: ItemCategoryBinding) : RecyclerView.ViewHolder(binding.root)
override fun inItemClick(paper: Paper) {
val intent=Intent(context,PaperActivity::class.java)
intent.putExtra(PaperActivity.paperKey,paper)
context.startActivity(intent)
}
}

View File

@ -0,0 +1,57 @@
package com.apps.pixwall.adapter
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.apps.pixwall.R
import com.apps.pixwall.data.Paper
import com.apps.pixwall.databinding.ItemThreeLineBinding
import com.apps.pixwall.listener.MainInListener
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.request.RequestOptions
class ThreeLineAdapter: RecyclerView.Adapter<ThreeLineAdapter.ThreeViewHolder>() {
private lateinit var context: Context
private var list:List<Paper> = emptyList()
private lateinit var listener: MainInListener
class ThreeViewHolder(val binding: ItemThreeLineBinding): RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ThreeViewHolder {
context=parent.context
val binding= ItemThreeLineBinding.inflate(LayoutInflater.from(context),parent,false)
return ThreeViewHolder(binding)
}
fun setList(list: List<Paper>){
this.list=list
}
override fun getItemCount(): Int {
return list.size
}
override fun onBindViewHolder(holder: ThreeViewHolder, position: Int) {
val item= list[position]
val previewUrl200 = item.previewUrl200
val previewUrl400 = item.previewUrl400
holder.binding.text.text=item.description
Glide.with(context).load(previewUrl400).placeholder(R.mipmap.bg_placeholder)
.error(R.mipmap.bg_placeholder).thumbnail(
Glide.with(context)
.asDrawable()
.load(previewUrl200)
.apply(
RequestOptions()
.format(DecodeFormat.PREFER_RGB_565)
)
.placeholder(R.mipmap.bg_placeholder)
.centerCrop()
).into(holder.binding.img)
holder.binding.img.setOnClickListener {
listener.inItemClick(item)
}
}
fun setListener(listener: MainInListener){
this.listener=listener
}
}

View File

@ -0,0 +1,23 @@
package com.apps.pixwall.data
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
@Database(entities = [Paper::class], version = 1, exportSchema = false)
abstract class AppDataBase:RoomDatabase() {
abstract fun paperDao():PaperDao
companion object{
@Volatile
private var INSTANCE:AppDataBase?=null
fun getDatabase(context:Context):AppDataBase{
return INSTANCE?: synchronized(this){
INSTANCE?:createDatabase(context).also { INSTANCE=it }
}
}
private fun createDatabase(context: Context):AppDataBase{
return Room.databaseBuilder(context.applicationContext,AppDataBase::class.java,"pixwall_database").fallbackToDestructiveMigration().build()
}
}
}

View File

@ -0,0 +1,147 @@
package com.apps.pixwall.data
import android.app.Application
import android.util.Log
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.apps.pixwall.IApplication
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
class MainViewModel(application: Application) : AndroidViewModel(application) {
private val repository: PaperRepository by lazy {
val dao = AppDataBase.getDatabase(application).paperDao()
PaperRepository(dao)
}
// 防抖控制
private var lastSearchTime = 0L
private var lastQuery: String? = null
private val searchDebounceTime = 500L
// LiveData 统一暴露
private val _paperResult = MutableLiveData<Paper?>() // id查询结果
val paperResult: LiveData<Paper?> get() = _paperResult
private val _categoryList = MutableLiveData<List<Paper>>(emptyList()) // 类别列表
val categoryList: LiveData<List<Paper>> get() = _categoryList
private val _coverMap = MutableLiveData<Map<String, List<Paper>>>(emptyMap()) // 封面分类映射
val coverMap: LiveData<Map<String, List<Paper>>> get() = _coverMap
private val _loadingState = MutableLiveData(false) // 加载状态
val loadingState: LiveData<Boolean> get() = _loadingState
private val _searchList = MutableLiveData<List<Paper>>(emptyList()) // 搜索结果
val searchList: LiveData<List<Paper>> get() = _searchList
private val _isLiked = MutableLiveData<Boolean?>() // 是否收藏
val isLiked: LiveData<Boolean?> get() = _isLiked
val likePapers: LiveData<List<Paper>> get() = repository.getLikes()
fun debugDatabase() {
viewModelScope.launch(Dispatchers.IO) {
try {
val papers = repository.allPaper()
Log.d("DB_DEBUG", "总记录数: ${papers.size}")
papers.take(5).forEach { paper ->
Log.d("DB_DEBUG", "Paper[${paper.id}]: " +
"cat=${paper.categoryName}, " +
"imId=${paper.imId}, " +
"desc=${paper.description.take(10)}...")
}
} catch (e: Exception) {
Log.e("DB_DEBUG", "查询失败", e)
}
}
}
fun updatePaper(paper: Paper) {
viewModelScope.launch(Dispatchers.IO) {
repository.updatePaper(paper)
}
}
fun getPaperResult(id: String) {
viewModelScope.launch(Dispatchers.IO) {
_paperResult.postValue(repository.getPaperById(id))
}
}
fun getCategoryList(name: String) {
viewModelScope.launch(Dispatchers.IO) {
_categoryList.postValue(repository.getPaperByCategory(name))
}
}
fun loadAllCategoryCovers() {
if (_loadingState.value == true) return
viewModelScope.launch(Dispatchers.IO) {
_loadingState.postValue(true)
val categoryList = IApplication.categoryList
val resultMap = mutableMapOf<String, List<Paper>>()
val deferredList = categoryList.map { category ->
async {
try {
category to repository.getCategoryCover(category)
} catch (e: Exception) {
Log.e("BatchLoad", "加载分类[$category]失败: ${e.message}")
category to emptyList<Paper>()
}
}
}
deferredList.awaitAll().forEach { (category, papers) ->
resultMap[category] = papers
}
_coverMap.postValue(resultMap)
_loadingState.postValue(false)
Log.d("BatchLoad", "所有分类封面数据加载完成")
}
}
fun getSearchList(query: String) {
val currentTime = System.currentTimeMillis()
if (query == lastQuery && (currentTime - lastSearchTime) < searchDebounceTime) {
return
}
lastQuery = query
lastSearchTime = currentTime
viewModelScope.launch(Dispatchers.IO) {
try {
_searchList.postValue(repository.searchByKey(query))
} catch (e: Exception) {
_searchList.postValue(emptyList())
Log.e("Search", "Search failed", e)
}
}
}
fun checkLike(id: String) {
viewModelScope.launch(Dispatchers.IO) {
_isLiked.postValue(repository.isLike(id))
}
}
fun setLike(paper: Paper) {
viewModelScope.launch(Dispatchers.IO) {
val updatePaper = paper.copy(isLike = !paper.isLike)
repository.updatePaper(updatePaper)
Log.d("setlike status",updatePaper.isLike.toString())
_isLiked.postValue(updatePaper.isLike)
}
}
}

View File

@ -0,0 +1,25 @@
package com.apps.pixwall.data
import android.os.Parcelable
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import kotlinx.parcelize.Parcelize
import java.io.Serializable
@Parcelize
@Entity(tableName = "papers",
indices = [Index(value = ["imId"], unique = true)])
data class Paper(
@PrimaryKey(autoGenerate = true) var id: Int = 0,
@ColumnInfo(name = "categoryName") var categoryName: String = "",
@ColumnInfo(name = "imId") var imId: String = "",
@ColumnInfo(name = "description") var description: String = "",
@ColumnInfo(name = "fullUrl") var fullUrl: String = "",
@ColumnInfo(name = "previewUrl1080") var previewUrl1080: String = "",
@ColumnInfo(name = "previewUrl400") var previewUrl400: String = "",
@ColumnInfo(name = "previewUrl200") var previewUrl200: String = "",
@ColumnInfo(name = "is_like") var isLike: Boolean = false,
@ColumnInfo(name = "isDownload") var isDownload: Boolean = false
):Parcelable

View File

@ -0,0 +1,40 @@
package com.apps.pixwall.data
import android.graphics.Picture
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
@Dao
interface PaperDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insertAll(papers: List<Paper>)
@Update
suspend fun update(paper: Paper)
@Query("SELECT * FROM papers WHERE imId=:imId")
suspend fun getById(imId: String): Paper?
@Query("SELECT * FROM papers WHERE categoryName=:name LIMIT 4 OFFSET 6")
suspend fun queryCover(name: String): List<Paper>
@Query("SELECT * FROM papers WHERE categoryName=:name")
suspend fun queryEachGenera(name: String): List<Paper>
@Query("SELECT * FROM papers WHERE is_like = 1")
fun queryLikePaper(): LiveData<List<Paper>>
@Query("SELECT * FROM papers WHERE description LIKE '%'||:name||'%'")
suspend fun search(name: String): List<Paper>
@Query("SELECT * FROM papers WHERE imId = :imId AND is_like = 1")
suspend fun queryIsLike(imId: String): Paper?
@Query("SELECT * FROM papers")
suspend fun getAllPapers(): List<Paper>
}

View File

@ -0,0 +1,31 @@
package com.apps.pixwall.data
import androidx.lifecycle.LiveData
class PaperRepository(private val paperDao: PaperDao) {
suspend fun allPaper():List<Paper>{
return paperDao.getAllPapers()
}
// suspend fun insertPaper(paper: Paper){
// paperDao.insert(paper)
// }
suspend fun updatePaper(paper: Paper){
paperDao.update(paper)
}
suspend fun getPaperById(id:String):Paper?{
return paperDao.getById(id)
}
suspend fun getCategoryCover(name:String):List<Paper>{
return paperDao.queryCover(name)
}
suspend fun getPaperByCategory(name: String):List<Paper>{
return paperDao.queryEachGenera(name)
}
fun getLikes():LiveData<List<Paper>>{
return paperDao.queryLikePaper()
}
suspend fun searchByKey(key:String):List<Paper>{
return paperDao.search(key)
}
suspend fun isLike(id: String): Boolean = paperDao.queryIsLike(id) != null
}

View File

@ -0,0 +1,7 @@
package com.apps.pixwall.listener
import com.apps.pixwall.data.Paper
interface MainInListener {
fun inItemClick(paper:Paper)
}

View File

@ -0,0 +1,5 @@
package com.apps.pixwall.listener
interface MainItemListener {
fun more(name:String)
}

View File

@ -0,0 +1,5 @@
package com.apps.pixwall.listener
interface ShowDialogListener {
fun onClick(type:Int)
}

View File

@ -0,0 +1,132 @@
package com.apps.pixwall.util
import android.content.ContentValues
import android.content.Context
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import android.util.Log
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.util.logging.Logger
object ConnectUtil {
private val LOGGER = Logger.getLogger(ConnectUtil::class.java.name)
interface ConnectCallBack {
fun onResult(success: Boolean, inputStream: InputStream?)
}
fun downloadFile(url: String, savePath: String, callback: ConnectCallBack): Call {
val client = OkHttpClient()
val request = Request.Builder().url(url).build()
val call = client.newCall(request)
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
LOGGER.severe("Download failed: ${e.message}")
callback.onResult(false, null)
}
override fun onResponse(call: Call, response: Response) {
response.use {
try {
val responseBody = response.body
if (responseBody != null) {
val inputStream = responseBody.byteStream()
val writeSuccess = writeFile(inputStream, savePath)
callback.onResult(writeSuccess, inputStream)
} else {
LOGGER.warning("Empty response body")
callback.onResult(false, null)
}
} catch (e: Exception) {
LOGGER.severe("Error processing response: ${e.message}")
callback.onResult(false, null)
}
}
}
})
return call
}
private fun writeFile(inputStream: InputStream, filePath: String): Boolean {
val file = File(filePath)
return try {
file.parentFile?.takeIf { !it.exists() }?.mkdirs()
FileOutputStream(file).use { fos ->
val buffer = ByteArray(4096)
var bytesRead: Int
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
fos.write(buffer, 0, bytesRead)
}
true
}
} catch (e: Exception) {
LOGGER.severe("File write error: ${e.message}")
false
}
}
fun saveToGallery(context: Context, file: File): Uri? {
val name = "${System.currentTimeMillis()}.jpg"
val contentValues = ContentValues().apply {
put(MediaStore.Images.Media.DISPLAY_NAME, name)
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 uri = 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 contentResolver = context.contentResolver
val imgUri = contentResolver.insert(uri, contentValues) ?: run {
Log.d("MediaSaver", "Failed to create media entry")
return null
}
try {
contentResolver.openOutputStream(imgUri)?.use { outputStream ->
FileInputStream(file).use { inputStream ->
val buffer = ByteArray(4026)
var byteRead: Int
while (inputStream.read(buffer).also { byteRead = it } != -1) {
outputStream.write(buffer, 0, byteRead)
}
}
}?:run {
Log.d("MediaSaver", "Failed to open output stream")
return null
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
contentValues.clear()
contentValues.put(MediaStore.Images.Media.IS_PENDING, 0)
contentResolver.update(imgUri, contentValues, null, null)
}
return imgUri
} catch (e: IOException) {
Log.e("MediaSaver", "Error saving image to gallery", e)
// 发生错误时删除创建的文件记录
try {
contentResolver.delete(imgUri, null, null)
} catch (deleteEx: Exception) {
Log.e("MediaSaver", "Failed to delete failed media entry", deleteEx)
}
return null
}
}
}

View File

@ -0,0 +1,105 @@
package com.apps.pixwall.util
import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.apps.pixwall.data.Paper
import org.json.JSONArray
import org.json.JSONObject
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStream
import java.io.InputStreamReader
import java.io.Reader
import java.nio.charset.StandardCharsets
object ConvertUtil {
fun getConvert(inputStream: InputStream): String {
var stringStr = ""
try {
val stringBuilder: StringBuilder = StringBuilder()
val buffer = CharArray(8192)
val reader: Reader =
BufferedReader(InputStreamReader(inputStream, StandardCharsets.UTF_8))
var byteRead: Int
while (reader.read(buffer).also { byteRead = it } != -1) {
stringBuilder.appendRange(buffer, 0, byteRead)
}
stringStr = stringBuilder.toString()
} catch (e: IOException) {
return stringStr
}
return stringStr
}
fun getData(data: String, name: String):List<Paper> {
val jsonArray = JSONArray(data)
val paperList = mutableListOf<Paper>()
var eachItem: JSONObject
var _description: String
var links: JSONObject
var download: String
var urls: JSONObject
var regular: String
var small: String
var thumb: String
val host = "https://unsplash.com/photos/"
var paper: Paper
var mid: String
for (i in 0 until jsonArray.length()) {
eachItem = jsonArray.getJSONObject(i)
_description = eachItem.getString("alt_description")
links = eachItem.getJSONObject("links")
download = links.getString("download")
urls = eachItem.getJSONObject("urls")
regular = urls.getString("regular")
small = urls.getString("small")
thumb = urls.getString("thumb")
mid = download.substring(host.length, download.indexOf("/download"))
paper = Paper().apply {
imId = mid
categoryName = name
description = _description
fullUrl = download
previewUrl1080 = regular
previewUrl400 = small
previewUrl200 = thumb
}
paperList.add(paper)
}
return paperList
}
fun getSaveFilePath(context: Context, imId: String): String {
return "${context.cacheDir}/${imId}.jpg"
}
fun checkPermission(context: Context,permissions:Array<String>):Boolean{
return permissions.all {
ContextCompat.checkSelfPermission(context,it)==PackageManager.PERMISSION_GRANTED
}
}
fun getStoragePermissions(): Array<String> {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
arrayOf(Manifest.permission.READ_MEDIA_IMAGES)
} else {
arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
}
}
fun hasStoragePermission(context: Context): Boolean {
return getStoragePermissions().all { permission ->
ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED
}
}
}

View File

@ -0,0 +1,90 @@
package com.apps.pixwall.view
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.apps.pixwall.IApplication
import com.apps.pixwall.adapter.MainOutAdapter
import com.apps.pixwall.data.MainViewModel
import com.apps.pixwall.data.Paper
import com.apps.pixwall.databinding.FragmentCategoryBinding
import com.apps.pixwall.listener.MainItemListener
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
class CategoryFragment : Fragment(),MainItemListener {
private lateinit var binding:FragmentCategoryBinding
private lateinit var viewModel:MainViewModel
private lateinit var adapter: MainOutAdapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding=FragmentCategoryBinding.inflate(inflater,container,false)
init()
return binding.root
}
private fun init(){
viewModel = ViewModelProvider(requireActivity())[MainViewModel::class.java]
adapter=MainOutAdapter()
adapter.setListener(this)
binding.rvView.adapter = adapter
binding.rvView.layoutManager = LinearLayoutManager(requireContext())
viewModel.coverMap.value?.takeIf { it.isNotEmpty() }?.let {
Log.d("DataLoad", "hasLoad")
updateAdapter()
}
viewModel.loadAllCategoryCovers()
viewModel.loadingState.observe(viewLifecycleOwner) { isLoading ->
viewModel.coverMap.value?.let { coverMap ->
if (!isLoading && coverMap.isNotEmpty()) {
updateAdapter()
}
}
}
viewModel.coverMap.observe(viewLifecycleOwner) { coverMap ->
viewModel.loadingState.value?.let { isLoading ->
if (!isLoading && coverMap.isNotEmpty()) {
updateAdapter()
}
}
}
}
private fun updateAdapter() {
val categoryList = IApplication.categoryList
val coverMap = viewModel.coverMap.value
// 确保数据一致性
val coversForCategories = categoryList.map { categoryName ->
coverMap?.get(categoryName) ?: emptyList()
}
adapter.setList(categoryList, coversForCategories)
adapter.notifyDataSetChanged()
Log.d("AdapterUpdate", "refresh data")
categoryList.forEachIndexed { index, category ->
val count = coversForCategories[index].size
Log.d("DataDebug", "[$index] $category: $count data")
}
}
override fun more(name: String) {
val intent=Intent(requireActivity(),MorePaperActivity::class.java)
intent.putExtra(MorePaperActivity.titleName,name)
startActivity(intent)
}
}

View File

@ -0,0 +1,58 @@
package com.apps.pixwall.view
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.GridLayoutManager
import com.apps.pixwall.R
import com.apps.pixwall.adapter.ThreeLineAdapter
import com.apps.pixwall.data.MainViewModel
import com.apps.pixwall.data.Paper
import com.apps.pixwall.databinding.FragmentFavoriteBinding
import com.apps.pixwall.listener.MainInListener
class FavoriteFragment : Fragment(),MainInListener {
private lateinit var binding: FragmentFavoriteBinding
private lateinit var viewModel: MainViewModel
private lateinit var adapter:ThreeLineAdapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding=FragmentFavoriteBinding.inflate(inflater,container,false)
init()
return binding.root
}
private fun init(){
viewModel=ViewModelProvider(requireActivity())[MainViewModel::class.java]
adapter=ThreeLineAdapter()
adapter.setListener(this)
viewModel.likePapers.observe(viewLifecycleOwner) { papers ->
Log.d("FavoriteFragment","paper is$papers")
if (papers.isNullOrEmpty()) {
// 可以在这里显示空状态视图
binding.layoutNoData.visibility = View.VISIBLE
binding.rvView.visibility = View.GONE
} else {
binding.layoutNoData.visibility = View.GONE
binding.rvView.visibility = View.VISIBLE
adapter.setList(papers)
adapter.notifyDataSetChanged()
}
}
val gridLayoutManager = GridLayoutManager(requireActivity(), 3)
binding.rvView.layoutManager=gridLayoutManager
binding.rvView.adapter=adapter
}
override fun inItemClick(paper: Paper) {
val intent= Intent(context,PaperActivity::class.java)
intent.putExtra(PaperActivity.paperKey,paper)
startActivity(intent)
}
}

View File

@ -0,0 +1,47 @@
package com.apps.pixwall.view
import android.content.Intent
import android.os.Bundle
import android.os.CountDownTimer
import android.os.Handler
import androidx.appcompat.app.AppCompatActivity
import com.apps.pixwall.databinding.ActivityLoadBinding
class LoadActivity : AppCompatActivity() {
lateinit var binding: ActivityLoadBinding
private var handler: Handler = Handler()
private var countDownTimer: CountDownTimer? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityLoadBinding.inflate(layoutInflater)
setContentView(binding.root)
handler.postDelayed({
val intent= Intent(
this@LoadActivity,
MainActivity::class.java
)
startActivity(intent)
finish()
}, 4000)
countDownTimer = object : CountDownTimer(4000, 100) {
override fun onTick(millisUntilFinished: Long) {
val progress = ((4000 - millisUntilFinished) / 4000f * 100).toInt()
binding.progressbar.progress = progress
}
override fun onFinish() {
binding.progressbar.progress = 100
}
}.start()
}
override fun onDestroy() {
super.onDestroy()
handler.removeCallbacksAndMessages(null)
if (countDownTimer != null) {
countDownTimer!!.cancel()
}
}
}

View File

@ -0,0 +1,112 @@
package com.apps.pixwall.view
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.apps.pixwall.R
import com.apps.pixwall.data.MainViewModel
import com.apps.pixwall.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var isFragmentTransitionRunning = false
private var lastClickTime = 0L
private val CLICK_THROTTLE = 300L
private lateinit var categoryFragment: Fragment
private lateinit var favoriteFragment: Fragment
private lateinit var mainViewModel: MainViewModel
private var currentFragment: Fragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
mainViewModel = ViewModelProvider(this)[MainViewModel::class.java]
initFragments()
// mainViewModel.debugDatabase()
initViews()
}
private fun updateTab(position: Int) {
binding.imgHome.isSelected = false
binding.imgLike.isSelected = false
val defaultColor = getColor(R.color.grey)
val selectColor = getColor(R.color.dark_purple)
binding.tvStart.setTextColor(defaultColor)
binding.tvEnd.setTextColor(defaultColor)
when (position) {
0 -> {
binding.imgHome.isSelected = true
binding.tvStart.setTextColor(selectColor)
}
1 -> {
binding.imgLike.isSelected = true
binding.tvEnd.setTextColor(selectColor)
}
}
}
private fun initFragments() {
categoryFragment = CategoryFragment()
favoriteFragment = FavoriteFragment()
}
private fun initViews() {
switchFragment(0)
binding.llHome.setOnClickListener {
if (System.currentTimeMillis() - lastClickTime > CLICK_THROTTLE) {
switchFragment(0)
lastClickTime = System.currentTimeMillis()
}
}
binding.llLike.setOnClickListener {
if (System.currentTimeMillis() - lastClickTime > CLICK_THROTTLE) {
switchFragment(1)
lastClickTime = System.currentTimeMillis()
}
}
binding.rlSearch.setOnClickListener {
startActivity(Intent(this, SearchActivity::class.java))
}
}
private fun switchFragment(position: Int) {
if (isFragmentTransitionRunning) return
var targetFragment = when (position) {
0 -> {
if (currentFragment is CategoryFragment) return
categoryFragment
}
1 -> {
if (currentFragment is FavoriteFragment) return
favoriteFragment
}
else -> null
}
if (targetFragment == null || binding.fragmentIn.id == View.NO_ID) return
updateTab(position)
isFragmentTransitionRunning = true
supportFragmentManager.beginTransaction().apply {
setCustomAnimations(
android.R.anim.fade_in,
android.R.anim.fade_out
)
if (targetFragment.isAdded) {
show(targetFragment)
} else {
add(binding.fragmentIn.id, targetFragment)
}
currentFragment?.takeIf { it.isAdded }?.let { hide(it) }
currentFragment = targetFragment
commit()
supportFragmentManager.executePendingTransactions()
isFragmentTransitionRunning = false
}
}
}

View File

@ -0,0 +1,66 @@
package com.apps.pixwall.view
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.GridLayoutManager
import com.apps.pixwall.adapter.DoubleLineAdapter
import com.apps.pixwall.data.MainViewModel
import com.apps.pixwall.data.Paper
import com.apps.pixwall.databinding.ActivityMorePaperBinding
import com.apps.pixwall.listener.MainInListener
class MorePaperActivity : AppCompatActivity(),MainInListener {
private lateinit var binding:ActivityMorePaperBinding
private lateinit var viewModel: MainViewModel
private lateinit var adapter:DoubleLineAdapter
companion object{
var titleName:String="name"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding=ActivityMorePaperBinding.inflate(layoutInflater)
init()
setContentView(binding.root)
}
private fun init(){
viewModel=ViewModelProvider(this)[MainViewModel::class.java]
titleName= intent.getStringExtra(titleName)!!
binding.name.text= titleName
binding.searchPb.visibility= View.VISIBLE
binding.imageBack.setOnClickListener { finish() }
adapter=DoubleLineAdapter()
adapter.setListener(this)
binding.list.layoutManager=GridLayoutManager(this,2)
binding.list.adapter=adapter
viewModel.categoryList.observe(this) { list ->
// 在这里处理返回的数据
if(list.isNotEmpty()){
updateUI(list)
}
}
if(viewModel.categoryList.value.isNullOrEmpty()){
Log.d("Therererer","startGet")
viewModel.getCategoryList(titleName)
}
}
private fun updateUI(list: List<Paper>){
Log.d("MorePaperActivity","list size is"+list.size.toString())
adapter.setList(list)
binding.searchPb.visibility= View.GONE
adapter.notifyDataSetChanged()
}
override fun inItemClick(paper: Paper) {
val intent= Intent(this,PaperActivity::class.java)
intent.putExtra(PaperActivity.paperKey,paper)
startActivity(intent)
}
}

View File

@ -0,0 +1,304 @@
package com.apps.pixwall.view
import android.app.WallpaperManager
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import com.apps.pixwall.R
import com.apps.pixwall.data.MainViewModel
import com.apps.pixwall.data.Paper
import com.apps.pixwall.databinding.ActivityPaperBinding
import com.apps.pixwall.listener.ShowDialogListener
import com.apps.pixwall.util.ConnectUtil
import com.apps.pixwall.util.ConvertUtil
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.request.RequestOptions
import okhttp3.Call
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
class PaperActivity : AppCompatActivity(), ShowDialogListener {
companion object {
var paperKey = "paper"
}
private lateinit var binding: ActivityPaperBinding
lateinit var paper: Paper
private lateinit var viewModel: MainViewModel
private var fullUrl = ""
private var mSavePath = ""
private lateinit var wallpaperManager: WallpaperManager
private lateinit var downloadFile: File
private var call: Call?=null
private var isGranted = false
private lateinit var setDialog: SelectDialogFragment
private var isSetting = false
private val storagePermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
if (permissions.all { it.value }) {
isGranted = true
} else {
Toast.makeText(this, getString(R.string.no_permit), Toast.LENGTH_SHORT).show()
}
}
private fun requestStoragePermission() {
val permissions = ConvertUtil.getStoragePermissions()
if (ConvertUtil.hasStoragePermission(this)) {
isGranted = true
} else {
storagePermissionLauncher.launch(permissions)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityPaperBinding.inflate(layoutInflater)
setContentView(binding.root)
init()
}
override fun onDestroy() {
super.onDestroy()
call?.let {
it.cancel()
}
deleteCacheFile()
}
private fun init() {
viewModel = ViewModelProvider(this)[MainViewModel::class.java]
paper = intent?.getParcelableExtra(paperKey)!!
fullUrl = paper.fullUrl
mSavePath = ConvertUtil.getSaveFilePath(this, paper.imId)
downloadFile = File(mSavePath)
setDialog = SelectDialogFragment()
setDialog.setListener(this@PaperActivity)
wallpaperManager = WallpaperManager.getInstance(this)
Glide.with(this)
.load(paper.previewUrl1080)
.apply(
RequestOptions()
.format(DecodeFormat.PREFER_RGB_565)
)
.skipMemoryCache(true)
.thumbnail(
Glide.with(this)
.load(paper.previewUrl400)
.apply(
RequestOptions()
.format(DecodeFormat.PREFER_RGB_565)
.centerCrop()
)
)
.into(binding.image)
binding.imageBack.setOnClickListener { finish() }
binding.tvContent.text = paper.description
viewModel.isLiked.observe(this) { b ->
Log.d("initb", b.toString())
if (b != null) {
binding.imageFavorite.isSelected = b
}
}
viewModel.checkLike(paper.imId)
binding.imageFavorite.setOnClickListener {
setLikeStatus()
}
binding.layoutDownload.setOnClickListener {
startDownload()
}
binding.layoutSet.setOnClickListener {
showSetDialog()
}
}
private fun showSetDialog() {
if (isSetting) return
if (!setDialog.isAdded) {
setDialog.show(supportFragmentManager, "")
}
}
private fun setLikeStatus() {
val b = !binding.imageFavorite.isSelected
binding.imageFavorite.isSelected = !b
paper.isLike = !b
viewModel.setLike(paper)
}
private fun startDownload() {
requestStoragePermission()
if (!isGranted) return
showDownloadLoading(true)
if (downloadFile.exists()) {
saveToGallery()
return
}
doDownload()
}
private fun saveToGallery() {
val uri: Uri? = ConnectUtil.saveToGallery(this, downloadFile)
runOnUiThread {
showDownloadLoading(false)
if (uri == null) {
Toast.makeText(
this@PaperActivity,
getString(R.string.save_fail),
Toast.LENGTH_SHORT
).show()
} else {
Toast.makeText(
this@PaperActivity,
getString(R.string.save_success),
Toast.LENGTH_SHORT
).show()
}
Log.d("YYYYYY", "--------path=" + downloadFile.getAbsolutePath() + "---uri=" + uri)
}
}
private fun doDownload() {
call = ConnectUtil.downloadFile(fullUrl, mSavePath, object : ConnectUtil.ConnectCallBack {
override fun onResult(success: Boolean, inputStream: InputStream?) {
val file = File(mSavePath)
if (file.exists() && success) {
downloadFile = file
saveToGallery()
} else {
runOnUiThread {
showDownloadLoading(false)
Toast.makeText(
this@PaperActivity,
getString(R.string.down_fail),
Toast.LENGTH_SHORT
).show()
}
}
}
})
}
private fun showDownloadLoading(show: Boolean) {
if (show) {
binding.pbDownload.visibility = View.VISIBLE
binding.imageDownload.visibility = View.GONE
} else {
binding.pbDownload.visibility = View.GONE
binding.imageDownload.visibility = View.VISIBLE
}
}
private fun deleteCacheFile() {
if (downloadFile.exists()) {
val delete = downloadFile.delete()
Log.d("YYYYYY", "--------delete=$delete")
}
}
override fun onClick(type: Int) {
showSetWallpaperLoading(true)
if (downloadFile.exists()) {
Thread {
Log.d("YYYYYY", "skip download and set")
setWallPaper(downloadFile, type)
}.start()
} else {
call =
ConnectUtil.downloadFile(fullUrl, mSavePath, object : ConnectUtil.ConnectCallBack {
override fun onResult(success: Boolean, inputStream: InputStream?) {
val file = File(mSavePath)
if (file.exists() && success) {
downloadFile = file
setWallPaper(downloadFile, type)
} else {
showDownloadLoading(false)
Toast.makeText(
this@PaperActivity,
getString(R.string.set_fail),
Toast.LENGTH_SHORT
).show()
}
}
})
}
}
private fun showSetWallpaperLoading(show: Boolean) {
Log.d("YYYYYY", "-----------showSetWallpaperLoading$show")
if (show) {
isSetting = true
binding.pbSet.visibility = View.VISIBLE
binding.txApply.visibility = View.GONE
binding.buttonSet.visibility = View.GONE
} else {
isSetting = false
binding.pbSet.visibility = View.GONE
binding.txApply.visibility = View.VISIBLE
binding.buttonSet.visibility = View.VISIBLE
}
}
private fun setWallPaper(file: File, type: Int) {
try {
FileInputStream(file).use { fileInputStream ->
when (type) {
SelectDialogFragment.TYPE_HOME -> {
// FLAG_SYSTEM 表示设置为主屏幕壁纸
wallpaperManager.setStream(
fileInputStream,
null,
true,
WallpaperManager.FLAG_SYSTEM
)
}
SelectDialogFragment.TYPE_LOCK -> {
// FLAG_LOCK 设置为锁屏壁纸
wallpaperManager.setStream(
fileInputStream,
null,
true,
WallpaperManager.FLAG_LOCK
)
}
SelectDialogFragment.TYPE_BOTH -> {
// 同时设置主屏和锁屏壁纸
wallpaperManager.setStream(fileInputStream)
}
else -> {}
}
}
runOnUiThread {
showSetWallpaperLoading(false)
Toast.makeText(
this@PaperActivity,
getString(R.string.set_success),
Toast.LENGTH_SHORT
).show()
}
} catch (e: Exception) {
runOnUiThread {
showSetWallpaperLoading(false)
Toast.makeText(
this@PaperActivity,
getString(R.string.set_fail),
Toast.LENGTH_SHORT
).show()
}
}
}
}

View File

@ -0,0 +1,124 @@
package com.apps.pixwall.view
import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.GridLayoutManager
import com.apps.pixwall.R
import com.apps.pixwall.adapter.DoubleLineAdapter
import com.apps.pixwall.data.MainViewModel
import com.apps.pixwall.data.Paper
import com.apps.pixwall.databinding.ActivitySearchBinding
import com.apps.pixwall.listener.MainInListener
class SearchActivity : AppCompatActivity(), MainInListener {
lateinit var binding: ActivitySearchBinding
private lateinit var viewModel: MainViewModel
private lateinit var adapter: DoubleLineAdapter
private var resultList: List<Paper> = emptyList()
private var searchKey = ""
private var isClick = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySearchBinding.inflate(layoutInflater)
setContentView(binding.root)
init()
}
private fun init() {
viewModel = ViewModelProvider(this)[MainViewModel::class.java]
adapter = DoubleLineAdapter()
adapter.setListener(this)
binding.list.adapter = adapter
binding.list.layoutManager = GridLayoutManager(this, 2)
binding.tvStart.setOnClickListener { startSearch() }
binding.imageBack.setOnClickListener { finish() }
binding.editText.requestFocus()
binding.editText.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_SEARCH || actionId == EditorInfo.IME_ACTION_DONE) {
startSearch()
return@setOnEditorActionListener true
}
false
}
viewModel.searchList.observe(this) { list ->
resultList = list
binding.searchPb.visibility = View.GONE
Log.d("SearchResult", "result list size${list.size}")
if (resultList.isNotEmpty()) {
showEmpty(false)
adapter.setList(resultList)
adapter.notifyDataSetChanged()
} else if (isClick) {
showEmpty(true)
}
}
binding.editText.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
searchKey = s.toString().trim()
if (searchKey.isNotEmpty()) {
binding.tvStart.visibility = View.VISIBLE
} else {
binding.tvStart.visibility = View.GONE
}
}
override fun afterTextChanged(s: Editable) {
}
})
}
private fun startSearch() {
closeKeyboard()
isClick = true
binding.searchPb.visibility = View.VISIBLE
if (searchKey.isNotEmpty()) {
Log.d("SearchStart", "searchKey is$searchKey")
viewModel.getSearchList(searchKey)
} else {
binding.searchPb.visibility = View.GONE
Toast.makeText(
this,
getString(R.string.please_enter),
Toast.LENGTH_SHORT
).show()
}
}
private fun showEmpty(showEmpty: Boolean) {
if (showEmpty) {
binding.emptyLayout.visibility = View.VISIBLE
binding.list.visibility = View.GONE
} else {
binding.emptyLayout.visibility = View.GONE
binding.list.visibility = View.VISIBLE
}
}
private fun closeKeyboard() {
val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as? InputMethodManager
val currentFocus = currentFocus ?: binding.root
inputMethodManager?.hideSoftInputFromWindow(currentFocus.windowToken, 0)
}
override fun inItemClick(paper: Paper) {
val intent = Intent(this, PaperActivity::class.java)
intent.putExtra(PaperActivity.paperKey, paper)
startActivity(intent)
}
}

View File

@ -0,0 +1,83 @@
package com.apps.pixwall.view
import android.graphics.Color
import android.view.Gravity
import android.view.LayoutInflater
import android.view.ViewGroup
import android.view.Window
import com.apps.pixwall.R
import com.apps.pixwall.databinding.FragmentDialogSelectBinding
import com.apps.pixwall.listener.ShowDialogListener
import androidx.core.graphics.drawable.toDrawable
class SelectDialogFragment : androidx.fragment.app.DialogFragment() {
private lateinit var vb: FragmentDialogSelectBinding
private var listener: ShowDialogListener? = null
companion object {
const val TYPE_HOME = 0
const val TYPE_LOCK = 1
const val TYPE_BOTH = 2
}
fun setListener(listener: ShowDialogListener?) {
this.listener = listener
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: android.os.Bundle?
): android.view.View {
vb = FragmentDialogSelectBinding.inflate(layoutInflater)
init()
return vb.root
}
override fun onCreateDialog(savedInstanceState: android.os.Bundle?): android.app.Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
dialog.window?.apply {
requestFeature(Window.FEATURE_NO_TITLE)
setWindowAnimations(R.style.BottomSheetDialogStyle)
setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
setGravity(Gravity.BOTTOM)
}
return dialog
}
override fun onStart() {
super.onStart()
dialog?.apply {
setCanceledOnTouchOutside(true)
window?.apply {
setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
}
}
}
private fun init() {
vb.layoutHome.setOnClickListener {
listener?.onClick(TYPE_HOME)
dismiss()
}
vb.layoutLock.setOnClickListener {
listener?.onClick(TYPE_LOCK)
dismiss()
}
vb.layoutBoth.setOnClickListener {
listener?.onClick(TYPE_BOTH)
dismiss()
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromYDelta="0%"
android:toYDelta="100%"
android:duration="300"/>
</set>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromYDelta="100%"
android:toYDelta="0%"
android:duration="300"/>
</set>

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/min_blue"/>
</shape>

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/light_purple"/>
</shape>

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="#80808080"/>
</shape>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- 线性渐变配置 -->
<gradient
android:type="linear"
android:startColor="#f5f3ff"
android:endColor="#8fa1d0"
android:angle="315"
/>
<corners android:radius="50dp"/>
</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/dark_purple"/>
<path
android:pathData="M993.3,12.4v692.7h-287.2v-90.4h196.8v-512h-512v224.4h-90.4V12.4z"
android:fillColor="@color/dark_purple"/>
</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/dark_purple"
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:fillColor="@color/dark_purple"
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,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- 上半部分渐变(从顶部黑色渐变到中间透明) -->
<gradient
android:angle="90"
android:startColor="#80000000"
android:centerColor="#00000000"
android:endColor="#80000000"
android:type="linear" />
</shape>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- 线性渐变配置 -->
<gradient
android:type="linear"
android:startColor="@color/min_purple"
android:endColor="@color/min_purple"
android:angle="0"
/>
<corners android:topLeftRadius="10dp" android:topRightRadius="10dp"/>
</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: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"
/>
<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/dark_purple"/>
</vector>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- 线性渐变配置 -->
<gradient
android:type="linear"
android:startColor="@color/white"
android:endColor="@color/white"
android:angle="0"
/>
<corners android:topLeftRadius="10dp" android:topRightRadius="10dp"/>
</shape>

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
android:height="108dp"
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z"/>
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
</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="M395.2,513.6l-323.1,-312.4c-19.1,-18.4 -19.1,-48.3 0,-66.7 19.1,-18.4 49.9,-18.4 69,0L498.6,480.3c19.1,18.4 19.1,48.3 0,66.7l-357.6,345.7c-9.5,9.2 -22,13.8 -34.5,13.8 -12.5,0 -25,-4.6 -34.5,-13.8 -19.1,-18.4 -19.1,-48.2 0,-66.7L395.2,513.6z"
android:fillColor="@color/light_purple"/>
</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="#F2E8EA" />
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="10dp" />
<gradient
android:angle="0"
android:endColor="@color/progress_purple"
android:centerColor="@color/min_blue"
android:startColor="@color/min_blue" />
</shape>
</clip>
</item>
</layer-list>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- 线性渐变配置 -->
<gradient
android:type="linear"
android:startColor="#f5f3ff"
android:endColor="#8fa1d0"
android:angle="315"
/>
</shape>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:topLeftRadius="10dp" android:topRightRadius="10dp"/>
<solid android:color="@color/white"/>
</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/select_fav_1" android:state_selected="true" />
<item android:drawable="@drawable/select_fav_0" />
</selector>

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/select_home_1" android:state_selected="true" />
<item android:drawable="@drawable/select_home_0" />
</selector>

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,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/select_like_1" android:state_selected="true" />
<item android:drawable="@drawable/select_like_0" />
</selector>

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/light_purple"/>
</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="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/white"/>
</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="rectangle">
<corners android:radius="50dp"/>
<solid android:color="@color/white"/>
</shape>

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="50dp"/>
<solid android:color="@color/min_purple"/>
</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="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/grey"/>
</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.3z"
android:fillColor="@color/dark_purple"/>
</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="M555.5,118l312.9,224.6A117.3,117.3 0,0 1,917.3 437.9V800c0,64.8 -52.5,117.3 -117.3,117.3H640V746.7c0,-70.7 -57.3,-128 -128,-128s-128,57.3 -128,128v170.7H224c-64.8,0 -117.3,-52.5 -117.3,-117.3V437.9a117.3,117.3 0,0 1,48.9 -95.3l312.9,-224.6a74.7,74.7 0,0 1,87.1 0z"
android:fillColor="@color/grey"/>
</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="M555.5,118l312.9,224.6A117.3,117.3 0,0 1,917.3 437.9V800c0,64.8 -52.5,117.3 -117.3,117.3H640V746.7c0,-70.7 -57.3,-128 -128,-128s-128,57.3 -128,128v170.7H224c-64.8,0 -117.3,-52.5 -117.3,-117.3V437.9a117.3,117.3 0,0 1,48.9 -95.3l312.9,-224.6a74.7,74.7 0,0 1,87.1 0z"
android:fillColor="@color/dark_purple"/>
</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="M704,128C833.6,128 938.7,234.7 938.7,384c0,298.7 -320,469.3 -426.7,533.3C405.3,853.3 85.3,682.7 85.3,384c0,-149.3 106.7,-256 234.7,-256C399.4,128 469.3,170.7 512,213.3c42.7,-42.7 112.6,-85.3 192,-85.3zM551.9,793.8a1141.4,1141.4 0,0 0,103.3 -72.6C782.3,620.1 853.3,509.6 853.3,384c0,-100.7 -65.6,-170.7 -149.3,-170.7 -45.9,0 -95.6,24.3 -131.7,60.3L512,334l-60.3,-60.3C415.6,237.7 365.9,213.3 320,213.3 237.2,213.3 170.7,284 170.7,384c0,125.6 71.1,236.1 198.2,337.2 31.8,25.3 65.7,48.9 103.3,72.5 12.8,8.1 25.4,15.8 39.9,24.4 14.5,-8.6 27.1,-16.3 39.9,-24.4z"
android:fillColor="@color/white"/>
</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="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="#C03B3B"/>
</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: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,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/light_purple"/>
<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/light_purple"/>
</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="#C9C7C7"
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="#C9C7C7"/>
<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="#C9C7C7"/>
</vector>

View File

@ -0,0 +1,43 @@
<?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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/min_purple"
tools:context=".view.LoadActivity">
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/imageview_logo"
android:layout_width="94dp"
android:layout_height="94dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="260dp"
android:src="@mipmap/ic_launcher_foreground"
app:roundPercent="0.2" />
<TextView
android:id="@+id/tvLogo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/imageview_logo"
android:layout_centerHorizontal="true"
android:layout_marginTop="19dp"
android:text="@string/app_name"
android:textColor="@color/progress_purple"
android:textStyle="bold"
android:textSize="22sp"/>
<ProgressBar
android:id="@+id/progressbar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="10dp"
android:layout_centerHorizontal="true"
android:layout_below="@+id/tvLogo"
android:layout_marginHorizontal="20dp"
android:max="100"
android:layout_marginTop="20dp"
android:progress="80"
android:indeterminateTint="@color/min_blue"
android:progressDrawable="@drawable/load_pb" />
</RelativeLayout>

View File

@ -0,0 +1,111 @@
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/main_bg"
android:orientation="vertical"
tools:context=".view.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:textSize="24sp"
android:textStyle="bold"
android:layout_marginTop="20dp"
android:layout_marginBottom="10dp"
android:layout_marginStart="10dp"
android:textColor="@color/light_purple"/>
<View
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="1dp"/>
<RelativeLayout
android:id="@+id/rlSearch"
android:layout_width="160dp"
android:layout_height="40dp"
android:background="@drawable/search_show"
android:layout_marginEnd="20dp"
android:layout_gravity="center">
<ImageView
android:id="@+id/imgSearch"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/explore_black_show"
android:layout_centerVertical="true"
android:layout_marginStart="10dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#a5aaa3"
android:layout_centerVertical="true"
android:layout_toEndOf="@+id/imgSearch"
android:textSize="16sp"
android:layout_marginStart="10dp"
android:text="@string/to_search"/>
</RelativeLayout>
</LinearLayout>
<FrameLayout
android:id="@+id/fragmentIn"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<LinearLayout
android:id="@+id/llBottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:background="@drawable/main_bottom"
app:layout_constraintBottom_toBottomOf="parent"
android:elevation="10dp"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/llHome"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:paddingVertical="8dp"
android:layout_weight="1"
>
<ImageView
android:id="@+id/imgHome"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/main_selector_home" />
<TextView
android:id="@+id/tvStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/grey"
android:text="@string/category"/>
</LinearLayout>
<LinearLayout
android:id="@+id/llLike"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:paddingVertical="10dp"
android:layout_weight="1"
>
<ImageView
android:id="@+id/imgLike"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/main_selecotr_fav" />
<TextView
android:id="@+id/tvEnd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/grey"
android:text="@string/favorite"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,48 @@
<?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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".view.MorePaperActivity">
<ImageView
android:id="@+id/imageBack"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_gravity="center"
android:padding="13dp"
android:src="@drawable/return_main"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="@color/black" />
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/imageBack"
android:layout_alignBottom="@id/imageBack"
android:layout_centerHorizontal="true"
android:gravity="center"
android:text="@string/app_name"
android:textColor="@color/light_purple"
android:textSize="17sp"
android:textStyle="bold" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginHorizontal="5dp"
android:layout_below="@id/imageBack" />
<ProgressBar
android:id="@+id/searchPb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminateTint="@color/progress_purple"
android:visibility="gone" />
</RelativeLayout>

View File

@ -0,0 +1,135 @@
<?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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.PaperActivity">
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/bg_placeholder"
android:scaleType="centerCrop" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="40dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/imageBack"
android:layout_width="46dp"
android:layout_height="46dp"
android:layout_gravity="center"
android:layout_marginStart="10dp"
android:padding="13dp"
android:background="@drawable/back_return"
android:src="@drawable/return_white"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/tvContent"
android:orientation="vertical">
<ImageView
android:id="@+id/imageFavorite"
android:layout_width="56dp"
android:layout_height="56dp"
android:background="@drawable/back_like"
android:padding="13dp"
android:layout_marginBottom="20dp"
android:src="@drawable/paper_selector_like" />
<RelativeLayout
android:id="@+id/layout_download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:background="@drawable/back_down">
<ImageView
android:id="@+id/imageDownload"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_centerInParent="true"
android:padding="13dp"
android:src="@drawable/paper_selector_download" />
<ProgressBar
android:id="@+id/pb_download"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_centerInParent="true"
android:indeterminateTint="@color/white"
android:padding="13dp"
android:visibility="gone" />
</RelativeLayout>
</LinearLayout>
<TextView
android:id="@+id/tvContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:minHeight="40dp"
android:padding="10dp"
android:text="@string/app_name"
android:textColor="@color/white"
android:textSize="17sp"
android:layout_marginBottom="130dp"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginStart="5dp"
app:layout_constraintBottom_toBottomOf="parent"/>
<RelativeLayout
android:id="@+id/layoutSet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_bg"
android:layout_marginTop="20dp"
android:paddingVertical="5dp"
android:paddingHorizontal="80dp"
app:layout_constraintTop_toBottomOf="@id/tvContent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
<ImageView
android:id="@+id/buttonSet"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_centerVertical="true"
android:layout_marginStart="15dp"
android:paddingTop="3dp"
android:src="@drawable/set_wall_paper"/>
<TextView
android:id="@+id/txApply"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/apply"
android:textColor="@color/light_purple"
android:layout_centerVertical="true"
android:textSize="18sp"
android:textStyle="bold"
android:layout_marginVertical="10dp"
android:layout_marginStart="42dp"
android:layout_marginEnd="20dp"/>
<ProgressBar
android:id="@+id/pbSet"
android:layout_width="46dp"
android:layout_height="46dp"
android:layout_centerInParent="true"
android:indeterminateTint="@color/white"
android:padding="13dp"
android:visibility="gone" />
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,115 @@
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical"
tools:context=".view.SearchActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/imageBack"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_gravity="center"
android:padding="13dp"
android:src="@drawable/return_main"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:tint="@color/black" />
<RelativeLayout
android:id="@+id/rlSearch"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@drawable/search_use"
android:layout_marginHorizontal="10dp"
android:gravity="center"
android:layout_gravity="center">
<ImageView
android:id="@+id/imgSearch"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/explore_black_show"
android:layout_centerVertical="true"
android:layout_marginStart="10dp"/>
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@+id/imgSearch"
android:textSize="16sp"
android:imeOptions="actionSearch"
android:background="@null"
android:maxLines="1"
android:inputType="text"
android:layout_marginEnd="60dp"
android:textColorHint="@color/grey"
android:layout_marginStart="10dp"
android:hint="@string/to_search"/>
<TextView
android:id="@+id/tvStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5sp"
android:text="@string/start"
android:textSize="16sp"
android:visibility="gone"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:layout_marginEnd="10dp"
android:textColor="@color/progress_purple"
/>
</RelativeLayout>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:layout_marginHorizontal="10dp"
android:background="@drawable/double_line_bg">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginHorizontal="5dp" />
<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/show_empty_result" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/no_data_found"
android:textColor="#000000" />
</LinearLayout>
<ProgressBar
android:id="@+id/searchPb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:indeterminateTint="@color/progress_purple"
android:visibility="gone" />
</RelativeLayout>
</LinearLayout>

View File

@ -0,0 +1,12 @@
<?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=".view.CategoryFragment">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/rvView"/>
</RelativeLayout>

View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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=".view.PaperActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/double_line_bg"
android:orientation="vertical"
android:paddingVertical="20dp">
<LinearLayout
android:id="@+id/layout_home"
android:layout_width="match_parent"
android:layout_height="64dp"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/dialog_home_set" />
<TextView
android:id="@+id/home"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginStart="21dp"
android:text="@string/apply_to_desktop"
android:textColor="@color/light_purple"
android:textSize="15sp" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginHorizontal="10dp"
android:background="@color/white" />
<LinearLayout
android:id="@+id/layout_lock"
android:layout_width="match_parent"
android:layout_height="64dp"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/dialog_lock_set" />
<TextView
android:id="@+id/lock"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginStart="22dp"
android:text="@string/apply_to_lock_screen"
android:textColor="@color/light_purple"
android:textSize="15sp" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginHorizontal="10dp"
android:background="@color/white" />
<LinearLayout
android:id="@+id/layout_both"
android:layout_width="match_parent"
android:layout_height="64dp"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/dialog_both_set" />
<TextView
android:id="@+id/both"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginStart="22dp"
android:text="@string/apply_to_all"
android:textColor="@color/light_purple"
android:textSize="15sp" />
</LinearLayout>
</LinearLayout>
</FrameLayout>

View File

@ -0,0 +1,49 @@
<?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=".view.FavoriteFragment">
<TextView
android:id="@+id/txTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginTop="8dp"
android:layout_marginStart="10dp"
android:textSize="18sp"
android:textColor="@color/dark_purple"
android:text="@string/favorite"/>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/txTitle"
android:layout_marginHorizontal="5dp"
android:id="@+id/rvView"/>
<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/show_empty_purple" />
<TextView
android:id="@+id/tvNoData"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center_horizontal"
android:lineSpacingExtra="4dp"
android:text="@string/empty"
android:textColor="@color/light_purple"
android:layout_marginBottom="50dp"
android:textSize="14sp" />
</LinearLayout>
</RelativeLayout>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="vertical"
android:id="@+id/llView"
android:layout_marginBottom="10dp"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:padding="10dp"
android:orientation="horizontal">
<TextView
android:id="@+id/txTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:textSize="16sp"
android:textColor="@color/dark_purple"/>
<View
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1"/>
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/img_go"
android:padding="3dp"/>
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="5dp"
android:id="@+id/rvView"/>
</LinearLayout>

View File

@ -0,0 +1,33 @@
<?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="5dp"
app:cardCornerRadius="10dp">
<ImageView
android:id="@+id/img"
android:layout_width="match_parent"
android:layout_height="300dp"
android:scaleType="centerCrop"
android:src="@mipmap/bg_placeholder" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/double_line_back" />
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginHorizontal="10dp"
android:layout_marginBottom="10dp"
android:text="@string/app_name"
android:textColor="@color/white"
android:maxLines="1"
android:ellipsize="end"
android:textSize="15sp" />
</androidx.cardview.widget.CardView>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:padding="5dp"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:layout_width="130dp"
android:layout_height="280dp"
app:cardCornerRadius="10dp"
app:cardElevation="0dp">
<ImageView
android:id="@+id/inImage"
android:layout_width="130dp"
android:layout_height="280dp"
android:scaleType="centerCrop"/>
</androidx.cardview.widget.CardView>
</RelativeLayout>

View File

@ -0,0 +1,37 @@
<?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:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_margin="5dp">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="10dp">
<ImageView
android:id="@+id/img"
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="centerCrop"
android:src="@mipmap/bg_placeholder" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:background="@drawable/double_line_back" />
</androidx.cardview.widget.CardView>
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginHorizontal="10dp"
android:layout_marginTop="5dp"
android:text="@string/app_name"
android:textColor="@color/light_purple"
android:maxLines="1"
android:ellipsize="end"
android:textSize="15sp" />
</LinearLayout>

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="@drawable/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

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="@drawable/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

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