接入tradplus

This commit is contained in:
yuqian 2025-12-16 10:58:51 +08:00
commit 29541ffbe5
138 changed files with 169411 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-05T06:38:25.784324800Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=659PX8INFIUKHYXK" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState>
</selectionStates>
</component>
</project>

13
.idea/deviceManager.xml generated Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DeviceTable">
<option name="columnSorters">
<list>
<ColumnSorterState>
<option name="column" value="Name" />
<option name="order" value="ASCENDING" />
</ColumnSorterState>
</list>
</option>
</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>

10
.idea/migrations.xml generated Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

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

@ -0,0 +1,9 @@
<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">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</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>

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

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings" defaultProject="true" />
</project>

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

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

@ -0,0 +1,70 @@
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")
}
android {
namespace = "com.paperapp.lenscape"
compileSdk {
version = release(36)
}
val timestamp = SimpleDateFormat("MM_dd_HH_mm").format(Date())
defaultConfig {
applicationId = "com.paperapp.lenscape"
minSdk = 26
targetSdk = 36
versionCode = 1
versionName = "1.0"
setProperty("archivesBaseName", "Lenscape_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"))
}

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

@ -0,0 +1,29 @@
{
"project_info": {
"project_number": "128607601276",
"project_id": "lenscape-39cbf",
"storage_bucket": "lenscape-39cbf.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:128607601276:android:280275f1d10184418d3ff9",
"android_client_info": {
"package_name": "com.paperapp.lenscape"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyDSj0iKMCLL5VYWkAVpnlayLtexLd0D6VY"
}
],
"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.paperapp.lenscape",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0",
"outputFile": "Lenscape_V1.0_1_12_05_16_26-release.apk"
}
],
"elementType": "File",
"baselineProfiles": [
{
"minApi": 28,
"maxApi": 30,
"baselineProfiles": [
"baselineProfiles/1/Lenscape_V1.0_1_12_05_16_26-release.dm"
]
},
{
"minApi": 31,
"maxApi": 2147483647,
"baselineProfiles": [
"baselineProfiles/0/Lenscape_V1.0_1_12_05_16_26-release.dm"
]
}
],
"minSdkVersionForDexing": 26
}

View File

@ -0,0 +1,24 @@
package com.paperapp.lenscape
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.paperapp.lenscape", appContext.packageName)
}
}

View File

@ -0,0 +1,42 @@
<?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:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:name=".DApp"
android:theme="@style/Theme.Lenscape">
<activity
android:name=".preview.MemberAccessActivity"
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.BrowseActivity"
android:exported="false" />
<activity
android:name=".preview.SortActivity"
android:exported="false" />
<activity
android:name=".preview.ImagePreviewActivity"
android:theme="@style/Base.Theme.Lenscape"
android:exported="false" />
</application>
</manifest>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 KiB

View File

@ -0,0 +1,83 @@
package com.paperapp.lenscape
import android.app.Application
import android.util.Log
import com.paperapp.lenscape.element.AppDataBase
import com.paperapp.lenscape.element.ElementDao
import com.paperapp.lenscape.tools.ImagePreUtil
import com.up.uploadlibrary.UpLoadManager
import java.io.IOException
class DApp : 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 = "Elementd.json"
companion object {
var classificationList: MutableList<String> = mutableListOf()
var isDataInitialized = false
private set
const val TAG = "DApp"
}
override fun onCreate() {
super.onCreate()
UpLoadManager.init(this, TAG) { _, _ ->
// 处理逻辑
null
Log.d(TAG, "upload success")
}
val database = AppDataBase.getDatabase(this)
val paperDao = database.elementDao()
Thread {
initializeData(paperDao)
isDataInitialized = true
}.start()
}
private fun initializeData(paperDao: ElementDao) {
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 = ImagePreUtil.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 element = ImagePreUtil.getData(jsonData, classificationName)
// 批量插入数据
if (element.isNotEmpty()) {
// 使用批量插入方法
paperDao.insertAll(element)
Log.d("DataInit", "[$classificationName] insert ${element.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,25 @@
package com.paperapp.lenscape
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,23 @@
package com.paperapp.lenscape.element
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
@Database(entities = [Element::class], version = 1, exportSchema = false)
abstract class AppDataBase:RoomDatabase() {
abstract fun elementDao():ElementDao
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.paperapp.lenscape.element
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 = "element",
indices = [Index(value = ["imId"], unique = true)])
data class Element(
@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.paperapp.lenscape.element
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 ElementDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun insertAll(element: List<Element>)
@Update
suspend fun update(element: Element)
@Query("SELECT * FROM element WHERE imId=:imId")
suspend fun getById(imId: String): Element?
@Query("SELECT * FROM element WHERE classificationName=:name LIMIT 6 OFFSET 20")
suspend fun queryCover(name: String): List<Element>
@Query("SELECT * FROM element WHERE classificationName=:name")
suspend fun queryEachGenera(name: String): List<Element>
@Query("SELECT * FROM element WHERE is_like = 1")
fun queryLikeElement(): LiveData<List<Element>>
@Query("SELECT * FROM element WHERE description LIKE '%'||:name||'%'")
suspend fun search(name: String): List<Element>
@Query("SELECT * FROM element WHERE imId = :imId AND is_like = 1")
suspend fun queryIsLike(imId: String): Element?
@Query("SELECT * FROM element")
suspend fun getAllElements(): List<Element>
}

View File

@ -0,0 +1,28 @@
package com.paperapp.lenscape.element
import androidx.lifecycle.LiveData
class ElementRepository(private val elementDao: ElementDao) {
suspend fun allElement():List<Element>{
return elementDao.getAllElements()
}
suspend fun updateElement(element: Element){
elementDao.update(element)
}
suspend fun getElementById(id:String):Element?{
return elementDao.getById(id)
}
suspend fun getClassificationCover(name:String):List<Element>{
return elementDao.queryCover(name)
}
suspend fun getElementByClassification(name: String):List<Element>{
return elementDao.queryEachGenera(name)
}
fun getLikes():LiveData<List<Element>>{
return elementDao.queryLikeElement()
}
suspend fun searchByKey(key:String):List<Element>{
return elementDao.search(key)
}
suspend fun isLike(id: String): Boolean = elementDao.queryIsLike(id) != null
}

View File

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

View File

@ -0,0 +1,130 @@
package com.paperapp.lenscape.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.paperapp.lenscape.R
import com.paperapp.lenscape.databinding.ActivityBrowseBinding
import com.paperapp.lenscape.tools.BrowseAdapter
import com.paperapp.lenscape.element.MainViewModel
import com.paperapp.lenscape.element.Element
import com.paperapp.lenscape.tools.SetLoveListener
import com.paperapp.lenscape.TopBarUtils
class BrowseActivity : AppCompatActivity(), SetLoveListener {
lateinit var binding: ActivityBrowseBinding
private lateinit var viewModel: MainViewModel
private lateinit var adapter: BrowseAdapter
private var resultList: List<Element> = emptyList()
private var searchKey = ""
private var isClick = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityBrowseBinding.inflate(layoutInflater)
setContentView(binding.root)
TopBarUtils.setStatusBar(this.window)
TopBarUtils.setLightStatusBar(this.window,true)
init()
}
private fun init() {
viewModel = ViewModelProvider(this)[MainViewModel::class.java]
adapter = BrowseAdapter()
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
}
binding.imageClear.setOnClickListener {
binding.editText.setText("")
}
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.imageClear.visibility = View.VISIBLE
} else {
binding.imageClear.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: Element) {
val intent = Intent(this, ImagePreviewActivity::class.java)
intent.putExtra(ImagePreviewActivity.paperKey, paper)
startActivity(intent)
}
}

View File

@ -0,0 +1,251 @@
package com.paperapp.lenscape.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.paperapp.lenscape.tools.TagMoveHelper
import com.paperapp.lenscape.DApp
import com.paperapp.lenscape.databinding.FragmentFilterBinding
import com.paperapp.lenscape.tools.FilterAdapter
import com.paperapp.lenscape.tools.TagFilterItem
import com.paperapp.lenscape.element.Element
import com.paperapp.lenscape.element.MainViewModel
import com.paperapp.lenscape.tools.BrowseAdapter
import com.paperapp.lenscape.tools.SetLoveListener
import kotlin.math.abs
class FilterFragment : Fragment(),SetLoveListener {
private lateinit var binding: FragmentFilterBinding
private lateinit var viewModel:MainViewModel
private lateinit var tagAdapter: FilterAdapter
private val snapHelper = TagMoveHelper()
private var isScrolling = false
private var pendingScrollPosition = -1
private lateinit var adapter:BrowseAdapter
private val tagList = mutableListOf<TagFilterItem>()
private var currentTagName = ""
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding=FragmentFilterBinding.inflate(inflater,container,false)
val classificationList = DApp.classificationList
viewModel=ViewModelProvider(this)[MainViewModel::class.java]
for(index in 0 until classificationList.size){
tagList.add(TagFilterItem(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 = FilterAdapter(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 = BrowseAdapter()
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<Element>) {
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(element: Element) {
val intent= Intent(requireActivity(),ImagePreviewActivity::class.java)
intent.putExtra(ImagePreviewActivity.paperKey,element)
startActivity(intent)
}
}

View File

@ -0,0 +1,104 @@
package com.paperapp.lenscape.preview
import android.graphics.Color
import android.view.Gravity
import android.view.LayoutInflater
import android.view.ViewGroup
import android.view.Window
import com.paperapp.lenscape.R
import com.paperapp.lenscape.databinding.FragmentDialogGuideBinding
import com.paperapp.lenscape.tools.OnclickListener
import androidx.core.graphics.drawable.toDrawable
class GuideDialog : androidx.fragment.app.DialogFragment() {
private lateinit var vb: FragmentDialogGuideBinding
private var listener: OnclickListener? = null
private var currentType = -1
companion object {
const val TYPE_HOME = 0
const val TYPE_LOCK = 1
const val TYPE_BOTH = 2
}
fun setListener(listener: OnclickListener?) {
this.listener = listener
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: android.os.Bundle?
): android.view.View {
vb = FragmentDialogGuideBinding.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 {
currentType=TYPE_HOME
setUIChange()
}
vb.layoutLock.setOnClickListener {
currentType=TYPE_LOCK
setUIChange()
}
vb.layoutBoth.setOnClickListener {
currentType=TYPE_BOTH
setUIChange()
}
vb.cancel.setOnClickListener { dismiss() }
vb.confirm.setOnClickListener {
listener?.onClick(currentType)
dismiss()}
}
private fun setUIChange(){
if(currentType==TYPE_HOME){
vb.layoutHome.isSelected=true
vb.layoutLock.isSelected=false
vb.layoutBoth.isSelected=false
}else if(currentType==TYPE_LOCK){
vb.layoutHome.isSelected=false
vb.layoutLock.isSelected=true
vb.layoutBoth.isSelected=false
}else{
vb.layoutHome.isSelected=false
vb.layoutLock.isSelected=false
vb.layoutBoth.isSelected=true
}
}
}

View File

@ -0,0 +1,312 @@
package com.paperapp.lenscape.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.paperapp.lenscape.R
import com.paperapp.lenscape.element.MainViewModel
import com.paperapp.lenscape.element.Element
import com.paperapp.lenscape.tools.OnclickListener
import com.paperapp.lenscape.tools.SetWayUtils
import com.paperapp.lenscape.tools.ImagePreUtil
import com.paperapp.lenscape.TopBarUtils
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.request.RequestOptions
import com.paperapp.lenscape.databinding.ActivityImagePreviewBinding
import okhttp3.Call
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
class ImagePreviewActivity : AppCompatActivity(), OnclickListener {
companion object {
var paperKey = "wallpaperData"
}
private lateinit var binding: ActivityImagePreviewBinding
lateinit var paper: Element
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: GuideDialog
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 = ImagePreUtil.getStoragePermissions()
if (ImagePreUtil.hasStoragePermission(this)) {
isGranted = true
} else {
storagePermissionLauncher.launch(permissions)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityImagePreviewBinding.inflate(layoutInflater)
setContentView(binding.root)
TopBarUtils.setStatusBar(this.window)
TopBarUtils.setLightStatusBar(this.window,true)
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 = ImagePreUtil.getSaveFilePath(this, paper.imId)
downloadedFile = File(fileSavePath)
setDialog = GuideDialog()
setDialog.setListener(this@ImagePreviewActivity)
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) {
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@ImagePreviewActivity,
getString(R.string.save_fail),
Toast.LENGTH_SHORT
).show()
} else {
Toast.makeText(
this@ImagePreviewActivity,
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@ImagePreviewActivity,
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@ImagePreviewActivity,
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) {
GuideDialog.TYPE_HOME -> {
// FLAG_SYSTEM 表示设置为主屏幕壁纸
wallpaperManager.setStream(
fileInputStream,
null,
true,
WallpaperManager.FLAG_SYSTEM
)
}
GuideDialog.TYPE_LOCK -> {
// FLAG_LOCK 设置为锁屏壁纸
wallpaperManager.setStream(
fileInputStream,
null,
true,
WallpaperManager.FLAG_LOCK
)
}
GuideDialog.TYPE_BOTH -> {
// 同时设置主屏和锁屏壁纸
wallpaperManager.setStream(fileInputStream)
}
else -> {}
}
}
if(!isActivityAlive()) return
runOnUiThread {
showSetWallpaperLoading(false)
Toast.makeText(
this@ImagePreviewActivity,
getString(R.string.set_success),
Toast.LENGTH_SHORT
).show()
}
} catch (e: Exception) {
if(!isActivityAlive()) return
runOnUiThread {
showSetWallpaperLoading(false)
Toast.makeText(
this@ImagePreviewActivity,
getString(R.string.set_fail),
Toast.LENGTH_SHORT
).show()
}
}
}
}

View File

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

View File

@ -0,0 +1,50 @@
package com.paperapp.lenscape.preview
import android.content.Intent
import android.os.Bundle
import android.os.CountDownTimer
import android.os.Handler
import androidx.appcompat.app.AppCompatActivity
import com.paperapp.lenscape.databinding.ActivityMemberAccessBinding
import com.paperapp.lenscape.TopBarUtils
class MemberAccessActivity : AppCompatActivity() {
lateinit var binding: ActivityMemberAccessBinding
private var handler: Handler = Handler()
private var countDownTimer: CountDownTimer? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMemberAccessBinding.inflate(layoutInflater)
setContentView(binding.root)
TopBarUtils.setStatusBar(this.window)
TopBarUtils.setLightStatusBar(this.window,true)
handler.postDelayed({
val intent= Intent(
this@MemberAccessActivity,
SortActivity::class.java
)
startActivity(intent)
finish()
}, 4000)
countDownTimer = object : CountDownTimer(4000, 100) {
override fun onTick(millisUntilFinished: Long) {
val progress = ((4000 - millisUntilFinished) / 4000f * 100).toInt()
binding.progressbar.progress = progress
}
override fun onFinish() {
binding.progressbar.progress = 100
}
}.start()
}
override fun onDestroy() {
super.onDestroy()
handler.removeCallbacksAndMessages(null)
if (countDownTimer != null) {
countDownTimer!!.cancel()
}
}
}

View File

@ -0,0 +1,134 @@
package com.paperapp.lenscape.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.paperapp.lenscape.R
import com.paperapp.lenscape.element.MainViewModel
import com.paperapp.lenscape.databinding.ActivitySortBinding
import com.paperapp.lenscape.TopBarUtils
class SortActivity : AppCompatActivity() {
private lateinit var binding: ActivitySortBinding
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 = ActivitySortBinding.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.black)
val selectColor = getColor(R.color.green_5)
binding.tvStart.setTextColor(defaultColor)
binding.tvEnd.setTextColor(defaultColor)
when (position) {
0 -> {
binding.tvStart.setTextColor(selectColor)
binding.tvEnd.setTextColor(defaultColor)
binding.rlSearch.visibility = View.VISIBLE
binding.viewLine1.visibility = View.VISIBLE
binding.viewLine2.visibility = View.GONE
binding.img1.isSelected = true
binding.img2.isSelected = false
}
1 -> {
binding.tvEnd.setTextColor(selectColor)
binding.tvStart.setTextColor(defaultColor)
binding.rlSearch.visibility = View.GONE
binding.viewLine1.visibility = View.GONE
binding.viewLine2.visibility = View.VISIBLE
binding.img1.isSelected = false
binding.img2.isSelected = true
}
}
}
private fun initFragments() {
tagShowFragment = FilterFragment()
collectWallFragment = LikedWallpapersFragment()
}
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, BrowseActivity::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,56 @@
package com.paperapp.lenscape.tools
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.paperapp.lenscape.R
import com.paperapp.lenscape.element.Element
import com.paperapp.lenscape.databinding.ItemMoreAndSearchBinding
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.request.RequestOptions
class BrowseAdapter: RecyclerView.Adapter<BrowseAdapter.DoubleViewHolder>() {
private lateinit var context:Context
private var list:List<Element> = emptyList()
private lateinit var listener:SetLoveListener
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<Element>){
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: SetLoveListener){
this.listener=listener
}
}

View File

@ -0,0 +1,67 @@
package com.paperapp.lenscape.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.paperapp.lenscape.R
class FilterAdapter(
private val tagList: MutableList<TagFilterItem>,
private val onTagClickListener: (TagFilterItem, Int) -> Unit
): RecyclerView.Adapter<FilterAdapter.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: TagFilterItem, position: Int) {
tagButton.text = tagItem.name
// 设置选中状态样式
if (position == selectedPosition) {
tagButton.setBackgroundResource(R.drawable.tag_full_bg)
tagButton.setTextColor(ContextCompat.getColor(itemView.context, R.color.green_1))
} else {
tagButton.setBackgroundResource(R.drawable.tag_null_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_each_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<TagFilterItem>) {
tagList.clear()
tagList.addAll(newList)
selectedPosition = 0 // 默认选中第一个
notifyDataSetChanged()
}
fun getSelectedPosition(): Int = selectedPosition
}

View File

@ -0,0 +1,103 @@
package com.paperapp.lenscape.tools
import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.content.ContextCompat
import com.paperapp.lenscape.element.Element
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 ImagePreUtil {
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<Element> {
val jsonArray = JSONArray(data)
val elementList = mutableListOf<Element>()
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 element: Element
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"))
element = Element().apply {
imId = mid
classificationName = name
description = _description
fullUrl = download
previewUrl1080 = regular
previewUrl400 = small
previewUrl200 = thumb
}
elementList.add(element)
}
return elementList
}
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,56 @@
package com.paperapp.lenscape.tools
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.paperapp.lenscape.R
import com.paperapp.lenscape.element.Element
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.request.RequestOptions
import com.paperapp.lenscape.databinding.ItemLikeWallBinding
class LikeWallpapersAdapter: RecyclerView.Adapter<LikeWallpapersAdapter.ElementViewHolder>() {
private lateinit var context: Context
private var elementList:List<Element> = emptyList()
private lateinit var listener: SetLoveListener
class ElementViewHolder(val binding: ItemLikeWallBinding): RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ElementViewHolder {
context=parent.context
val binding= ItemLikeWallBinding.inflate(LayoutInflater.from(context),parent,false)
return ElementViewHolder(binding)
}
fun setList(list: List<Element>){
this.elementList=list
}
override fun getItemCount(): Int {
return elementList.size
}
override fun onBindViewHolder(holder: ElementViewHolder, position: Int) {
val item= elementList[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: SetLoveListener){
this.listener=listener
}
}

View File

@ -0,0 +1,5 @@
package com.paperapp.lenscape.tools
interface OnclickListener {
fun onClick(type:Int)
}

View File

@ -0,0 +1,7 @@
package com.paperapp.lenscape.tools
import com.paperapp.lenscape.element.Element
interface SetLoveListener {
fun inItemClick(element:Element)
}

View File

@ -0,0 +1,132 @@
package com.paperapp.lenscape.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,7 @@
package com.paperapp.lenscape.tools
data class TagFilterItem(
val id: Int,
val name: String,
var isSelected: Boolean = false
)

View File

@ -0,0 +1,69 @@
package com.paperapp.lenscape.tools
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSnapHelper
import androidx.recyclerview.widget.RecyclerView
class TagMoveHelper : 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,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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

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

View File

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

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/give_good_0" android:state_selected="false"/>
<item android:drawable="@drawable/give_good_1"/>
</selector>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/file_cho_0" android:state_selected="false"/>
<item android:drawable="@drawable/file_cho_1"/>
</selector>

View File

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

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

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/green_5"/>
</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>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="false" android:drawable="@android:color/transparent"/>
<item android:drawable="@drawable/choose_style"/>
</selector>

View File

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

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="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: 6.2 KiB

View File

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

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="28dp" android:topRightRadius="28dp"/>
<solid android:color="@color/green_2_nav"/>
</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/green_5"/>
</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/green_5" />
<!-- 线性渐变配置 -->
<gradient
android:type="linear"
android:startColor="@color/green_2_nav"
android:endColor="@color/green_2_nav"
android:angle="0"
/>
<corners android:radius="25dp"/>
</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/green_5" />
<corners android:radius="18dp" />
</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/green_3" />
<stroke
android:width="1dp"
android:color="@color/green_3" />
<corners android:radius="15dp" />
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.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/green_5"/>
<path
android:pathData="M993.3,12.4v692.7h-287.2v-90.4h196.8v-512h-512v224.4h-90.4V12.4z"
android:fillColor="@color/green_5"/>
</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/green_5"
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/green_5"
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,139 @@
<?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/green_1"
android:orientation="vertical"
tools:context=".preview.BrowseActivity">
<ImageView
android:id="@+id/imageBack"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_gravity="start"
android:layout_marginStart="8dp"
android:padding="12dp"
android:src="@drawable/return_last_page"
app:tint="@color/black"
android:layout_marginTop="55dp"
android:layout_marginBottom="10dp"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RelativeLayout
android:id="@+id/rlSearch"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_gravity="center"
android:layout_marginStart="25dp"
android:layout_weight="1"
android:background="@drawable/browse_out_stroke"
android:gravity="center">
<ImageView
android:id="@+id/imgSearch"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_centerVertical="true"
android:layout_marginStart="10dp"
android:src="@drawable/find_some_ic"
app:tint="@color/black" />
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="10dp"
android:layout_marginEnd="30dp"
android:layout_toEndOf="@+id/imgSearch"
android:background="@null"
android:hint="@string/input_name_or_keyword"
android:imeOptions="actionSearch"
android:inputType="text"
android:maxLines="1"
android:textColorHint="@color/grey"
android:textSize="15sp" />
<ImageView
android:id="@+id/imageClear"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_gravity="center"
android:padding="13dp"
android:visibility="gone"
android:src="@drawable/big_x"
app:tint="@color/black" />
</RelativeLayout>
<TextView
android:id="@+id/tvStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="8sp"
android:paddingVertical="6dp"
android:text="@string/search"
android:textSize="16sp"
android:layout_gravity="center"
android:visibility="visible"
android:elevation="4dp"
android:background="@drawable/choose_style"
android:layout_marginEnd="25dp"
android:layout_marginVertical="5dp"
android:layout_marginStart="5dp"
android:textColor="@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:paddingBottom="80dp"
android:orientation="vertical"
android:visibility="gone">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/a_big_plant" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
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/green_5"
android:visibility="gone" />
</RelativeLayout>
</LinearLayout>

View File

@ -0,0 +1,110 @@
<?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_center_tran"/>
<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/return_last_page"
app:tint="@color/black"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
<TextView
android:id="@+id/tvContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:minHeight="40dp"
android:padding="10dp"
android:text="@string/app_name"
android:textColor="@color/white"
android:textSize="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_constraintTop_toBottomOf="@id/tvContent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:background="@drawable/browse_out_stroke"
android:orientation="horizontal">
<ImageView
android:id="@+id/imageLike"
android:layout_width="60dp"
android:layout_height="60dp"
android:padding="15dp"
android:src="@drawable/pink_or_green" />
<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/green_down" />
<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/green_5"
android:src="@drawable/to_select_apply"/>
</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/green_5"
android:visibility="gone" />
</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.MemberAccessActivity">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@color/green_1"
app:layout_constraintTop_toTopOf="parent"
android:scaleType="fitXY"/>
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/imageview_logo"
android:layout_width="130dp"
android:layout_height="130dp"
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="30dp"
android:text="@string/app_name"
android:textColor="@color/black"
android:textStyle="bold"
android:textSize="28sp"/>
<ProgressBar
android:id="@+id/progressbar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="9dp"
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/set_bg_progress" />
</RelativeLayout>

View File

@ -0,0 +1,141 @@
<?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.SortActivity">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@color/green_1"
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_vertical"
android:paddingVertical="20dp"
android:layout_marginTop="40dp"
app:layout_constraintTop_toTopOf="parent"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:textColor="@color/black"
android:textStyle="bold"
android:layout_marginStart="25dp"
android:text="@string/app_name"/>
<RelativeLayout
android:id="@+id/rlSearch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/browse_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_no_color"
app:tint="@color/black"
android:layout_centerVertical="true" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/grey"
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/sort_bottom"
android:paddingBottom="10dp"
android:elevation="8dp"
app:layout_constraintBottom_toBottomOf="parent"
android:orientation="horizontal">
<RelativeLayout
android:id="@+id/llHome"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingVertical="6dp"
android:layout_weight="1"
>
<View
android:id="@+id/viewLine1"
android:layout_width="50dp"
android:layout_centerInParent="true"
android:background="@drawable/choose_style"
android:layout_height="30dp"/>
<ImageView
android:id="@+id/img1"
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_centerInParent="true"
android:src="@drawable/choose_home" />
<TextView
android:id="@+id/tvStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:textSize="13sp"
android:layout_below="@+id/img1"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
android:text="@string/category"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/llLike"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:paddingVertical="6dp"
android:layout_weight="1"
>
<View
android:id="@+id/viewLine2"
android:layout_width="50dp"
android:layout_centerInParent="true"
android:visibility="gone"
android:background="@drawable/choose_style"
android:layout_height="30dp"/>
<ImageView
android:id="@+id/img2"
android:layout_width="26dp"
android:layout_height="26dp"
android:padding="3dp"
android:layout_centerInParent="true"
android:src="@drawable/choose_good" />
<TextView
android:id="@+id/tvEnd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:layout_below="@+id/img2"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
android:textSize="13sp"
android:text="@string/like"/>
</RelativeLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,113 @@
<?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/stroke_green_bg"
android:padding="20dp"
android:orientation="vertical">
<LinearLayout
android:id="@+id/layout_home"
android:layout_width="match_parent"
android:layout_height="64dp"
android:gravity="center"
android:background="@drawable/dialog_sel"
android:orientation="horizontal">
<ImageView
android:layout_width="34dp"
android:layout_height="34dp"
android:src="@drawable/type_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/green_5"
android:textSize="18sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_lock"
android:layout_width="match_parent"
android:layout_height="64dp"
android:gravity="center"
android:background="@drawable/dialog_sel"
android:orientation="horizontal">
<ImageView
android:layout_width="34dp"
android:layout_height="34dp"
android:src="@drawable/type_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/green_5"
android:textSize="18sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_both"
android:layout_width="match_parent"
android:layout_height="64dp"
android:gravity="center"
android:background="@drawable/dialog_sel"
android:orientation="horizontal">
<ImageView
android:layout_width="34dp"
android:layout_height="34dp"
android:src="@drawable/type_1" />
<TextView
android:id="@+id/both"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/apply_to_all"
android:layout_marginStart="4dp"
android:textStyle="bold"
android:textColor="@color/green_5"
android:textSize="18sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:orientation="horizontal">
<TextView
android:id="@+id/cancel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAlignment="center"
android:paddingVertical="10dp"
android:textSize="18sp"
android:background="@drawable/browse_out_stroke"
android:text="@string/cancel"/>
<TextView
android:id="@+id/confirm"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textAlignment="center"
android:textSize="18sp"
android:paddingVertical="10dp"
android:layout_marginStart="10dp"
android:textColor="@color/white"
android:background="@drawable/choose_confirm"
android:text="@string/confirm"/>
</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="@color/green_1">
<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/green_5"
android:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,38 @@
<?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="@color/green_1"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginHorizontal="5dp"
android:id="@+id/rvView"/>
<LinearLayout
android:id="@+id/layout_no_data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical"
android:visibility="gone">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:src="@drawable/a_big_plant" />
<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,18 @@
<?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="14dp"
android:textSize="15sp"
android:textStyle="bold"
android:gravity="center"
android:background="@drawable/tag_null_bg" />
</LinearLayout>

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="8dp">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="20dp">
<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>

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