接入TradPlus

This commit is contained in:
yuqian 2025-12-10 15:08:15 +08:00
commit 880af6d93d
126 changed files with 169385 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

3
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

6
.idea/AndroidProjectSystem.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AndroidProjectSystem">
<option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
</component>
</project>

6
.idea/compiler.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="21" />
</component>
</project>

18
.idea/deploymentTargetSelector.xml generated Normal file
View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-12-10T06:43:19.331679300Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=659PX8INFIUKHYXK" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState>
</selectionStates>
</component>
</project>

19
.idea/gradle.xml generated Normal file
View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

4
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,4 @@
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK" />
</project>

17
.idea/runConfigurations.xml generated Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
</set>
</option>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

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

@ -0,0 +1,157 @@
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")
id("com.google.gms.google-services")
id("com.google.firebase.crashlytics")
}
android {
namespace = "com.design.zenspace"
compileSdk {
version = release(36)
}
val timestamp = SimpleDateFormat("MM_dd_HH_mm").format(Date())
defaultConfig {
applicationId = "com.design.zenspace"
minSdk = 26
targetSdk = 36
versionCode = 1
versionName = "1.0"
setProperty(
"archivesBaseName",
"ZenSpace_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_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
buildFeatures{
viewBinding = true
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
implementation("androidx.room:room-runtime:2.7.2")
kapt("androidx.room:room-compiler:2.7.2")
implementation("androidx.room:room-ktx:2.7.2")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.2")
implementation("androidx.activity:activity-ktx:1.10.1")
implementation("com.github.bumptech.glide:glide:4.16.0")
implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation(files("libs/TradPlusLibrary_11_25_15_02-release.aar"))
implementation(files("libs/UpLoadLibrary_12_03_15_13-release.aar"))
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
implementation ("com.google.android.gms:play-services-ads-identifier:18.0.1")
// TradPlus
implementation("com.tradplusad:tradplus:14.5.0.1")
//noinspection GradleCompatible
implementation("androidx.legacy:legacy-support-v4:1.0.0")
implementation("androidx.appcompat:appcompat:1.3.0-alpha02")
// Meta
implementation("com.facebook.android:audience-network-sdk:6.20.0")
implementation("com.tradplusad:tradplus-facebook:1.14.5.0.1")
// Applovin
implementation("com.applovin:applovin-sdk:13.3.1")
implementation("com.tradplusad:tradplus-applovin:9.14.5.0.1")
implementation("com.google.android.gms:play-services-ads-identifier:18.2.0")
// Ironsource
implementation("com.ironsource.sdk:mediationsdk:8.10.0")
implementation("com.tradplusad:tradplus-ironsource:10.14.5.0.1")
implementation("com.google.android.gms:play-services-appset:16.0.0")
implementation("com.google.android.gms:play-services-ads-identifier:17.0.0")
implementation("com.google.android.gms:play-services-basement:17.5.0")
// Adcolony
implementation("com.adcolony:sdk:4.8.0")
implementation("com.tradplusad:tradplus-adcolony:4.14.5.0.1")
implementation("com.google.android.gms:play-services-ads-identifier:17.0.0")
// Pangle
implementation("com.tradplusad:tradplus-pangle:19.14.5.0.1")
implementation("com.pangle.global:pag-sdk:7.3.0.3")
// UnityAds
implementation("com.tradplusad:tradplus-unity:5.14.5.0.1")
implementation("com.unity3d.ads:unity-ads:4.15.1")
// Chartboost
implementation("com.tradplusad:tradplus-chartboostx:15.14.5.0.1")
implementation("com.chartboost:chartboost-sdk:9.8.3")
implementation("com.google.android.gms:play-services-ads-identifier:17.0.0")
implementation("com.google.android.gms:play-services-base:17.4.0")
// Inmobi
implementation("com.tradplusad:tradplus-inmobix:23.14.5.0.1")
implementation("com.inmobi.monetization:inmobi-ads-kotlin:10.8.3")
implementation("androidx.core:core-ktx:1.5.0")
implementation("com.inmobi.omsdk:inmobi-omsdk:1.5.2.0")
// Fyber
implementation("com.fyber:marketplace-sdk:8.3.7")
implementation("com.tradplusad:tradplus-fyber:24.14.5.0.1")
implementation("com.google.android.gms:play-services-ads-identifier:17.0.0")
implementation("com.google.android.gms:play-services-base:17.4.0")
// Start.io
implementation("com.startapp:inapp-sdk:5.2.3")
implementation("com.tradplusad:tradplus-startapp:28.14.5.0.1")
// Mintegral
implementation("com.tradplusad:tradplus-mintegralx_overseas:18.14.5.0.1")
implementation("androidx.recyclerview:recyclerview:1.1.0")
implementation("com.mbridge.msdk.oversea:mbridge_android_sdk:16.9.71")
// Liftoff
implementation("com.tradplusad:tradplus-vunglex:7.14.5.0.1")
implementation("com.vungle:vungle-ads:7.5.0")
// Yandex
implementation("com.yandex.android:mobileads:7.13.0") {
exclude(group = "com.caverock", module = "androidsvg-aar")
}
implementation("com.tradplusad:tradplus-yandex:50.14.6.10.1")
// Bigo
implementation("com.bigossp:bigo-ads:5.4.0")
implementation("com.tradplusad:tradplus-bigo:57.14.5.0.1")
// Cross Promotion
implementation("com.tradplusad:tradplus-crosspromotion:27.14.5.0.1")
// TP Exchange
// 请注意保持与主包版本同步更新
implementation("com.google.code.gson:gson:2.8.6")
implementation("com.tradplusad:tp_exchange:40.14.5.0.1")
// Google UMP
implementation ("com.google.android.ump:user-messaging-platform:3.2.0")
// TradPlus Tools
// implementation 'com.tradplusad:tradplus-tool:1.1.4'
// Firebase
implementation(platform("com.google.firebase:firebase-bom:33.7.0"))
implementation("com.google.firebase:firebase-crashlytics")
implementation("com.google.firebase:firebase-analytics")
implementation("com.google.firebase:firebase-config")
}

29
app/google-services.json Normal file
View File

@ -0,0 +1,29 @@
{
"project_info": {
"project_number": "541914285342",
"project_id": "zenspace-f0c81",
"storage_bucket": "zenspace-f0c81.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:541914285342:android:f579ec19e4d6b9e8efb50f",
"android_client_info": {
"package_name": "com.design.zenspace"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyBhWhVEYpL2EtCcOy1YmxUdc8lqLWBAhXk"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}

Binary file not shown.

Binary file not shown.

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

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,37 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.design.zenspace",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0",
"outputFile": "ZenSpace_V1.0_1_11_26_12_03-release.apk"
}
],
"elementType": "File",
"baselineProfiles": [
{
"minApi": 28,
"maxApi": 30,
"baselineProfiles": [
"baselineProfiles/1/ZenSpace_V1.0_1_11_26_12_03-release.dm"
]
},
{
"minApi": 31,
"maxApi": 2147483647,
"baselineProfiles": [
"baselineProfiles/0/ZenSpace_V1.0_1_11_26_12_03-release.dm"
]
}
],
"minSdkVersionForDexing": 26
}

View File

@ -0,0 +1,24 @@
package com.design.zenspace
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.design.zenspace", appContext.packageName)
}
}

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" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:name="com.design.zenspace.DApplication"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ZenSpace">
<activity
android:name=".preview.ComeInActivity"
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=".preview.FindSomeActivity"
android:exported="false" />
<activity
android:name=".preview.CateAndLikActivity"
android:exported="false" />
<activity
android:name=".preview.PreviewBigActivity"
android:theme="@style/Base.Theme.ZenSpace"
android:exported="false" />
<meta-data
android:name="com.startapp.sdk.MIXED_AUDIENCE"
android:value="true"/>
</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: 374 KiB

View File

@ -0,0 +1,83 @@
package com.design.zenspace
import android.app.Application
import android.util.Log
import com.design.zenspace.entity.AppDataBase
import com.design.zenspace.entity.FeatureDao
import com.design.zenspace.tools.SaveUtil
import com.up.uploadlibrary.UpLoadManager
import java.io.IOException
class DApplication : 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 {
const val TAG = "DApplication"
var classificationList: MutableList<String> = mutableListOf()
var isDataInitialized = false
private set
}
override fun onCreate() {
super.onCreate()
UpLoadManager.init(this, TAG) { _, _ ->
// 处理逻辑
null
Log.d(TAG, "upload success")
}
val database = AppDataBase.getDatabase(this)
val paperDao = database.featureDao()
Thread {
initializeData(paperDao)
isDataInitialized = true
}.start()
}
private fun initializeData(paperDao: FeatureDao) {
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 = SaveUtil.getConvert(inputStream)
Log.d("DataInit", "Loaded JSON for $name")
if (jsonData.isNotEmpty()) {
val classificationName = name.substring(0, name.indexOf("."))
// 同步添加分类名称(线程安全)
synchronized(classificationList) {
classificationList.add(classificationName)
}
// 解析数据
val feature = SaveUtil.getData(jsonData, classificationName)
// 批量插入数据
if (feature.isNotEmpty()) {
// 使用批量插入方法
paperDao.insertAll(feature)
Log.d("DataInit", "[$classificationName] insert ${feature.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,23 @@
package com.design.zenspace.entity
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
@Database(entities = [Feature::class], version = 1, exportSchema = false)
abstract class AppDataBase:RoomDatabase() {
abstract fun featureDao():FeatureDao
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,"zenspace_database").fallbackToDestructiveMigration().build()
}
}
}

View File

@ -0,0 +1,24 @@
package com.design.zenspace.entity
import android.os.Parcelable
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import kotlinx.parcelize.Parcelize
@Parcelize
@Entity(tableName = "feature",
indices = [Index(value = ["imId"], unique = true)])
data class Feature(
@PrimaryKey(autoGenerate = true) var id: Int = 0,
@ColumnInfo(name = "classificationName") var classificationName: 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,39 @@
package com.design.zenspace.entity
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 FeatureDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insertAll(feature: List<Feature>)
@Update
suspend fun update(feature: Feature)
@Query("SELECT * FROM feature WHERE imId=:imId")
suspend fun getById(imId: String): Feature?
@Query("SELECT * FROM feature WHERE classificationName=:name LIMIT 6 OFFSET 20")
suspend fun queryCover(name: String): List<Feature>
@Query("SELECT * FROM feature WHERE classificationName=:name")
suspend fun queryEachGenera(name: String): List<Feature>
@Query("SELECT * FROM feature WHERE is_like = 1")
fun queryLikeFeature(): LiveData<List<Feature>>
@Query("SELECT * FROM feature WHERE description LIKE '%'||:name||'%'")
suspend fun search(name: String): List<Feature>
@Query("SELECT * FROM feature WHERE imId = :imId AND is_like = 1")
suspend fun queryIsLike(imId: String): Feature?
@Query("SELECT * FROM feature")
suspend fun getAllFeatures(): List<Feature>
}

View File

@ -0,0 +1,28 @@
package com.design.zenspace.entity
import androidx.lifecycle.LiveData
class FeatureRepository(private val featureDao: FeatureDao) {
suspend fun allFeature():List<Feature>{
return featureDao.getAllFeatures()
}
suspend fun updateFeature(feature: Feature){
featureDao.update(feature)
}
suspend fun getFeatureById(id:String):Feature?{
return featureDao.getById(id)
}
suspend fun getClassificationCover(name:String):List<Feature>{
return featureDao.queryCover(name)
}
suspend fun getFeatureByClassification(name: String):List<Feature>{
return featureDao.queryEachGenera(name)
}
fun getLikes():LiveData<List<Feature>>{
return featureDao.queryLikeFeature()
}
suspend fun searchByKey(key:String):List<Feature>{
return featureDao.search(key)
}
suspend fun isLike(id: String): Boolean = featureDao.queryIsLike(id) != null
}

View File

@ -0,0 +1,146 @@
package com.design.zenspace.entity
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.design.zenspace.DApplication
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.launch
class MainViewModel(application: Application) : AndroidViewModel(application) {
private val repository: FeatureRepository by lazy {
val dao = AppDataBase.getDatabase(application).featureDao()
FeatureRepository(dao)
}
// 防抖控制
private var lastSearchTime = 0L
private var lastQuery: String? = null
private val searchDebounceTime = 500L
// LiveData 统一暴露
private val _paperResult = MutableLiveData<Feature?>() // id查询结果
val paperResult: LiveData<Feature?> get() = _paperResult
private val _classificationList = MutableLiveData<List<Feature>>(emptyList()) // 类别列表
val classificationList: LiveData<List<Feature>> get() = _classificationList
private val _coverMap = MutableLiveData<Map<String, List<Feature>>>(emptyMap()) // 封面分类映射
val coverMap: LiveData<Map<String, List<Feature>>> get() = _coverMap
private val _loadingState = MutableLiveData(false) // 加载状态
val loadingState: LiveData<Boolean> get() = _loadingState
private val _searchList = MutableLiveData<List<Feature>>(emptyList()) // 搜索结果
val searchList: LiveData<List<Feature>> get() = _searchList
private val _isLiked = MutableLiveData<Boolean?>() // 是否收藏
val isLiked: LiveData<Boolean?> get() = _isLiked
val likeFeatures: LiveData<List<Feature>> get() = repository.getLikes()
// 添加标题存储
var currentTitleName: String? = null
fun debugDatabase() {
viewModelScope.launch(Dispatchers.IO) {
try {
val feature = repository.allFeature()
Log.d("DB_DEBUG", "总记录数: ${feature.size}")
feature.take(5).forEach { paper ->
Log.d("DB_DEBUG", "Feature[${paper.id}]: " +
"cat=${paper.classificationName}, " +
"imId=${paper.imId}, " +
"desc=${paper.description.take(10)}...")
}
} catch (e: Exception) {
Log.e("DB_DEBUG", "查询失败", e)
}
}
}
fun updateFeature(paper: Feature) {
viewModelScope.launch(Dispatchers.IO) {
repository.updateFeature(paper)
}
}
fun getFeatureResult(id: String) {
viewModelScope.launch(Dispatchers.IO) {
_paperResult.postValue(repository.getFeatureById(id))
}
}
fun getClassificationList(name: String) {
viewModelScope.launch(Dispatchers.IO) {
_classificationList.postValue(repository.getFeatureByClassification(name))
}
}
fun loadAllClassificationCovers() {
if (_loadingState.value == true) return
viewModelScope.launch(Dispatchers.IO) {
_loadingState.postValue(true)
val classificationList = DApplication.classificationList
val resultMap = mutableMapOf<String, List<Feature>>()
val deferredList = classificationList.map { classification ->
async {
try {
classification to repository.getClassificationCover(classification)
} catch (e: Exception) {
Log.e("BatchLoad", "加载分类[$classification]失败: ${e.message}")
classification to emptyList<Feature>()
}
}
}
deferredList.awaitAll().forEach { (classification, feature) ->
resultMap[classification] = feature
}
_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: Feature) {
viewModelScope.launch(Dispatchers.IO) {
val updateFeature = paper.copy(isLike = !paper.isLike)
repository.updateFeature(updateFeature)
Log.d("setlike status",updateFeature.isLike.toString())
_isLiked.postValue(updateFeature.isLike)
}
}
}

View File

@ -0,0 +1,128 @@
package com.design.zenspace.preview
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.design.zenspace.R
import com.design.zenspace.entity.MainViewModel
import com.design.zenspace.databinding.ActivityCateAndLikeBinding
import com.design.zenspace.tools.TopBarUtils
class CateAndLikActivity : AppCompatActivity() {
private lateinit var binding: ActivityCateAndLikeBinding
private var isTransitionInProgress = false
private var lastClickTime = 0L
private val TAP_THROTTLE = 300L
private lateinit var tagShowFragment: Fragment
private lateinit var collectWallFragment: Fragment
private lateinit var mainViewModel : MainViewModel
private var activeFragment: Fragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityCateAndLikeBinding.inflate(layoutInflater)
setContentView(binding.root)
mainViewModel = ViewModelProvider(this)[MainViewModel::class.java]
initFragments()
TopBarUtils.setStatusBar(this.window)
TopBarUtils.setLightStatusBar(this.window,true)
mainViewModel .debugDatabase()
initializeFragments()
}
private fun updateTab(position: Int) {
val defaultColor = getColor(R.color.text_normal)
val selectColor = getColor(R.color.black)
binding.tvStart.setTextColor(defaultColor)
binding.tvEnd.setTextColor(defaultColor)
when (position) {
0 -> {
binding.tvStart.setTextColor(selectColor)
binding.tvStart.textSize = 18f
binding.tvEnd.textSize = 16f
binding.rlSearch.visibility = View.VISIBLE
}
1 -> {
binding.tvEnd.setTextColor(selectColor)
binding.tvEnd.textSize = 18f
binding.tvStart.textSize = 16f
binding.rlSearch.visibility = View.GONE
}
}
}
private fun initFragments() {
tagShowFragment = TagShowFragment()
collectWallFragment = CollectWallFragment()
}
private fun initializeFragments() {
// 初始添加两个Fragment但默认隐藏collectWallFragment
supportFragmentManager.beginTransaction().apply {
add(binding.fragmentIn.id, tagShowFragment, "classification")
add(binding.fragmentIn.id, collectWallFragment, "like")
hide(collectWallFragment)
commit()
}
activeFragment = tagShowFragment
updateTab(0)
binding.llHome.setOnClickListener {
if (System.currentTimeMillis() - lastClickTime > TAP_THROTTLE) {
switchFragment(0)
lastClickTime = System.currentTimeMillis()
}
}
binding.llLike.setOnClickListener {
if (System.currentTimeMillis() - lastClickTime > TAP_THROTTLE) {
switchFragment(1)
lastClickTime = System.currentTimeMillis()
}
}
binding.rlSearch.setOnClickListener {
Log.d("ClickTest", "RelativeLayout被点击了")
startActivity(Intent(this, FindSomeActivity::class.java))
}
}
private fun switchFragment(position: Int) {
if (isTransitionInProgress) return
val targetFragment = when (position) {
0 -> tagShowFragment
1 -> collectWallFragment
else -> return
}
// 如果目标Fragment已经是当前显示的Fragment则直接返回
if (targetFragment == activeFragment) return
updateTab(position)
isTransitionInProgress = true
supportFragmentManager.beginTransaction().apply {
setCustomAnimations(
android.R.anim.fade_in,
android.R.anim.fade_out
)
// 隐藏当前活动的Fragment
activeFragment?.let { hide(it) }
// 显示目标Fragment
show(targetFragment)
activeFragment = targetFragment
commit()
}
// 使用postDelayed来重置标志位确保动画完成
binding.root.postDelayed({
isTransitionInProgress = false
}, 300)
}
}

View File

@ -0,0 +1,57 @@
package com.design.zenspace.preview
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.design.zenspace.databinding.FragmentCollectWallBinding
import com.design.zenspace.tools.LikeWallAdapter
import com.design.zenspace.entity.MainViewModel
import com.design.zenspace.entity.Feature
import com.design.zenspace.tools.SecFavListener
class CollectWallFragment : Fragment(),SecFavListener {
private lateinit var binding: FragmentCollectWallBinding
private lateinit var viewModel: MainViewModel
private lateinit var adapter:LikeWallAdapter
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding= FragmentCollectWallBinding.inflate(inflater,container,false)
init()
return binding.root
}
private fun init(){
viewModel=ViewModelProvider(requireActivity())[MainViewModel::class.java]
adapter=LikeWallAdapter()
adapter.setListener(this)
viewModel.likeFeatures.observe(viewLifecycleOwner) { feature ->
Log.d("LikeFragment","paper is$feature")
if (feature.isNullOrEmpty()) {
// 可以在这里显示空状态视图
binding.layoutNoData.visibility = View.VISIBLE
binding.rvView.visibility = View.GONE
} else {
binding.layoutNoData.visibility = View.GONE
binding.rvView.visibility = View.VISIBLE
adapter.setList(feature)
adapter.notifyDataSetChanged()
}
}
val gridLayoutManager = GridLayoutManager(requireActivity(), 3)
binding.rvView.layoutManager=gridLayoutManager
binding.rvView.adapter=adapter
}
override fun inItemClick(paper: Feature) {
val intent= Intent(context, PreviewBigActivity::class.java)
intent.putExtra(PreviewBigActivity.paperKey,paper)
startActivity(intent)
}
}

View File

@ -0,0 +1,64 @@
package com.design.zenspace.preview
import android.content.Intent
import android.os.Bundle
import android.os.CountDownTimer
import android.os.Handler
import androidx.appcompat.app.AppCompatActivity
import com.ad.tradpluslibrary.TPAdManager
import com.design.zenspace.DApplication
import com.design.zenspace.databinding.ActivityComeInBinding
import com.design.zenspace.tools.TopBarUtils
class ComeInActivity : AppCompatActivity() {
lateinit var binding: ActivityComeInBinding
private var handler: Handler = Handler()
private var time: Long = 14000
private var countDownTimer: CountDownTimer? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityComeInBinding.inflate(layoutInflater)
setContentView(binding.root)
TPAdManager.init(
this,
DApplication.TAG,
"B40C100CB1E175ED81EFC575BFFB3511",
"99E134664DC9E21D796BDF7747FCFF12",
"0B01387BA902075D61D1265B59099412",
"43A0C367BC57777A6DA8B22FF2A1F312"
) {
}
TopBarUtils.setStatusBar(this.window)
TopBarUtils.setLightStatusBar(this.window,true)
countDownTimer = TPAdManager.showWelcomeAd(
this@ComeInActivity,
time,
{ aLong ->
val progressPercentage = (100 * aLong) / time
val percentage = 100 - progressPercentage
binding.progressbar.progress = percentage.toInt()
},
{
val intent= Intent(
this@ComeInActivity,
CateAndLikActivity::class.java
)
startActivity(intent)
finish()
}
)
countDownTimer?.start()
}
override fun onDestroy() {
super.onDestroy()
handler.removeCallbacksAndMessages(null)
if (countDownTimer != null) {
countDownTimer!!.cancel()
}
}
}

View File

@ -0,0 +1,129 @@
package com.design.zenspace.preview
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.ad.tradpluslibrary.TPAdManager.showTPAD
import com.design.zenspace.R
import com.design.zenspace.databinding.ActivityFindSomeBinding
import com.design.zenspace.tools.MoreAndSearchAdapter
import com.design.zenspace.entity.MainViewModel
import com.design.zenspace.entity.Feature
import com.design.zenspace.tools.SecFavListener
import com.design.zenspace.tools.TopBarUtils
class FindSomeActivity : AppCompatActivity(), SecFavListener {
lateinit var binding: ActivityFindSomeBinding
private lateinit var viewModel: MainViewModel
private lateinit var adapter: MoreAndSearchAdapter
private var resultList: List<Feature> = emptyList()
private var searchKey = ""
private var isClick = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityFindSomeBinding.inflate(layoutInflater)
setContentView(binding.root)
TopBarUtils.setStatusBar(this.window)
TopBarUtils.setLightStatusBar(this.window,true)
showTPAD(this) {}
init()
}
private fun init() {
viewModel = ViewModelProvider(this)[MainViewModel::class.java]
adapter = MoreAndSearchAdapter()
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: Feature) {
val intent = Intent(this, PreviewBigActivity::class.java)
intent.putExtra(PreviewBigActivity.paperKey, paper)
startActivity(intent)
}
}

View File

@ -0,0 +1,316 @@
package com.design.zenspace.preview
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.ad.tradpluslibrary.TPAdManager.showTPAD
import com.design.zenspace.R
import com.design.zenspace.entity.MainViewModel
import com.design.zenspace.entity.Feature
import com.design.zenspace.tools.IntentListener
import com.design.zenspace.tools.SetWayUtils
import com.design.zenspace.tools.SaveUtil
import com.design.zenspace.tools.TopBarUtils
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.request.RequestOptions
import com.design.zenspace.databinding.ActivityPreviewBigBinding
import okhttp3.Call
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
class PreviewBigActivity : AppCompatActivity(), IntentListener {
companion object {
var paperKey = "wallpaperData"
}
private lateinit var binding: ActivityPreviewBigBinding
lateinit var paper: Feature
private lateinit var viewModel: MainViewModel
private var fullImageUrl = ""
private var fileSavePath = ""
private lateinit var wallpaperManager: WallpaperManager
private lateinit var downloadedFile: File
private var call: Call?=null
private var isGranted = false
private lateinit var setDialog: ShowWayDialog
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 isActivityAlive(): Boolean {
return !isFinishing && !isDestroyed
}
private fun requestStoragePermission() {
val permissions = SaveUtil.getStoragePermissions()
if (SaveUtil.hasStoragePermission(this)) {
isGranted = true
} else {
storagePermissionLauncher.launch(permissions)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityPreviewBigBinding.inflate(layoutInflater)
setContentView(binding.root)
TopBarUtils.setStatusBar(this.window)
TopBarUtils.setLightStatusBar(this.window,true)
showTPAD(this) {}
initializeComponents()
}
override fun onDestroy() {
super.onDestroy()
call?.let {
it.cancel()
}
deleteCacheFile()
}
private fun initializeComponents() {
viewModel = ViewModelProvider(this)[MainViewModel::class.java]
paper = intent?.getParcelableExtra(paperKey)!!
fullImageUrl = paper.fullUrl
fileSavePath = SaveUtil.getSaveFilePath(this, paper.imId)
downloadedFile = File(fileSavePath)
setDialog = ShowWayDialog()
setDialog.setListener(this@PreviewBigActivity)
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.imageLike.isSelected = b
}
}
viewModel.checkLike(paper.imId)
binding.imageLike.setOnClickListener {
setLikeStatus()
}
binding.layoutDownload.setOnClickListener {
initiateDownload()
}
binding.layoutSet.setOnClickListener {
showSetDialog()
}
}
private fun showSetDialog() {
if (isSetting) return
if (!setDialog.isAdded) {
showTPAD(this) {
setDialog.show(supportFragmentManager, "")
}
}
}
private fun setLikeStatus() {
val b = !binding.imageLike.isSelected
binding.imageLike.isSelected = !b
paper.isLike = !b
viewModel.setLike(paper)
}
private fun initiateDownload() {
requestStoragePermission()
if (!isGranted) return
showDownloadLoading(true)
if (downloadedFile.exists()) {
saveToGallery()
return
}
downloadImageFile()
}
private fun saveToGallery() {
val uri: Uri? = SetWayUtils.saveToGallery(this, downloadedFile)
if(!isActivityAlive()) return
runOnUiThread {
showDownloadLoading(false)
if (uri == null) {
Toast.makeText(
this@PreviewBigActivity,
getString(R.string.save_fail),
Toast.LENGTH_SHORT
).show()
} else {
Toast.makeText(
this@PreviewBigActivity,
getString(R.string.save_success),
Toast.LENGTH_SHORT
).show()
}
Log.d("YYYYYY", "--------path=" + downloadedFile.getAbsolutePath() + "---uri=" + uri)
}
}
private fun downloadImageFile() {
call = SetWayUtils.downloadFile(fullImageUrl, fileSavePath, object : SetWayUtils.ConnectCallBack {
override fun onResult(success: Boolean, inputStream: InputStream?) {
val file = File(fileSavePath)
if (file.exists() && success) {
downloadedFile = file
saveToGallery()
} else {
if(!isActivityAlive()) return
runOnUiThread {
showDownloadLoading(false)
Toast.makeText(
this@PreviewBigActivity,
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 (downloadedFile.exists()) {
val delete = downloadedFile.delete()
Log.d("YYYYYY", "--------delete=$delete")
}
}
override fun onClick(type: Int) {
showSetWallpaperLoading(true)
if (downloadedFile.exists()) {
Thread {
Log.d("YYYYYY", "skip download and set")
setWallpaperFromFile(downloadedFile, type)
}.start()
} else {
call =
SetWayUtils.downloadFile(fullImageUrl, fileSavePath, object : SetWayUtils.ConnectCallBack {
override fun onResult(success: Boolean, inputStream: InputStream?) {
val file = File(fileSavePath)
if (file.exists() && success) {
downloadedFile = file
setWallpaperFromFile(downloadedFile, type)
} else {
if(!isActivityAlive()) return
showDownloadLoading(false)
runOnUiThread {
Toast.makeText(
this@PreviewBigActivity,
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
} else {
isSetting = false
binding.pbSet.visibility = View.GONE
}
}
private fun setWallpaperFromFile(file: File, type: Int) {
try {
FileInputStream(file).use { fileInputStream ->
when (type) {
ShowWayDialog.TYPE_HOME -> {
// FLAG_SYSTEM 表示设置为主屏幕壁纸
wallpaperManager.setStream(
fileInputStream,
null,
true,
WallpaperManager.FLAG_SYSTEM
)
}
ShowWayDialog.TYPE_LOCK -> {
// FLAG_LOCK 设置为锁屏壁纸
wallpaperManager.setStream(
fileInputStream,
null,
true,
WallpaperManager.FLAG_LOCK
)
}
ShowWayDialog.TYPE_BOTH -> {
// 同时设置主屏和锁屏壁纸
wallpaperManager.setStream(fileInputStream)
}
else -> {}
}
}
if(!isActivityAlive()) return
runOnUiThread {
showSetWallpaperLoading(false)
Toast.makeText(
this@PreviewBigActivity,
getString(R.string.set_success),
Toast.LENGTH_SHORT
).show()
}
} catch (e: Exception) {
if(!isActivityAlive()) return
runOnUiThread {
showSetWallpaperLoading(false)
Toast.makeText(
this@PreviewBigActivity,
getString(R.string.set_fail),
Toast.LENGTH_SHORT
).show()
}
}
}
}

View File

@ -0,0 +1,83 @@
package com.design.zenspace.preview
import android.graphics.Color
import android.view.Gravity
import android.view.LayoutInflater
import android.view.ViewGroup
import android.view.Window
import com.design.zenspace.R
import com.design.zenspace.databinding.FragmentShowWayBinding
import com.design.zenspace.tools.IntentListener
import androidx.core.graphics.drawable.toDrawable
class ShowWayDialog : androidx.fragment.app.DialogFragment() {
private lateinit var vb: FragmentShowWayBinding
private var listener: IntentListener? = null
companion object {
const val TYPE_HOME = 0
const val TYPE_LOCK = 1
const val TYPE_BOTH = 2
}
fun setListener(listener: IntentListener?) {
this.listener = listener
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: android.os.Bundle?
): android.view.View {
vb = FragmentShowWayBinding.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.CenterShowDialogStyle)
setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
setGravity(Gravity.CENTER)
}
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,251 @@
package com.design.zenspace.preview
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 androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.design.zenspace.tools.CenterSnapHelper
import com.design.zenspace.DApplication
import com.design.zenspace.tools.TagAdapter
import com.design.zenspace.tools.TagItem
import com.design.zenspace.entity.Feature
import com.design.zenspace.entity.MainViewModel
import com.design.zenspace.databinding.FragmentTagShowBinding
import com.design.zenspace.tools.MoreAndSearchAdapter
import com.design.zenspace.tools.SecFavListener
import kotlin.math.abs
class TagShowFragment : Fragment(),SecFavListener {
private lateinit var binding: FragmentTagShowBinding
private lateinit var viewModel:MainViewModel
private lateinit var tagAdapter: TagAdapter
private val snapHelper = CenterSnapHelper()
private var isScrolling = false
private var pendingScrollPosition = -1
private lateinit var adapter:MoreAndSearchAdapter
private val tagList = mutableListOf<TagItem>()
private var currentTagName = ""
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding=FragmentTagShowBinding.inflate(inflater,container,false)
val classificationList = DApplication.classificationList
viewModel=ViewModelProvider(this)[MainViewModel::class.java]
for(index in 0 until classificationList.size){
tagList.add(TagItem(index , classificationList[index]))
}
initRecyclerView() // 先初始化 Adapter
setupRecyclerView()
setupDataObserver() // 设置数据观察
return binding.root
}
private fun setupRecyclerView() {
// 设置布局管理器
val layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)
binding.rvTags.layoutManager = layoutManager
// 创建适配器
tagAdapter = TagAdapter(tagList) { selectedTag, position ->
Log.d("ClassificationFragment00", "Selected tag: ${selectedTag.name}")
updateSelectedText(selectedTag.name)
smoothScrollToCenter(position)
}
binding.rvTags.adapter = tagAdapter
// 添加 SnapHelper 实现居中吸附
snapHelper.attachToRecyclerView(binding.rvTags)
// 添加滚动状态监听
binding.rvTags.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
isScrolling = newState != RecyclerView.SCROLL_STATE_IDLE
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
// 滚动停止时更新选中状态
updateSelectedItemFromScroll()
// 执行延迟的滚动
if (pendingScrollPosition != -1) {
val position = pendingScrollPosition
pendingScrollPosition = -1
executeSmoothScroll(position)
}
}
}
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
// 只在滚动时实时更新(可选,如果不需要实时更新可以去掉)
// updateSelectedItemFromScroll()
}
})
// 初始选中第一个
// updateSelectedText(tagList[0].name)
// 延迟滚动到第一个位置
binding.rvTags.post {
smoothScrollToCenter(0)
}
}
private fun smoothScrollToCenter(position: Int) {
if (isScrolling) {
// 如果正在滚动,延迟执行
pendingScrollPosition = position
return
}
executeSmoothScroll(position)
}
private fun executeSmoothScroll(position: Int) {
if (!binding.rvTags.isComputingLayout && !isScrolling) {
binding.rvTags.smoothScrollToPosition(position)
// 添加一个小的延迟来确保精确居中
binding.rvTags.postDelayed({
if (!binding.rvTags.isComputingLayout) {
adjustToExactCenter(position)
}
}, 100)
} else {
// 如果仍然在计算布局,再次延迟
pendingScrollPosition = position
}
}
private fun adjustToExactCenter(position: Int) {
val layoutManager = binding.rvTags.layoutManager as? LinearLayoutManager ?: return
if (binding.rvTags.isComputingLayout || isScrolling) {
return
}
val targetView = layoutManager.findViewByPosition(position)
targetView?.let {
val centerX = it.left + it.width / 2
val targetScrollX = centerX - binding.rvTags.width / 2
// 只在需要调整时才滚动
if (Math.abs(targetScrollX) > 10) {
binding.rvTags.smoothScrollBy(targetScrollX, 0)
}
}
}
private fun updateSelectedItemFromScroll() {
if (binding.rvTags.isComputingLayout) {
return
}
val layoutManager = binding.rvTags.layoutManager as? LinearLayoutManager ?: return
val centerX = binding.rvTags.width / 2
var minDistance = Int.MAX_VALUE
var centerPosition = 0
// 找到最接近中心的item
for (i in 0 until layoutManager.childCount) {
val child = layoutManager.getChildAt(i) ?: continue
val position = layoutManager.getPosition(child)
if (position == RecyclerView.NO_POSITION) continue
val childCenterX = (child.left + child.right) / 2
val distance = abs(childCenterX - centerX)
if (distance < minDistance) {
minDistance = distance
centerPosition = position
}
}
// 安全地更新选中状态
if (centerPosition >= 0 && centerPosition < tagList.size) {
val currentSelected = tagAdapter.getSelectedPosition()
if (currentSelected != centerPosition) {
tagAdapter.notifyItemChanged(currentSelected)
tagAdapter.notifyItemChanged(centerPosition)
Log.d("ClassificationFragment", "Selected tag: ${currentSelected}")
updateSelectedText(tagList[currentSelected].name)
}
}
}
private fun setupDataObserver() {
// 统一设置数据观察者
viewModel.classificationList.observe(viewLifecycleOwner) { list ->
if (list.isNotEmpty() && currentTagName == viewModel.currentTitleName) {
updateUI(list)
} else if (list.isEmpty()) {
// 处理空数据情况
binding.searchPb.visibility = View.GONE
adapter.setList(emptyList())
adapter.notifyDataSetChanged()
}
}
}
private fun initRecyclerView() {
adapter = MoreAndSearchAdapter()
adapter.setListener(this)
binding.list.layoutManager = GridLayoutManager(requireContext(), 2)
binding.list.adapter = adapter
}
private fun updateSelectedText(tagName: String) {
Log.d("ClassificationFragment", "updateSelectedText: $tagName")
// 如果点击的是当前已选中的标签,不重复请求
if (currentTagName == tagName) {
Log.d("ClassificationFragment", "Same tag selected, skip request")
return
}
currentTagName = tagName
viewModel.currentTitleName = tagName
// 显示加载状态
binding.searchPb.visibility = View.VISIBLE
// 先清空旧数据,显示加载状态
adapter.setList(emptyList())
adapter.notifyDataSetChanged()
// 强制重新获取数据
Log.d("ClassificationFragment", "Requesting data for: $tagName")
viewModel.getClassificationList(tagName)
}
private fun updateUI(list: List<Feature>) {
Log.d("ClassificationFragment", "updateUI: ${list.size} items for $currentTagName")
// 确保当前显示的数据与当前选中的标签匹配
if (currentTagName == viewModel.currentTitleName) {
adapter.setList(list)
binding.searchPb.visibility = View.GONE
adapter.notifyDataSetChanged()
Log.d("ClassificationFragment", "UI updated successfully")
} else {
Log.d("ClassificationFragment", "Data mismatch, current: $currentTagName, data for: ${viewModel.currentTitleName}")
}
}
override fun inItemClick(feature: Feature) {
val intent= Intent(requireActivity(),PreviewBigActivity::class.java)
intent.putExtra(PreviewBigActivity.paperKey,feature)
startActivity(intent)
}
}

View File

@ -0,0 +1,69 @@
package com.design.zenspace.tools
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSnapHelper
import androidx.recyclerview.widget.RecyclerView
class CenterSnapHelper : LinearSnapHelper() {
private var recyclerView: RecyclerView? = null
override fun attachToRecyclerView(recyclerView: RecyclerView?) {
super.attachToRecyclerView(recyclerView)
this.recyclerView = recyclerView
}
override fun calculateDistanceToFinalSnap(
layoutManager: RecyclerView.LayoutManager,
targetView: View
): IntArray {
val out = IntArray(2)
if (layoutManager.canScrollHorizontally()) {
out[0] = calculateDistanceToCenter(targetView, layoutManager)
} else {
out[0] = 0
}
if (layoutManager.canScrollVertically()) {
out[1] = calculateDistanceToCenter(targetView, layoutManager)
} else {
out[1] = 0
}
return out
}
override fun findSnapView(layoutManager: RecyclerView.LayoutManager): View? {
return findCenterView(layoutManager)
}
private fun calculateDistanceToCenter(targetView: View, layoutManager: RecyclerView.LayoutManager): Int {
if (layoutManager.canScrollHorizontally()) {
val centerX = (layoutManager.width / 2)
val targetCenterX = (targetView.left + targetView.right) / 2
return targetCenterX - centerX
}
return 0
}
private fun findCenterView(layoutManager: RecyclerView.LayoutManager): View? {
if (layoutManager !is LinearLayoutManager) return null
val centerX = layoutManager.width / 2
var minDistance = Int.MAX_VALUE
var centerView: View? = null
for (i in 0 until layoutManager.childCount) {
val child = layoutManager.getChildAt(i) ?: continue
val childCenterX = (child.left + child.right) / 2
val distance = Math.abs(childCenterX - centerX)
if (distance < minDistance) {
minDistance = distance
centerView = child
}
}
return centerView
}
}

View File

@ -0,0 +1,5 @@
package com.design.zenspace.tools
interface IntentListener {
fun onClick(type:Int)
}

View File

@ -0,0 +1,56 @@
package com.design.zenspace.tools
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.design.zenspace.R
import com.design.zenspace.entity.Feature
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.request.RequestOptions
import com.design.zenspace.databinding.ItemLikeWallBinding
class LikeWallAdapter: RecyclerView.Adapter<LikeWallAdapter.FeatureViewHolder>() {
private lateinit var context: Context
private var featureList:List<Feature> = emptyList()
private lateinit var listener: SecFavListener
class FeatureViewHolder(val binding: ItemLikeWallBinding): RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FeatureViewHolder {
context=parent.context
val binding= ItemLikeWallBinding.inflate(LayoutInflater.from(context),parent,false)
return FeatureViewHolder(binding)
}
fun setList(list: List<Feature>){
this.featureList=list
}
override fun getItemCount(): Int {
return featureList.size
}
override fun onBindViewHolder(holder: FeatureViewHolder, position: Int) {
val item= featureList[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: SecFavListener){
this.listener=listener
}
}

View File

@ -0,0 +1,56 @@
package com.design.zenspace.tools
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.design.zenspace.R
import com.design.zenspace.entity.Feature
import com.design.zenspace.databinding.ItemMoreAndSearchBinding
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.request.RequestOptions
class MoreAndSearchAdapter: RecyclerView.Adapter<MoreAndSearchAdapter.DoubleViewHolder>() {
private lateinit var context:Context
private var list:List<Feature> = emptyList()
private lateinit var listener:SecFavListener
class DoubleViewHolder(val binding: ItemMoreAndSearchBinding): RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DoubleViewHolder {
context=parent.context
val binding=ItemMoreAndSearchBinding.inflate(LayoutInflater.from(context),parent,false)
return DoubleViewHolder(binding)
}
fun setList(list: List<Feature>){
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: SecFavListener){
this.listener=listener
}
}

View File

@ -0,0 +1,103 @@
package com.design.zenspace.tools
import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.content.ContextCompat
import com.design.zenspace.entity.Feature
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 SaveUtil {
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<Feature> {
val jsonArray = JSONArray(data)
val featureList = mutableListOf<Feature>()
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 feature: Feature
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"))
feature = Feature().apply {
imId = mid
classificationName = name
description = _description
fullUrl = download
previewUrl1080 = regular
previewUrl400 = small
previewUrl200 = thumb
}
featureList.add(feature)
}
return featureList
}
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,7 @@
package com.design.zenspace.tools
import com.design.zenspace.entity.Feature
interface SecFavListener {
fun inItemClick(feature:Feature)
}

View File

@ -0,0 +1,132 @@
package com.design.zenspace.tools
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 SetWayUtils {
private val LOGGER = Logger.getLogger(SetWayUtils::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,67 @@
package com.design.zenspace.tools
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.design.zenspace.R
class TagAdapter(
private val tagList: MutableList<TagItem>,
private val onTagClickListener: (TagItem, Int) -> Unit
): RecyclerView.Adapter<TagAdapter.TagViewHolder>() {
private var selectedPosition = 0
inner class TagViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val tagButton: TextView = itemView.findViewById(R.id.tv_tag)
fun bind(tagItem: TagItem, position: Int) {
tagButton.text = tagItem.name
// 设置选中状态样式
if (position == selectedPosition) {
tagButton.setBackgroundResource(R.drawable.tag_selected_bg)
tagButton.setTextColor(ContextCompat.getColor(itemView.context, R.color.white))
} else {
tagButton.setBackgroundResource(R.drawable.tag_normal_bg)
tagButton.setTextColor(ContextCompat.getColor(itemView.context, R.color.black))
}
// 点击事件
tagButton.setOnClickListener {
if (selectedPosition != position) {
// 更新之前选中的item
val previousPosition = selectedPosition
selectedPosition = position
notifyItemChanged(previousPosition)
notifyItemChanged(position)
onTagClickListener(tagItem, position)
}
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TagViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_tag, parent, false)
return TagViewHolder(view)
}
override fun onBindViewHolder(holder: TagViewHolder, position: Int) {
holder.bind(tagList[position], position)
}
override fun getItemCount(): Int = tagList.size
fun setData(newList: List<TagItem>) {
tagList.clear()
tagList.addAll(newList)
selectedPosition = 0 // 默认选中第一个
notifyDataSetChanged()
}
fun getSelectedPosition(): Int = selectedPosition
}

View File

@ -0,0 +1,7 @@
package com.design.zenspace.tools
data class TagItem(
val id: Int,
val name: String,
var isSelected: Boolean = false
)

View File

@ -0,0 +1,24 @@
package com.design.zenspace.tools
import android.graphics.Color
import android.view.View
import android.view.Window
object TopBarUtils {
// 设置状态栏透明
fun setStatusBar(window: Window) {
window.statusBarColor = Color.TRANSPARENT
window.decorView.systemUiVisibility =
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
}
// 设置状态栏黑色字体
fun setLightStatusBar(window: Window, isLight: Boolean) {
var systemUiVisibility = window.decorView.systemUiVisibility
systemUiVisibility = if (isLight) {
systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
} else {
systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
}
window.decorView.systemUiVisibility = systemUiVisibility
}
}

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,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:topLeftRadius="5dp" android:topRightRadius="5dp"/>
<solid android:color="@color/navigation_bar_color"/>
</shape>

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="12dp"/>
<stroke android:color="@color/text_tint" android:width="1dp"/>
</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/text_tint"/>
</vector>

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,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="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,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,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/text_tint"/>
</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/preview_full" android:state_selected="true" />
<item android:drawable="@drawable/preview_stroke" />
</selector>

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="#e6e6e6" />
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="10dp" />
<gradient
android:angle="0"
android:endColor="@color/text_tint"
android:centerColor="@color/text_start_progress"
android:startColor="@color/text_start_progress" />
</shape>
</clip>
</item>
</layer-list>

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/text_tint"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

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/text_tint"/>
<path
android:pathData="M993.3,12.4v692.7h-287.2v-90.4h196.8v-512h-512v224.4h-90.4V12.4z"
android:fillColor="@color/text_tint"/>
</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/text_tint"
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,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/text_tint"
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,16 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
android:width="2dp"
android:color="@color/text_tint" />
<!-- 线性渐变配置 -->
<gradient
android:type="linear"
android:startColor="@color/white"
android:endColor="@color/white"
android:angle="0"
/>
<corners android:radius="25dp"/>
</shape>

View File

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

View File

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

View File

@ -0,0 +1,103 @@
<?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"
android:background="@color/white"
android:orientation="vertical"
tools:context=".preview.CateAndLikActivity">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/bg_pix"
app:layout_constraintTop_toTopOf="parent"
android:scaleType="fitXY"/>
<LinearLayout
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingVertical="20dp"
android:layout_marginTop="20dp"
app:layout_constraintTop_toTopOf="parent"
android:orientation="horizontal">
<RelativeLayout
android:id="@+id/rlSearch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/every_out_stroke"
android:layout_marginHorizontal="25dp"
android:padding="8dp"
android:descendantFocusability="blocksDescendants"
android:layout_gravity="end">
<ImageView
android:id="@+id/imgSearch"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/search_grey"
app:tint="@color/text_tint"
android:layout_centerVertical="true" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/text_normal"
android:layout_marginStart="30dp"
android:textSize="15sp"
android:text="@string/find_more"/>
</RelativeLayout>
</LinearLayout>
<FrameLayout
android:id="@+id/fragmentIn"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@+id/title"
app:layout_constraintBottom_toTopOf="@+id/llBottom" />
<LinearLayout
android:id="@+id/llBottom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:background="@drawable/cate_and_like_bottom"
android:paddingBottom="10dp"
app:layout_constraintBottom_toBottomOf="parent"
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="10dp"
android:layout_weight="1"
>
<TextView
android:id="@+id/tvStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/text_normal"
android:textSize="16sp"
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"
>
<TextView
android:id="@+id/tvEnd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/text_normal"
android:textSize="16sp"
android:text="@string/like"/>
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,49 @@
<?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=".preview.ComeInActivity">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/bg_pix"
app:layout_constraintTop_toTopOf="parent"
android:scaleType="fitXY"/>
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/imageview_logo"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="260dp"
android:src="@mipmap/ic_launcher_round"
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="20dp"
android:text="@string/app_name"
android:textColor="@color/text_tint"
android:textStyle="bold"
android:textSize="28sp"/>
<ProgressBar
android:id="@+id/progressbar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="8dp"
android:layout_centerHorizontal="true"
android:layout_below="@+id/tvLogo"
android:layout_marginHorizontal="50dp"
android:max="100"
android:layout_marginTop="30dp"
android:progress="80"
android:indeterminateTint="@color/white"
android:progressDrawable="@drawable/progress_bar_grey_bg" />
</RelativeLayout>

View File

@ -0,0 +1,117 @@
<?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=".preview.FindSomeActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="45dp"
android:orientation="horizontal">
<RelativeLayout
android:id="@+id/rlSearch"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="40dp"
android:layout_marginStart="20dp"
android:background="@drawable/every_out_stroke"
android:gravity="center"
android:layout_gravity="center">
<ImageView
android:id="@+id/imgSearch"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/find_some_ic"
app:tint="@color/text_tint"
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="15sp"
android:imeOptions="actionSearch"
android:background="@null"
android:maxLines="1"
android:inputType="text"
android:layout_marginEnd="60dp"
android:textColorHint="@color/text_normal"
android:layout_marginStart="10dp"
android:hint="@string/input_name_or_keyword"/>
<TextView
android:id="@+id/tvStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5sp"
android:text="@string/search"
android:textSize="16sp"
android:visibility="gone"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:layout_marginEnd="10dp"
android:textColor="@color/black"
/>
</RelativeLayout>
<ImageView
android:id="@+id/imageBack"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_gravity="center"
android:padding="13dp"
android:src="@drawable/close_return"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginEnd="10dp"
app:tint="@color/black" />
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:layout_marginHorizontal="20dp">
<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/kongshuju" />
<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/text_tint"
android:visibility="gone" />
</RelativeLayout>
</LinearLayout>

View File

@ -0,0 +1,112 @@
<?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">
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/bg_placeholder"
android:scaleType="centerCrop" />
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/preview_img_before"/>
<LinearLayout
android:id="@+id/layout_top"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="45dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/imageBack"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_gravity="center"
android:layout_marginStart="8dp"
android:padding="15dp"
android:src="@drawable/close_now_page"
app:tint="@color/black"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1"/>
</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/navigation_bar_color"
android:textSize="18sp"
android:textStyle="bold"
android:layout_marginBottom="90dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/layout_top"
android:orientation="horizontal">
<ImageView
android:id="@+id/imageLike"
android:layout_width="60dp"
android:layout_height="60dp"
android:padding="15dp"
android:src="@drawable/preview_stroke_full" />
<RelativeLayout
android:id="@+id/layout_download"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/imageDownload"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_centerInParent="true"
android:padding="15dp"
android:src="@drawable/pull_down_icon" />
<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>
<ImageView
android:id="@+id/layout_set"
android:layout_width="60dp"
android:layout_height="60dp"
android:padding="14dp"
app:tint="@color/text_tint"
android:src="@drawable/phone_setting"/>
</LinearLayout>
<ProgressBar
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:id="@+id/pbSet"
android:layout_width="55dp"
android:layout_height="55dp"
android:layout_centerInParent="true"
android:indeterminateTint="@color/text_tint"
android:visibility="gone" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,48 @@
<?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:background="@mipmap/bg_pix"
android:layout_height="match_parent">
<TextView
android:id="@+id/tvTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/text_selected"
android:textSize="20sp"
android:layout_marginHorizontal="20dp"
android:text="@string/collect_your_favorite_wallpapers"/>
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginHorizontal="5dp"
android:layout_marginTop="20dp"
android:layout_below="@+id/tvTitle"
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="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:src="@drawable/kongshuju" />
<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/black"
android:layout_marginBottom="50dp"
android:textSize="14sp" />
</LinearLayout>
</RelativeLayout>

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/show_way_bg"
android:padding="10dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingVertical="20dp">
<LinearLayout
android:id="@+id/layout_home"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="64dp"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="34dp"
android:layout_height="34dp"
android:src="@drawable/set_wall_way_3" />
<TextView
android:id="@+id/home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:text="@string/apply_to_desktop"
android:textAlignment="center"
android:textColor="@color/text_tint"
android:textSize="12sp" />
</LinearLayout>
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:background="@color/text_tint" />
<LinearLayout
android:id="@+id/layout_lock"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="64dp"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="34dp"
android:layout_height="34dp"
android:src="@drawable/set_wall_way_2" />
<TextView
android:id="@+id/lock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/apply_to_lock_screen"
android:textStyle="bold"
android:textAlignment="center"
android:textColor="@color/text_tint"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginHorizontal="10dp"
android:background="@color/text_tint" />
<LinearLayout
android:id="@+id/layout_both"
android:layout_width="match_parent"
android:layout_height="64dp"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="34dp"
android:layout_height="34dp"
android:src="@drawable/set_wall_way_1" />
<TextView
android:id="@+id/both"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/apply_to_all"
android:textStyle="bold"
android:textColor="@color/text_tint"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@mipmap/bg_pix">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_tags"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:layout_marginHorizontal="10dp"
app:layout_constraintTop_toBottomOf="@+id/rv_tags"
app:layout_constraintBottom_toBottomOf="parent"/>
<ProgressBar
android:id="@+id/searchPb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:indeterminateTint="@color/text_tint"
android:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,25 @@
<?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="210dp"
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/preview_img_before" />
</androidx.cardview.widget.CardView>
</LinearLayout>

View File

@ -0,0 +1,15 @@
<?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="180dp"
android:scaleType="centerCrop"
android:src="@mipmap/bg_placeholder" />
</androidx.cardview.widget.CardView>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp">
<TextView
android:id="@+id/tv_tag"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:paddingHorizontal="5dp"
android:paddingVertical="8dp"
android:textSize="13sp"
android:gravity="center"
android:background="@drawable/tag_normal_bg" />
</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.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

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