first commit

This commit is contained in:
ocean 2025-12-24 15:41:49 +08:00
commit a3eb7f6f2d
163 changed files with 174157 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

1
.idea/.name generated Normal file
View File

@ -0,0 +1 @@
DreamWallpapers

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>

435
.idea/dbnavigator.xml generated Normal file
View File

@ -0,0 +1,435 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DBNavigator.Project.DDLFileAttachmentManager">
<mappings />
<preferences />
</component>
<component name="DBNavigator.Project.DatabaseAssistantManager">
<assistants />
</component>
<component name="DBNavigator.Project.DatabaseBrowserManager">
<autoscroll-to-editor value="false" />
<autoscroll-from-editor value="true" />
<show-object-properties value="true" />
<loaded-nodes />
</component>
<component name="DBNavigator.Project.DatabaseFileManager">
<open-files />
</component>
<component name="DBNavigator.Project.Settings">
<connections />
<browser-settings>
<general>
<display-mode value="TABBED" />
<navigation-history-size value="100" />
<show-object-details value="false" />
<enable-sticky-paths value="true" />
</general>
<filters>
<object-type-filter>
<object-type name="SCHEMA" enabled="true" />
<object-type name="USER" enabled="true" />
<object-type name="ROLE" enabled="true" />
<object-type name="PRIVILEGE" enabled="true" />
<object-type name="CHARSET" enabled="true" />
<object-type name="TABLE" enabled="true" />
<object-type name="VIEW" enabled="true" />
<object-type name="MATERIALIZED_VIEW" enabled="true" />
<object-type name="NESTED_TABLE" enabled="true" />
<object-type name="COLUMN" enabled="true" />
<object-type name="INDEX" enabled="true" />
<object-type name="CONSTRAINT" enabled="true" />
<object-type name="DATASET_TRIGGER" enabled="true" />
<object-type name="DATABASE_TRIGGER" enabled="true" />
<object-type name="SYNONYM" enabled="true" />
<object-type name="SEQUENCE" enabled="true" />
<object-type name="PROCEDURE" enabled="true" />
<object-type name="FUNCTION" enabled="true" />
<object-type name="PACKAGE" enabled="true" />
<object-type name="TYPE" enabled="true" />
<object-type name="TYPE_ATTRIBUTE" enabled="true" />
<object-type name="ARGUMENT" enabled="true" />
<object-type name="JAVA_CLASS" enabled="true" />
<object-type name="JAVA_INNER_CLASS" enabled="true" />
<object-type name="JAVA_FIELD" enabled="true" />
<object-type name="JAVA_METHOD" enabled="true" />
<object-type name="DIMENSION" enabled="true" />
<object-type name="CLUSTER" enabled="true" />
<object-type name="DBLINK" enabled="true" />
<object-type name="CREDENTIAL" enabled="true" />
<object-type name="AI_PROFILE" enabled="true" />
</object-type-filter>
</filters>
<sorting>
<object-type name="COLUMN" sorting-type="NAME" />
<object-type name="FUNCTION" sorting-type="NAME" />
<object-type name="PROCEDURE" sorting-type="NAME" />
<object-type name="ARGUMENT" sorting-type="POSITION" />
<object-type name="TYPE ATTRIBUTE" sorting-type="POSITION" />
</sorting>
<default-editors>
<object-type name="VIEW" editor-type="SELECTION" />
<object-type name="PACKAGE" editor-type="SELECTION" />
<object-type name="TYPE" editor-type="SELECTION" />
</default-editors>
</browser-settings>
<navigation-settings>
<lookup-filters>
<lookup-objects>
<object-type name="SCHEMA" enabled="true" />
<object-type name="USER" enabled="false" />
<object-type name="ROLE" enabled="false" />
<object-type name="PRIVILEGE" enabled="false" />
<object-type name="CHARSET" enabled="false" />
<object-type name="TABLE" enabled="true" />
<object-type name="VIEW" enabled="true" />
<object-type name="MATERIALIZED VIEW" enabled="true" />
<object-type name="INDEX" enabled="true" />
<object-type name="CONSTRAINT" enabled="true" />
<object-type name="DATASET TRIGGER" enabled="true" />
<object-type name="DATABASE TRIGGER" enabled="true" />
<object-type name="SYNONYM" enabled="false" />
<object-type name="SEQUENCE" enabled="true" />
<object-type name="PROCEDURE" enabled="true" />
<object-type name="FUNCTION" enabled="true" />
<object-type name="PACKAGE" enabled="true" />
<object-type name="TYPE" enabled="true" />
<object-type name="JAVA CLASS" enabled="true" />
<object-type name="INNER CLASS" enabled="true" />
<object-type name="JAVA FIELD" enabled="true" />
<object-type name="JAVA METHOD" enabled="true" />
<object-type name="JAVA PARAMETER" enabled="true" />
<object-type name="DIMENSION" enabled="false" />
<object-type name="CLUSTER" enabled="false" />
<object-type name="DBLINK" enabled="true" />
<object-type name="CREDENTIAL" enabled="false" />
</lookup-objects>
<force-database-load value="false" />
<prompt-connection-selection value="true" />
<prompt-schema-selection value="true" />
</lookup-filters>
</navigation-settings>
<dataset-grid-settings>
<general>
<enable-zooming value="true" />
<enable-column-tooltip value="true" />
</general>
<sorting>
<nulls-first value="true" />
<max-sorting-columns value="4" />
</sorting>
<audit-columns>
<column-names value="" />
<visible value="true" />
<editable value="false" />
</audit-columns>
</dataset-grid-settings>
<dataset-editor-settings>
<text-editor-popup>
<active value="false" />
<active-if-empty value="false" />
<data-length-threshold value="100" />
<popup-delay value="1000" />
</text-editor-popup>
<values-actions-popup>
<show-popup-button value="true" />
<element-count-threshold value="1000" />
<data-length-threshold value="250" />
</values-actions-popup>
<general>
<fetch-block-size value="100" />
<fetch-timeout value="30" />
<trim-whitespaces value="true" />
<convert-empty-strings-to-null value="true" />
<select-content-on-cell-edit value="true" />
<large-value-preview-active value="true" />
</general>
<filters>
<prompt-filter-dialog value="true" />
<default-filter-type value="BASIC" />
</filters>
<qualified-text-editor text-length-threshold="300">
<content-types>
<content-type name="Text" enabled="true" />
<content-type name="Properties" enabled="true" />
<content-type name="XML" enabled="true" />
<content-type name="DTD" enabled="true" />
<content-type name="HTML" enabled="true" />
<content-type name="XHTML" enabled="true" />
<content-type name="Java" enabled="true" />
<content-type name="SQL" enabled="true" />
<content-type name="PL/SQL" enabled="true" />
<content-type name="JSON" enabled="true" />
<content-type name="JSON5" enabled="true" />
<content-type name="Groovy" enabled="true" />
<content-type name="AIDL" enabled="true" />
<content-type name="YAML" enabled="true" />
<content-type name="Manifest" enabled="true" />
</content-types>
</qualified-text-editor>
<record-navigation>
<navigation-target value="VIEWER" />
</record-navigation>
</dataset-editor-settings>
<code-editor-settings>
<general>
<show-object-navigation-gutter value="false" />
<show-spec-declaration-navigation-gutter value="true" />
<enable-spellchecking value="true" />
<enable-reference-spellchecking value="false" />
</general>
<confirmations>
<save-changes value="false" />
<revert-changes value="true" />
<exit-on-changes value="ASK" />
</confirmations>
</code-editor-settings>
<code-completion-settings>
<filters>
<basic-filter>
<filter-element type="RESERVED_WORD" id="keyword" selected="true" />
<filter-element type="RESERVED_WORD" id="function" selected="true" />
<filter-element type="RESERVED_WORD" id="parameter" selected="true" />
<filter-element type="RESERVED_WORD" id="datatype" selected="true" />
<filter-element type="RESERVED_WORD" id="exception" selected="true" />
<filter-element type="OBJECT" id="schema" selected="true" />
<filter-element type="OBJECT" id="role" selected="true" />
<filter-element type="OBJECT" id="user" selected="true" />
<filter-element type="OBJECT" id="privilege" selected="true" />
<user-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="false" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</user-schema>
<public-schema>
<filter-element type="OBJECT" id="table" selected="false" />
<filter-element type="OBJECT" id="view" selected="false" />
<filter-element type="OBJECT" id="materialized view" selected="false" />
<filter-element type="OBJECT" id="index" selected="false" />
<filter-element type="OBJECT" id="constraint" selected="false" />
<filter-element type="OBJECT" id="trigger" selected="false" />
<filter-element type="OBJECT" id="synonym" selected="false" />
<filter-element type="OBJECT" id="sequence" selected="false" />
<filter-element type="OBJECT" id="procedure" selected="false" />
<filter-element type="OBJECT" id="function" selected="false" />
<filter-element type="OBJECT" id="package" selected="false" />
<filter-element type="OBJECT" id="type" selected="false" />
<filter-element type="OBJECT" id="dimension" selected="false" />
<filter-element type="OBJECT" id="cluster" selected="false" />
<filter-element type="OBJECT" id="dblink" selected="false" />
</public-schema>
<any-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</any-schema>
</basic-filter>
<extended-filter>
<filter-element type="RESERVED_WORD" id="keyword" selected="true" />
<filter-element type="RESERVED_WORD" id="function" selected="true" />
<filter-element type="RESERVED_WORD" id="parameter" selected="true" />
<filter-element type="RESERVED_WORD" id="datatype" selected="true" />
<filter-element type="RESERVED_WORD" id="exception" selected="true" />
<filter-element type="OBJECT" id="schema" selected="true" />
<filter-element type="OBJECT" id="user" selected="true" />
<filter-element type="OBJECT" id="role" selected="true" />
<filter-element type="OBJECT" id="privilege" selected="true" />
<user-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</user-schema>
<public-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</public-schema>
<any-schema>
<filter-element type="OBJECT" id="table" selected="true" />
<filter-element type="OBJECT" id="view" selected="true" />
<filter-element type="OBJECT" id="materialized view" selected="true" />
<filter-element type="OBJECT" id="index" selected="true" />
<filter-element type="OBJECT" id="constraint" selected="true" />
<filter-element type="OBJECT" id="trigger" selected="true" />
<filter-element type="OBJECT" id="synonym" selected="true" />
<filter-element type="OBJECT" id="sequence" selected="true" />
<filter-element type="OBJECT" id="procedure" selected="true" />
<filter-element type="OBJECT" id="function" selected="true" />
<filter-element type="OBJECT" id="package" selected="true" />
<filter-element type="OBJECT" id="type" selected="true" />
<filter-element type="OBJECT" id="dimension" selected="true" />
<filter-element type="OBJECT" id="cluster" selected="true" />
<filter-element type="OBJECT" id="dblink" selected="true" />
</any-schema>
</extended-filter>
</filters>
<sorting enabled="true">
<sorting-element type="RESERVED_WORD" id="keyword" />
<sorting-element type="RESERVED_WORD" id="datatype" />
<sorting-element type="OBJECT" id="column" />
<sorting-element type="OBJECT" id="table" />
<sorting-element type="OBJECT" id="view" />
<sorting-element type="OBJECT" id="materialized view" />
<sorting-element type="OBJECT" id="index" />
<sorting-element type="OBJECT" id="constraint" />
<sorting-element type="OBJECT" id="trigger" />
<sorting-element type="OBJECT" id="synonym" />
<sorting-element type="OBJECT" id="sequence" />
<sorting-element type="OBJECT" id="procedure" />
<sorting-element type="OBJECT" id="function" />
<sorting-element type="OBJECT" id="package" />
<sorting-element type="OBJECT" id="type" />
<sorting-element type="OBJECT" id="dimension" />
<sorting-element type="OBJECT" id="cluster" />
<sorting-element type="OBJECT" id="dblink" />
<sorting-element type="OBJECT" id="schema" />
<sorting-element type="OBJECT" id="role" />
<sorting-element type="OBJECT" id="user" />
<sorting-element type="RESERVED_WORD" id="function" />
<sorting-element type="RESERVED_WORD" id="parameter" />
</sorting>
<format>
<enforce-code-style-case value="true" />
</format>
</code-completion-settings>
<execution-engine-settings>
<statement-execution>
<fetch-block-size value="100" />
<execution-timeout value="20" />
<debug-execution-timeout value="600" />
<focus-result value="false" />
<prompt-execution value="false" />
</statement-execution>
<script-execution>
<command-line-interfaces />
<execution-timeout value="300" />
</script-execution>
<method-execution>
<execution-timeout value="30" />
<debug-execution-timeout value="600" />
<parameter-history-size value="10" />
</method-execution>
</execution-engine-settings>
<operation-settings>
<transactions>
<uncommitted-changes>
<on-project-close value="ASK" />
<on-disconnect value="ASK" />
<on-autocommit-toggle value="ASK" />
</uncommitted-changes>
<multiple-uncommitted-changes>
<on-commit value="ASK" />
<on-rollback value="ASK" />
</multiple-uncommitted-changes>
</transactions>
<session-browser>
<disconnect-session value="ASK" />
<kill-session value="ASK" />
<reload-on-filter-change value="false" />
</session-browser>
<compiler>
<compile-type value="KEEP" />
<compile-dependencies value="ASK" />
<always-show-controls value="false" />
</compiler>
</operation-settings>
<ddl-file-settings>
<extensions>
<mapping file-type-id="VIEW" extensions="vw" />
<mapping file-type-id="TRIGGER" extensions="trg" />
<mapping file-type-id="PROCEDURE" extensions="prc" />
<mapping file-type-id="FUNCTION" extensions="fnc" />
<mapping file-type-id="PACKAGE" extensions="pkg" />
<mapping file-type-id="PACKAGE_SPEC" extensions="pks" />
<mapping file-type-id="PACKAGE_BODY" extensions="pkb" />
<mapping file-type-id="TYPE" extensions="tpe" />
<mapping file-type-id="TYPE_SPEC" extensions="tps" />
<mapping file-type-id="TYPE_BODY" extensions="tpb" />
<mapping file-type-id="JAVA_SOURCE" extensions="sql" />
</extensions>
<general>
<lookup-ddl-files value="true" />
<create-ddl-files value="false" />
<synchronize-ddl-files value="true" />
<use-qualified-names value="false" />
<make-scripts-rerunnable value="true" />
</general>
</ddl-file-settings>
<assistant-settings>
<credential-settings>
<credentials />
</credential-settings>
</assistant-settings>
<general-settings>
<regional-settings>
<date-format value="MEDIUM" />
<number-format value="UNGROUPED" />
<locale value="SYSTEM_DEFAULT" />
<use-custom-formats value="false" />
</regional-settings>
<environment>
<environment-types>
<environment-type id="development" name="Development" description="Development environment" color="-2430209/-12296320" readonly-code="false" readonly-data="false" />
<environment-type id="integration" name="Integration" description="Integration environment" color="-2621494/-12163514" readonly-code="true" readonly-data="false" />
<environment-type id="production" name="Production" description="Productive environment" color="-11574/-10271420" readonly-code="true" readonly-data="true" />
<environment-type id="other" name="Other" description="" color="-1576/-10724543" readonly-code="false" readonly-data="false" />
</environment-types>
<visibility-settings>
<connection-tabs value="true" />
<dialog-headers value="true" />
<object-editor-tabs value="true" />
<script-editor-tabs value="false" />
<execution-result-tabs value="true" />
</visibility-settings>
</environment>
</general-settings>
</component>
</project>

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

@ -0,0 +1,21 @@
<?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-10T05:41:17.715139600Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\Administrator\.android\avd\Pixel_9_Pro.avd" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState>
<SelectionState runConfigName="good_Wallpapers.app">
<option name="selectionMode" value="DROPDOWN" />
</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>

View File

@ -0,0 +1,8 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="AutoCloseableResource" enabled="true" level="WARNING" enabled_by_default="true">
<option name="METHOD_MATCHER_CONFIG" value="java.util.Formatter,format,java.io.Writer,append,com.google.common.base.Preconditions,checkNotNull,org.hibernate.Session,close,java.io.PrintWriter,printf,java.io.PrintStream,printf,android.content.res.AssetManager,open" />
</inspection_tool>
</profile>
</component>

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

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.0" />
</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>

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

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

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

BIN
app/DreamWallpaper.jks Normal file

Binary file not shown.

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

@ -0,0 +1,104 @@
import java.util.Date
import java.text.SimpleDateFormat
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("io.objectbox")
kotlin("kapt")
id("com.google.gms.google-services")
id("com.google.firebase.crashlytics")
}
val timestamp = SimpleDateFormat("MM_dd_HH_mm").format(Date())
android {
namespace = "com.wall.dream.wallpapers"
compileSdk = 36
defaultConfig {
//com.wall.dream.wallpapers
applicationId = "com.wall.dream.wallpapers"
minSdk = 24
targetSdk = 36
versionCode = 2
versionName = "1.1"
setProperty("archivesBaseName", "dream Wallpapers_V" + versionName + "(${versionCode})_$timestamp")
testInstrumentationRunner = "androidx.live.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
buildFeatures{
viewBinding = true
}
kotlinOptions {
jvmTarget = "1.8"
}
}
dependencies {
implementation("androidx.appcompat:appcompat:1.7.1")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.2.1")
testImplementation("junit:junit:4.13.2")
implementation ("com.github.bumptech.glide:glide:5.0.5")
implementation ("jp.wasabeef:glide-transformations:4.3.0") // Glide Transformations
implementation(files("libs/UpLoadLibrary_12_03_15_13-release.aar"))
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
implementation("com.google.android.gms:play-services-ads-identifier:18.0.1")
implementation("com.google.android.gms:play-services-location:21.0.1")
implementation("com.google.android.gms:play-services-appset:16.0.1")
// Import the Firebase BoM
implementation(platform("com.google.firebase:firebase-bom:34.6.0"))
implementation("com.google.firebase:firebase-crashlytics-ndk")
implementation("com.google.firebase:firebase-analytics")
// okhttp
implementation ("com.squareup.okhttp3:okhttp:5.3.1")
implementation("com.squareup.okhttp3:logging-interceptor:5.3.1")
// TradPlus
implementation("com.tradplusad:tradplus:15.1.10.1")
//noinspection GradleCompatible
implementation("androidx.legacy:legacy-support-v4:1.0.0")
implementation("androidx.appcompat:appcompat:1.3.0-alpha02")
// Ironsource
implementation("com.ironsource.sdk:mediationsdk:9.0.0")
implementation("com.tradplusad:tradplus-ironsource:10.15.1.10.1")
// Pangle
implementation("com.tradplusad:tradplus-pangle:19.15.1.10.1")
implementation("com.pangle.global:pag-sdk:7.7.0.2")
// UnityAds
implementation("com.tradplusad:tradplus-unity:5.15.1.10.1")
implementation("com.unity3d.ads:unity-ads:4.16.3")
//optional dependency for better targeting
implementation("androidx.browser:browser:1.8.0")
implementation("com.squareup.picasso:picasso:2.8")
implementation("androidx.viewpager:viewpager:1.0.0")
implementation("androidx.recyclerview:recyclerview:1.2.1")
// Mintegral
implementation("com.tradplusad:tradplus-mintegralx_overseas:18.15.1.10.1")
implementation("androidx.recyclerview:recyclerview:1.1.0")
implementation("com.mbridge.msdk.oversea:mbridge_android_sdk:16.10.11")
// Liftoff
implementation("com.tradplusad:tradplus-vunglex:7.15.1.10.1")
implementation("com.vungle:vungle-ads:7.6.0")
// Cross Promotion
implementation("com.tradplusad:tradplus-crosspromotion:27.15.1.10.1")
// TP Exchange
// 请注意保持与主包版本同步更新
implementation("com.google.code.gson:gson:2.8.6")
implementation("com.tradplusad:tp_exchange:40.15.1.10.1")
}

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

@ -0,0 +1,29 @@
{
"project_info": {
"project_number": "1051188491220",
"project_id": "dreamwallpapers-6d7cc",
"storage_bucket": "dreamwallpapers-6d7cc.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:1051188491220:android:acfda7c95543efc03bdc41",
"android_client_info": {
"package_name": "com.wall.dream.wallpapers"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyCRzyY9X1qlyS3Bc9TwPmfynG3BDWwtIdY"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}

Binary file not shown.

View File

@ -0,0 +1,116 @@
{
"_note1": "KEEP THIS FILE! Check it into a version control system (VCS) like git.",
"_note2": "ObjectBox manages crucial IDs for your object model. See docs for details.",
"_note3": "If you have VCS merge conflicts, you must resolve them according to ObjectBox docs.",
"entities": [
{
"id": "4:5374318059423987080",
"lastPropertyId": "13:1127054227079914732",
"name": "DataBase",
"properties": [
{
"id": "1:5907193265594068445",
"name": "id",
"type": 6,
"flags": 1
},
{
"id": "2:7643711915014989832",
"name": "categoryName",
"type": 9
},
{
"id": "3:5454072153734548882",
"name": "imId",
"type": 9
},
{
"id": "4:8866886314389627366",
"name": "description",
"type": 9
},
{
"id": "5:6647852625511577303",
"name": "fullUrl",
"type": 9
},
{
"id": "6:8481286751506557167",
"name": "previewUrl1080",
"type": 9
},
{
"id": "7:615207224772228883",
"name": "previewUrl400",
"type": 9
},
{
"id": "8:2114128640869665061",
"name": "previewUrl200",
"type": 9
},
{
"id": "9:4004858028833616093",
"name": "authorName",
"type": 9
},
{
"id": "10:1649948666606108567",
"name": "authorHeader",
"type": 9
},
{
"id": "11:4925649389754620618",
"name": "authorHtml",
"type": 9
},
{
"id": "12:6869613325061909824",
"name": "isLike",
"type": 1
},
{
"id": "13:1127054227079914732",
"name": "isDownload",
"type": 1
}
],
"relations": []
}
],
"lastEntityId": "4:5374318059423987080",
"lastIndexId": "0:0",
"lastRelationId": "0:0",
"lastSequenceId": "0:0",
"modelVersion": 5,
"modelVersionParserMinimum": 5,
"retiredEntityUids": [
8119453540460508569,
8776066878034520742,
817335537070466014
],
"retiredIndexUids": [],
"retiredPropertyUids": [
8848640050018073106,
4870222079156330783,
4966768060561274983,
8892036187720267027,
1670319685727744805,
3855211567189961055,
7567671966987007993,
2590164264280025677,
8912833100894718986,
7138929457594592554,
3957870060050722570,
2943285943884558608,
7262008615134929676,
7105947400861196483,
1954934496493857304,
8582031355111471002,
8410380097928190493,
3380197792593924336,
5750724995960958985
],
"retiredRelationUids": [],
"version": 1
}

View File

@ -0,0 +1,102 @@
{
"_note1": "KEEP THIS FILE! Check it into a version control system (VCS) like git.",
"_note2": "ObjectBox manages crucial IDs for your object model. See docs for details.",
"_note3": "If you have VCS merge conflicts, you must resolve them according to ObjectBox docs.",
"entities": [
{
"id": "3:817335537070466014",
"lastPropertyId": "15:5750724995960958985",
"name": "Data",
"properties": [
{
"id": "1:7567671966987007993",
"name": "id",
"type": 6,
"flags": 1
},
{
"id": "2:2590164264280025677",
"name": "description",
"type": 9
},
{
"id": "3:8912833100894718986",
"name": "fullUrl",
"type": 9
},
{
"id": "4:7138929457594592554",
"name": "previewUrl1080",
"type": 9
},
{
"id": "5:3957870060050722570",
"name": "previewUrl400",
"type": 9
},
{
"id": "6:2943285943884558608",
"name": "previewUrl200",
"type": 9
},
{
"id": "7:7262008615134929676",
"name": "authorName",
"type": 9
},
{
"id": "8:7105947400861196483",
"name": "authorHeader",
"type": 9
},
{
"id": "9:1954934496493857304",
"name": "authorHtml",
"type": 9
},
{
"id": "12:8582031355111471002",
"name": "imId",
"type": 9
},
{
"id": "13:8410380097928190493",
"name": "isLike",
"type": 1
},
{
"id": "14:3380197792593924336",
"name": "isDownload",
"type": 1
},
{
"id": "15:5750724995960958985",
"name": "categoryName",
"type": 9
}
],
"relations": []
}
],
"lastEntityId": "3:817335537070466014",
"lastIndexId": "0:0",
"lastRelationId": "0:0",
"lastSequenceId": "0:0",
"modelVersion": 5,
"modelVersionParserMinimum": 5,
"retiredEntityUids": [
8119453540460508569,
8776066878034520742
],
"retiredIndexUids": [],
"retiredPropertyUids": [
8848640050018073106,
4870222079156330783,
4966768060561274983,
8892036187720267027,
1670319685727744805,
3855211567189961055
],
"retiredRelationUids": [],
"version": 1
}

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

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

View File

@ -0,0 +1,26 @@
package com.free.life.wallpaper;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented live, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under live.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.hd.kwallpapers.wallpapers.live", appContext.getPackageName());
}
}

View File

@ -0,0 +1,52 @@
<?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.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.AD_ID" />
<application
android:name="com.wall.dream.wallpapers.DreamWallpaper"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/logo"
android:label="@string/app_name"
android:roundIcon="@mipmap/logo"
tools:replace="networkSecurityConfig"
android:networkSecurityConfig="@xml/net"
android:supportsRtl="true"
android:theme="@style/Theme.Wallpaper"
tools:targetApi="31">
<activity
android:name="com.wall.dream.wallpapers.acacctivity.SearchViewActivity"
android:exported="false" />
<activity
android:name="com.wall.dream.wallpapers.acacctivity.ListViewActivity"
android:exported="false" />
<activity
android:name="com.wall.dream.wallpapers.acacctivity.SplashActivity"
android:exported="true"
android:theme="@style/Theme.WelWallpaper">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.wall.dream.wallpapers.acacctivity.WallpaperViewActivity"
android:exported="false" />
<activity
android:name="com.wall.dream.wallpapers.acacctivity.MainViewActivity"
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

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.

View File

@ -0,0 +1,94 @@
package com.wall.dream.wallpapers;
import android.app.Application;
import android.content.Context;
import android.graphics.Typeface;
import android.util.Log;
import com.tradplus.ads.open.TradPlusSdk;
import com.up.uploadlibrary.UpLoadManager;
import com.wall.dream.wallpapers.data.DataBase;
import com.wall.dream.wallpapers.GJ.ComUtilsGJ;
import com.wall.dream.wallpapers.GJ.JsonDataBase;
import com.wall.dream.wallpapers.GJ.ObectBoxManagerGJ;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class DreamWallpaper extends Application {
public static Context mAppContext;
public static String TAG = "-------MyApp---------";
public static Typeface defaultFont;
private String animasName = "AnimalsGood.json";
private String exName = "ExperimentalGood.json";
private String filmName = "FilmGood.json";
private String natureName = "NatureGood.json";
private String pattName = "PatternsGood.json";
private String streetName = "StreetGood.json";
private String travelName = "TravelGood.json";
private String wallpaperName = "FeaturedGood.json";
private ExecutorService executor;
private static List<String> CategoryNames = new ArrayList<>();
private int i = 0;
@Override
public void onCreate() {
super.onCreate();
mAppContext = this;
defaultFont = Typeface.createFromAsset(getAssets(), "custfontGood.ttf");
ObectBoxManagerGJ.init(this);
executor = Executors.newFixedThreadPool(8);
String[] names = {wallpaperName, animasName, exName, filmName, natureName, pattName, streetName, travelName};
try {
for (String name : names) {
InputStream open = getAssets().open(name);
String covertStr = ComUtilsGJ.getCovertStr(open);
if (!covertStr.isEmpty()) {
String realName = name.substring(0, name.indexOf("."));
CategoryNames.add(realName);
executor.execute(new Runnable() {
@Override
public void run() {
i++;
Log.d(DreamWallpaper.TAG, "------------111");
List<DataBase> data = JsonDataBase.INSTANCE.getData(covertStr, realName);
Collections.shuffle(data);
for (DataBase data1:data){
ObectBoxManagerGJ.addData(data1);
}
// if (i == 8) {
// executor.shutdown();
// Log.d(MyWallpaper.TAG, "------------data complete");
// }
}
});
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
UpLoadManager.INSTANCE.init(this, "ocean", (s, s2) -> null);
TradPlusSdk.initSdk(this, "561313B7BB2FBAABFFA4E860CDA15B11");
}
public static List<String> getCategoryNames() {
return CategoryNames;
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,166 @@
package com.wall.dream.wallpapers.GJ;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import com.wall.dream.wallpapers.DreamWallpaper;
import com.wall.dream.wallpapers.data.DataBase;
import com.wall.dream.wallpapers.data.DataBase_;
import com.wall.dream.wallpapers.data.MyObjectBox;
import com.wall.dream.wallpapers.LianXi.OnUpdateDeLike;
import com.wall.dream.wallpapers.LianXi.OnLikeDeList;
import java.util.ArrayList;
import java.util.List;
import io.objectbox.Box;
import io.objectbox.BoxStore;
import io.objectbox.android.AndroidScheduler;
import io.objectbox.query.Query;
import io.objectbox.query.QueryBuilder;
import io.objectbox.reactive.DataObserver;
import io.objectbox.reactive.DataSubscription;
import io.objectbox.reactive.DataSubscriptionList;
public class ObectBoxManagerGJ {
private static BoxStore boxStore;
private static Box<DataBase> LikeBox;
private static List<OnUpdateDeLike> list = new ArrayList<>();
public static void init(Context context) {
boxStore = MyObjectBox.builder().androidContext(context).build();
}
public static Box<DataBase> getObjectBoxLike() {
if (LikeBox == null) {
LikeBox = boxStore.boxFor(DataBase.class);
}
return LikeBox;
}
public static void addData(DataBase data) {
Box<DataBase> objectBoxLike = getObjectBoxLike();
String imId = data.getImId();
DataBase first = objectBoxLike.query()
.equal(DataBase_.imId, imId, QueryBuilder.StringOrder.CASE_SENSITIVE)
.build()
.findFirst();
if (first == null) {
Log.d(DreamWallpaper.TAG, "-----------addData " + imId);
objectBoxLike.put(data);
}else {
Log.d(DreamWallpaper.TAG, "-----------忽略添加 ");
}
}
public static DataSubscription setLikeDataListener(OnLikeDeList listener) {
Query<DataBase> build = getObjectBoxLike().query()
.equal(DataBase_.isLike, true)
.build();
return build.subscribe(new DataSubscriptionList())
.on(AndroidScheduler.mainThread())
.observer(new DataObserver<List<DataBase>>() {
@Override
public void onData(@NonNull List<DataBase> data) {
Log.d(DreamWallpaper.TAG, "------data=" + data.size());
listener.onLikeList(data);
}
});
}
public static void updateLike(DataBase boxLike) {
Box<DataBase> objectBoxLike = getObjectBoxLike();
String imId = boxLike.getImId();
objectBoxLike.put(boxLike);
for (OnUpdateDeLike listener : list) {
listener.onAdd(boxLike);
}
}
public static void insertOrUpdateDownload(DataBase boxLike) {
Box<DataBase> objectBoxLike = getObjectBoxLike();
String imId = boxLike.getImId();
DataBase first = objectBoxLike.query()
.equal(DataBase_.imId, imId, QueryBuilder.StringOrder.CASE_SENSITIVE)
.build()
.findFirst();
if (first == null) {
Log.d(DreamWallpaper.TAG, "-----------添加11 Download=" + imId);
boxLike.setDownload(true);
objectBoxLike.put(boxLike);
} else {
first.setDownload(true);
objectBoxLike.put(first);
Log.d(DreamWallpaper.TAG, "-----------已经存在添加22 Download=" + imId);
}
}
public static List<DataBase> search(String name) {
Box<DataBase> objectBoxLike = getObjectBoxLike();
List<DataBase> data = objectBoxLike.query()
.contains(DataBase_.description, name, QueryBuilder.StringOrder.CASE_SENSITIVE)
.build()
.find();
return data;
}
public static List<DataBase> queryHome(String name) {
Box<DataBase> objectBoxLike = getObjectBoxLike();
List<DataBase> data = objectBoxLike.query()
.equal(DataBase_.categoryName, name, QueryBuilder.StringOrder.CASE_SENSITIVE)
.build()
.find(10, 1);
return data;
}
public static List<DataBase> queryCategoryAll(String name) {
Box<DataBase> objectBoxLike = getObjectBoxLike();
List<DataBase> data = objectBoxLike.query()
.equal(DataBase_.categoryName, name, QueryBuilder.StringOrder.CASE_SENSITIVE)
.build()
.find(0, 200);
return data;
}
public static boolean queryIsLike(String imId) {
Box<DataBase> objectBoxLike = getObjectBoxLike();
DataBase first = objectBoxLike.query()
.equal(DataBase_.imId, imId, QueryBuilder.StringOrder.CASE_SENSITIVE)
.build()
.findFirst();
if (first != null && first.isLike()) {
return true;
} else {
return false;
}
}
/**
* 获取所有壁纸数据
*/
public static List<DataBase> getAllWallpapers() {
Box<DataBase> objectBoxLike = getObjectBoxLike();
List<DataBase> data = objectBoxLike.query().build().find();
return data;
}
}

View File

@ -0,0 +1,129 @@
package com.wall.dream.wallpapers.ItemPag;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.wall.dream.wallpapers.databinding.PagCategoryCardBinding;
import com.wall.dream.wallpapers.GJ.ObectBoxManagerGJ;
import com.wall.dream.wallpapers.LianXi.OnItemXianClick;
import com.wall.dream.wallpapers.data.DataBase;
import java.util.ArrayList;
import java.util.List;
/**
* 宽卡片样式的分类适配器
*/
public class ItemCategoryPag extends RecyclerView.Adapter<ItemCategoryPag.CategoryCardHolder> {
private List<String> categoryList = new ArrayList<>();
private Context mContext;
private OnItemXianClick listener;
public void setData(List<String> data) {
this.categoryList = data;
notifyDataSetChanged();
}
public void setOnItemClickListener(OnItemXianClick onItemxianClick) {
this.listener = onItemxianClick;
}
@NonNull
@Override
public CategoryCardHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
mContext = parent.getContext();
PagCategoryCardBinding binding = PagCategoryCardBinding.inflate(
LayoutInflater.from(mContext), parent, false);
return new CategoryCardHolder(binding);
}
@Override
public void onBindViewHolder(@NonNull CategoryCardHolder holder, int position) {
String categoryName = categoryList.get(position);
// 设置分类名称隐藏后面的Good
String displayName = removeGoodSuffix(categoryName);
holder.binding.tvCategoryName.setText(displayName);
// 获取该分类的壁纸数量
List<DataBase> wallpapers = ObectBoxManagerGJ.queryHome(categoryName);
int count = wallpapers != null ? wallpapers.size() : 0;
// 根据分类名称设置不同的图标可以扩展更多图标
setCategoryIcon(holder, categoryName);
// 设置点击事件
holder.binding.categoryCard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
listener.onClickMore(categoryName);
}
}
});
// 添加点击动画效果
holder.binding.categoryCard.setOnTouchListener((v, event) -> {
switch (event.getAction()) {
case android.view.MotionEvent.ACTION_DOWN:
v.animate().scaleX(0.95f).scaleY(0.95f).setDuration(100).start();
break;
case android.view.MotionEvent.ACTION_UP:
case android.view.MotionEvent.ACTION_CANCEL:
v.animate().scaleX(1.0f).scaleY(1.0f).setDuration(100).start();
break;
}
return false;
});
}
/**
* 移除分类名称后面的"Good"后缀不区分大小写
*/
private String removeGoodSuffix(String categoryName) {
if (categoryName == null || categoryName.isEmpty()) {
return categoryName;
}
// 使用正则表达式不区分大小写地移除末尾的"Good"
return categoryName.replaceAll("(?i)good$", "");
}
/**
* 根据分类名称设置对应的图标
*/
private void setCategoryIcon(CategoryCardHolder holder, String categoryName) {
// 这里可以根据不同的分类设置不同的图标
// 目前使用默认的自然图标后续可以扩展
// 例如
// if (categoryName.toLowerCase().contains("nature")) {
// holder.binding.ivCategoryIcon.setImageResource(R.drawable.ic_category_nature);
// } else if (categoryName.toLowerCase().contains("city")) {
// holder.binding.ivCategoryIcon.setImageResource(R.drawable.ic_category_city);
// }
// 暂时使用默认图标
// holder.binding.ivCategoryIcon.setImageResource(R.drawable.ic_category_nature);
}
@Override
public int getItemCount() {
return categoryList.size();
}
static class CategoryCardHolder extends RecyclerView.ViewHolder {
private PagCategoryCardBinding binding;
public CategoryCardHolder(@NonNull PagCategoryCardBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
}
}

View File

@ -0,0 +1,157 @@
package com.wall.dream.wallpapers.ItemPag;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.DecodeFormat;
import com.bumptech.glide.load.MultiTransformation;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
import com.wall.dream.wallpapers.R;
import com.wall.dream.wallpapers.data.DataBase;
import com.wall.dream.wallpapers.LianXi.OnItemXianClick;
import com.wall.dream.wallpapers.GJ.ComUtilsGJ;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
public class ItemFeaturedPag extends RecyclerView.Adapter<ItemFeaturedPag.MyViewHolder> {
private List<DataBase> dataInfo = new ArrayList<>();
private OnItemXianClick onItemxianClick;
private WeakReference<Context> weakReference;
private int itemHeight;
public void setInfoWallpaperListener(OnItemXianClick onItemxianClick) {
this.onItemxianClick = onItemxianClick;
}
public ItemFeaturedPag(Context myCon, int itemHeight) {
weakReference = new WeakReference<>(myCon);
this.itemHeight = itemHeight;
}
public void setDataInfo(List<DataBase> dataInfo) {
this.dataInfo = dataInfo;
notifyDataSetChanged();
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
Context context = weakReference.get();
if (context != null) {
View itemView = LayoutInflater.from(context).inflate(R.layout.pag_featured, parent, false);
ImageView imageView = itemView.findViewById(R.id.wallpaper);
ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams();
layoutParams.height = itemHeight;
imageView.setLayoutParams(layoutParams);
return new MyViewHolder(itemView);
}
return null;
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
DataBase info = dataInfo.get(position);
ImageView imageView = holder.getImageView();
CardView cardView = holder.getCardView();
String previewUrl400 = info.getPreviewUrl400();
// 使用更大的圆角更现代的风格
MultiTransformation<Bitmap> multiTransformation = new MultiTransformation<>(
new CenterCrop(),
new RoundedCornersTransformation(ComUtilsGJ.dp2Px(20), 0) // 20dp圆角
);
RequestOptions options = new RequestOptions()
.format(DecodeFormat.PREFER_RGB_565);
Context context = weakReference.get();
if (context != null) {
Glide.with(context)
.asDrawable()
.skipMemoryCache(true)
.apply(options)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.load(previewUrl400)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<Drawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target<Drawable> target, @NonNull DataSource dataSource, boolean isFirstResource) {
return false;
}
})
.placeholder(R.mipmap.im_placeholder)
.transform(multiTransformation)
.into(imageView);
}
cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onItemxianClick != null) {
onItemxianClick.onItemClickAction(info);
}
}
});
}
@Override
public int getItemCount() {
return dataInfo.size();
}
@Override
public void onViewRecycled(@NonNull MyViewHolder holder) {
super.onViewRecycled(holder);
}
static class MyViewHolder extends RecyclerView.ViewHolder {
private ImageView imageView;
private CardView cardView;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.wallpaper);
cardView = itemView.findViewById(R.id.layout);
}
public ImageView getImageView() {
return imageView;
}
public CardView getCardView() {
return cardView;
}
}
}

View File

@ -0,0 +1,173 @@
package com.wall.dream.wallpapers.ItemPag;
import android.content.Context;
import android.graphics.Bitmap;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import androidx.annotation.NonNull;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.MultiTransformation;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.wall.dream.wallpapers.DreamWallpaper;
import com.wall.dream.wallpapers.R;
import com.wall.dream.wallpapers.GJ.ObectBoxManagerGJ;
import com.wall.dream.wallpapers.data.DataBase;
import com.wall.dream.wallpapers.LianXi.OnItemXianClick;
import com.wall.dream.wallpapers.GJ.ComUtilsGJ;
import java.util.ArrayList;
import java.util.List;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
public class ItemLikePag extends RecyclerView.Adapter<ItemLikePag.LikeVh> {
private List<DataBase> dataInfo = new ArrayList<>();
private Context myContext;
private OnItemXianClick onItemxianClick;
private int itemHeight;
public void setInfoWallpaperListener(OnItemXianClick onItemxianClick) {
this.onItemxianClick = onItemxianClick;
}
public ItemLikePag(Context myCon) {
myContext = myCon;
this.itemHeight = 0; // 默认使用布局中的高度
}
public ItemLikePag(Context myCon, int itemHeight) {
myContext = myCon;
this.itemHeight = itemHeight;
}
public void setDataInfo(List<DataBase> dataInfo) {
this.dataInfo = dataInfo;
notifyDataSetChanged();
}
@NonNull
@Override
public LikeVh onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(myContext).inflate(R.layout.pag_like, parent, false);
// 如果指定了高度则动态设置
if (itemHeight > 0) {
CardView cardView = itemView.findViewById(R.id.like_card);
if (cardView != null) {
ViewGroup.LayoutParams params = cardView.getLayoutParams();
params.height = itemHeight;
cardView.setLayoutParams(params);
}
}
return new LikeVh(itemView);
}
@Override
public void onBindViewHolder(@NonNull LikeVh holder, int position) {
DataBase info = dataInfo.get(position);
ImageView imageView = holder.getImageView();
View favoriteContainer = holder.getFavoriteContainer();
ImageView favoriteIcon = holder.getFavoriteIcon();
String previewUrl400 = info.getPreviewUrl400();
String imId = info.getImId();
View spaceView = holder.getSpaceView();
if (position == dataInfo.size() - 1) {
spaceView.setVisibility(View.VISIBLE);
} else {
spaceView.setVisibility(View.GONE);
}
MultiTransformation<Bitmap> multiTransformation = new MultiTransformation<>(
new CenterCrop(),
new RoundedCornersTransformation(ComUtilsGJ.dp2Px(12), 0) // 圆角效果
);
Glide.with(myContext)
.load(previewUrl400)
.placeholder(R.mipmap.im_placeholder)
.transform(multiTransformation)
.into(imageView);
// 设置心形图标为选中状态
if (favoriteIcon != null) {
favoriteIcon.setSelected(true);
}
// 设置收藏按钮点击事件
if (favoriteContainer != null) {
favoriteContainer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (favoriteIcon != null) {
favoriteIcon.setSelected(false);
}
info.setLike(false);
ObectBoxManagerGJ.updateLike(info);
int adapterPosition = holder.getAdapterPosition();
notifyItemRemoved(adapterPosition);
Log.d(DreamWallpaper.TAG, "----------notifyItemRemoved-adapterPosition=" + adapterPosition);
}
});
}
holder.getLayout().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onItemxianClick != null) {
onItemxianClick.onItemClickAction(info);
}
}
});
}
@Override
public int getItemCount() {
return dataInfo.size();
}
public class LikeVh extends RecyclerView.ViewHolder {
private ImageView imageView;
private RelativeLayout layout;
private View favoriteContainer;
private ImageView favoriteIcon;
private View spaceView;
public LikeVh(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.wallpaper);
layout = itemView.findViewById(R.id.layout);
favoriteContainer = itemView.findViewById(R.id.image_favorite);
favoriteIcon = itemView.findViewById(R.id.favorite_icon);
spaceView = itemView.findViewById(R.id.space_view);
}
public View getSpaceView() {
return spaceView;
}
public View getFavoriteContainer() {
return favoriteContainer;
}
public ImageView getFavoriteIcon() {
return favoriteIcon;
}
public RelativeLayout getLayout() {
return layout;
}
public ImageView getImageView() {
return imageView;
}
}
}

View File

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

View File

@ -0,0 +1,123 @@
package com.wall.dream.wallpapers.ItemPag;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.MultiTransformation;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.wall.dream.wallpapers.DreamWallpaper;
import com.wall.dream.wallpapers.R;
import com.wall.dream.wallpapers.databinding.PagMainBinding;
import com.wall.dream.wallpapers.GJ.ComUtilsGJ;
import com.wall.dream.wallpapers.GJ.ObectBoxManagerGJ;
import com.wall.dream.wallpapers.LianXi.OnItemXianClick;
import com.wall.dream.wallpapers.data.DataBase;
import java.util.ArrayList;
import java.util.List;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
public class ItemMainPag extends RecyclerView.Adapter<ItemMainPag.HomeParentHolder> {
private List<String> data = new ArrayList<>();
private Context mContext;
private OnItemXianClick listener;
private MultiTransformation<Bitmap> multiTransformation = new MultiTransformation<>(
new CenterCrop(),
new RoundedCornersTransformation(ComUtilsGJ.dp2Px(12), 0) // 圆角效果
);
public void setData(List<String> data) {
this.data = data;
notifyDataSetChanged();
}
public void setInfoWallpaperListener(OnItemXianClick onItemxianClick) {
this.listener = onItemxianClick;
}
@NonNull
@Override
public HomeParentHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
mContext = parent.getContext();
PagMainBinding inflate = PagMainBinding.inflate(LayoutInflater.from(mContext), parent, false);
return new HomeParentHolder(inflate);
}
@Override
public void onBindViewHolder(@NonNull HomeParentHolder holder, int position) {
String name = data.get(position);
List<DataBase> data1 = ObectBoxManagerGJ.queryHome(name);
String previewUrl400 = data1.get(0).getPreviewUrl1080();
holder.itemBing.tvClassName.setText(name);
if(position == data.size()-1){
holder.itemBing.spaceView.setVisibility(View.VISIBLE);
}else {
holder.itemBing.spaceView.setVisibility(View.GONE);
}
Glide.with(mContext)
.asDrawable()
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.load(previewUrl400)
// .centerCrop()
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<Drawable> target, boolean isFirstResource) {
Log.d(DreamWallpaper.TAG, "------------e="+e.getMessage()+"---previewUrl400="+previewUrl400);
return false;
}
@Override
public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target<Drawable> target, @NonNull DataSource dataSource, boolean isFirstResource) {
return false;
}
})
.placeholder(R.mipmap.im_placeholder)
// .transform(multiTransformation)
.into(holder.itemBing.preview);
// initChild(holder,data1);
holder.itemBing.preview.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.onClickMore(name);
}
});
}
@Override
public int getItemCount() {
return data.size();
}
static class HomeParentHolder extends RecyclerView.ViewHolder {
private PagMainBinding itemBing;
public HomeParentHolder(@NonNull PagMainBinding itemView) {
super(itemView.getRoot());
itemBing = itemView;
}
}
}

View File

@ -0,0 +1,10 @@
package com.wall.dream.wallpapers.LianXi;
import com.wall.dream.wallpapers.data.DataBase;
public interface OnItemXianClick {
void onItemClickAction(DataBase info);
default void onClickMore(String name){}
}

View File

@ -0,0 +1,9 @@
package com.wall.dream.wallpapers.LianXi;
import com.wall.dream.wallpapers.data.DataBase;
import java.util.List;
public interface OnLikeDeList {
void onLikeList(List<DataBase> dataList);
}

View File

@ -0,0 +1,6 @@
package com.wall.dream.wallpapers.LianXi;
public interface OnSelectDeType {
void onSelectType(int type);
}

View File

@ -0,0 +1,8 @@
package com.wall.dream.wallpapers.LianXi;
import com.wall.dream.wallpapers.data.DataBase;
public interface OnUpdateDeLike {
void onAdd(DataBase data);
void onRemove(DataBase data);
}

View File

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

View File

@ -0,0 +1,132 @@
package com.wall.dream.wallpapers.View;
import android.app.Dialog;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.DialogFragment;
import com.wall.dream.wallpapers.R;
public class RateUsDialog extends DialogFragment {
private View rootView;
private ImageView[] stars;
private int selectedRating = 0;
private Drawable starFilled;
private Drawable starOutline;
private Handler mainHandler;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置对话框样式减少创建开销
setStyle(DialogFragment.STYLE_NO_TITLE, android.R.style.Theme_DeviceDefault_Dialog);
mainHandler = new Handler(Looper.getMainLooper());
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.dialog_rate_us_001, container, false);
return rootView;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// 立即初始化但使用轻量方式
if (getContext() != null) {
// 预加载drawable资源
starFilled = ContextCompat.getDrawable(requireContext(), R.drawable.star_filled_gag);
starOutline = ContextCompat.getDrawable(requireContext(), R.drawable.star_outline_gas);
initViews();
}
}
@Override
public void onStart() {
super.onStart();
Dialog dialog = getDialog();
if (dialog != null) {
dialog.setCanceledOnTouchOutside(true);
Window window = dialog.getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
}
}
private void initViews() {
stars = new ImageView[5];
stars[0] = rootView.findViewById(R.id.star1);
stars[1] = rootView.findViewById(R.id.star2);
stars[2] = rootView.findViewById(R.id.star3);
stars[3] = rootView.findViewById(R.id.star4);
stars[4] = rootView.findViewById(R.id.star5);
// 设置星星点击事件
for (int i = 0; i < stars.length; i++) {
final int rating = i + 1;
stars[i].setOnClickListener(v -> {
if (selectedRating != rating) {
selectedRating = rating;
updateStars();
}
});
}
// 取消按钮
TextView btnCancel = rootView.findViewById(R.id.btn_cancel);
btnCancel.setOnClickListener(v -> dismiss());
// 评分按钮
TextView btnRate = rootView.findViewById(R.id.btn_rate);
btnRate.setOnClickListener(v -> {
if (selectedRating > 0) {
// 可以在这里添加打开Google Play的逻辑
}
dismiss();
});
}
private void updateStars() {
if (starFilled == null || starOutline == null) {
return;
}
// 使用预加载的drawable避免每次调用setImageResource
for (int i = 0; i < stars.length; i++) {
if (i < selectedRating) {
stars[i].setImageDrawable(starFilled);
} else {
stars[i].setImageDrawable(starOutline);
}
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
// 清理资源
if (mainHandler != null) {
mainHandler.removeCallbacksAndMessages(null);
}
starFilled = null;
starOutline = null;
rootView = null;
}
}

View File

@ -0,0 +1,135 @@
package com.wall.dream.wallpapers.View;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import com.wall.dream.wallpapers.R;
public class RateUsDialogHelper {
private Dialog dialog;
private ImageView[] stars;
private int selectedRating = 0;
private Drawable starFilled;
private Drawable starOutline;
public void show(Context context) {
if (dialog != null && dialog.isShowing()) {
return;
}
// 预加载资源提前加载避免在show时加载
if (starFilled == null) {
starFilled = ContextCompat.getDrawable(context, R.drawable.star_filled_gag);
}
if (starOutline == null) {
starOutline = ContextCompat.getDrawable(context, R.drawable.star_outline_gas);
}
// 创建对话框
dialog = new Dialog(context);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
// 加载布局
dialog.setContentView(R.layout.dialog_rate_us_001);
// 设置窗口属性
Window window = dialog.getWindow();
if (window != null) {
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
WindowManager.LayoutParams params = window.getAttributes();
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
window.setAttributes(params);
}
dialog.setCanceledOnTouchOutside(true);
// 初始化视图
initViews();
// 直接显示对话框
dialog.show();
}
private void initViews() {
if (dialog == null) return;
// dialog.setContentView后可以直接使用dialog.findViewById查找视图
stars = new ImageView[5];
stars[0] = dialog.findViewById(R.id.star1);
stars[1] = dialog.findViewById(R.id.star2);
stars[2] = dialog.findViewById(R.id.star3);
stars[3] = dialog.findViewById(R.id.star4);
stars[4] = dialog.findViewById(R.id.star5);
// 设置星星点击事件
for (int i = 0; i < stars.length; i++) {
final int rating = i + 1;
if (stars[i] != null) {
// 确保星星可点击
stars[i].setClickable(true);
stars[i].setFocusable(true);
stars[i].setOnClickListener(v -> {
selectedRating = rating;
updateStars();
});
}
}
// 取消按钮
TextView btnCancel = dialog.findViewById(R.id.btn_cancel);
if (btnCancel != null) {
btnCancel.setOnClickListener(v -> dismiss());
}
// 评分按钮
TextView btnRate = dialog.findViewById(R.id.btn_rate);
if (btnRate != null) {
btnRate.setOnClickListener(v -> {
if (selectedRating > 0) {
// 可以在这里添加打开Google Play的逻辑
}
dismiss();
});
}
}
private void updateStars() {
if (starFilled == null || starOutline == null) {
return;
}
for (int i = 0; i < stars.length; i++) {
if (stars[i] != null) {
if (i < selectedRating) {
stars[i].setImageDrawable(starFilled);
} else {
stars[i].setImageDrawable(starOutline);
}
}
}
}
public void dismiss() {
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
}
public void cleanup() {
dismiss();
starFilled = null;
starOutline = null;
stars = null;
dialog = null;
}
}

View File

@ -0,0 +1,181 @@
package com.wall.dream.wallpapers.View;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import com.wall.dream.wallpapers.LianXi.OnItemXianClick;
import com.wall.dream.wallpapers.R;
import com.wall.dream.wallpapers.acacctivity.WallpaperViewActivity;
import com.wall.dream.wallpapers.databinding.View1MainBinding;
import com.wall.dream.wallpapers.GJ.ComUtilsGJ;
import com.wall.dream.wallpapers.GJ.ItemHelperGJ;
import com.wall.dream.wallpapers.GJ.ObectBoxManagerGJ;
import com.wall.dream.wallpapers.data.DataBase;
import com.wall.dream.wallpapers.ItemPag.ItemFeaturedPag;
import java.util.Collections;
import java.util.List;
public class ViewFeatured extends Fragment implements OnItemXianClick {
private View1MainBinding vb;
public ViewFeatured() {
}
public static ViewFeatured newInstance() {
return new ViewFeatured();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
vb = View1MainBinding.inflate(getLayoutInflater());
// 隐藏分类标题栏精选界面不需要标题
View categoryTitleBar = vb.getRoot().findViewById(R.id.category_title_bar);
if (categoryTitleBar != null) {
categoryTitleBar.setVisibility(View.GONE);
}
// 调整RecyclerView的布局参数使其从顶部开始不依赖标题栏
android.widget.RelativeLayout.LayoutParams params =
(android.widget.RelativeLayout.LayoutParams) vb.classRecycler.getLayoutParams();
params.addRule(android.widget.RelativeLayout.ALIGN_PARENT_TOP);
params.removeRule(android.widget.RelativeLayout.BELOW);
// 确保RecyclerView有正确的padding
vb.classRecycler.setPadding(
vb.classRecycler.getPaddingLeft(),
(int) (8 * getResources().getDisplayMetrics().density), // 顶部padding
vb.classRecycler.getPaddingRight(),
vb.classRecycler.getPaddingBottom()
);
vb.classRecycler.setLayoutParams(params);
initFeaturedWallpapers();
return vb.getRoot();
}
private void initFeaturedWallpapers() {
// 显示加载指示器
View loadingLayout = vb.getRoot().findViewById(R.id.loading_layout);
View emptyLayout = vb.getRoot().findViewById(R.id.empty_layout);
if (loadingLayout != null) {
loadingLayout.setVisibility(View.VISIBLE);
}
if (emptyLayout != null) {
emptyLayout.setVisibility(View.GONE);
}
// 初始状态隐藏RecyclerView等待数据加载
vb.classRecycler.setVisibility(View.GONE);
// 在后台线程获取所有壁纸数据
new Thread(() -> {
// 从数据库获取所有壁纸
List<DataBase> data = ObectBoxManagerGJ.getAllWallpapers();
// 随机打乱顺序
if (data != null && !data.isEmpty()) {
Collections.shuffle(data);
}
// 切换到主线程更新UI
if (getActivity() != null && isAdded()) {
final List<DataBase> finalData = data;
getActivity().runOnUiThread(() -> {
if (!isAdded() || getActivity() == null || vb == null) {
return;
}
// 隐藏加载指示器
if (loadingLayout != null) {
loadingLayout.setVisibility(View.GONE);
}
if (finalData == null || finalData.isEmpty()) {
// 显示空状态
if (emptyLayout != null) {
emptyLayout.setVisibility(View.VISIBLE);
}
vb.classRecycler.setVisibility(View.GONE);
} else {
// 显示数据
if (emptyLayout != null) {
emptyLayout.setVisibility(View.GONE);
}
// 确保RecyclerView可见
vb.classRecycler.setVisibility(View.VISIBLE);
initGridList(finalData);
}
});
}
}).start();
}
private void initGridList(List<DataBase> data) {
// 确保RecyclerView可见
if (vb.classRecycler.getVisibility() != View.VISIBLE) {
vb.classRecycler.setVisibility(View.VISIBLE);
}
// 优化item高度根据屏幕宽度动态计算两列布局
int screenWidth = getResources().getDisplayMetrics().widthPixels;
int padding = (int) (12 * getResources().getDisplayMetrics().density); // 左右padding
int spacing = (int) (12 * getResources().getDisplayMetrics().density); // item间距
int columnCount = 2; // 两列布局
int itemWidth = (screenWidth - padding * 2 - spacing * (columnCount - 1)) / columnCount;
int itemHeight = (int) (itemWidth * 1.15); // 使用1.15:1的宽高比平衡高度和宽度
ItemFeaturedPag itemList = new ItemFeaturedPag(requireContext(), itemHeight);
itemList.setDataInfo(data);
itemList.setInfoWallpaperListener(this);
// 使用2列网格布局优化性能
GridLayoutManager gridLayoutManager = new GridLayoutManager(requireContext(), columnCount);
gridLayoutManager.setItemPrefetchEnabled(true);
gridLayoutManager.setInitialPrefetchItemCount(4); // 两列时减少预取数量
// 优化间距装饰两列时增大间距
int itemSpacing = (int) (12 * getResources().getDisplayMetrics().density);
ItemHelperGJ itemHelperGJ = new ItemHelperGJ(itemSpacing, itemSpacing, 0);
// 清除旧的装饰器如果有
int decorationCount = vb.classRecycler.getItemDecorationCount();
for (int i = decorationCount - 1; i >= 0; i--) {
vb.classRecycler.removeItemDecorationAt(i);
}
vb.classRecycler.addItemDecoration(itemHelperGJ);
// 优化RecyclerView性能
vb.classRecycler.setLayoutManager(gridLayoutManager);
vb.classRecycler.setAdapter(itemList);
vb.classRecycler.setHasFixedSize(true);
vb.classRecycler.setItemViewCacheSize(20);
vb.classRecycler.setDrawingCacheEnabled(true);
vb.classRecycler.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
// 强制刷新
if (itemList.getItemCount() > 0) {
itemList.notifyDataSetChanged();
}
}
@Override
public void onItemClickAction(DataBase info) {
Intent intent = new Intent(requireContext(), WallpaperViewActivity.class);
intent.putExtra(ComUtilsGJ.key_info, info);
startActivity(intent);
}
@Override
public void onClickMore(String name) {
// 精选模式下不需要此功能
}
}

View File

@ -0,0 +1,88 @@
package com.wall.dream.wallpapers.View;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.tabs.TabLayout;
import com.wall.dream.wallpapers.databinding.View1HomeContainerBinding;
import java.util.ArrayList;
import java.util.List;
public class ViewHomeContainer extends Fragment {
private View1HomeContainerBinding vb;
private List<Fragment> topFragments = new ArrayList<>();
public ViewHomeContainer() {
}
public static ViewHomeContainer newInstance() {
return new ViewHomeContainer();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
vb = View1HomeContainerBinding.inflate(inflater, container, false);
initTopTabs();
return vb.getRoot();
}
private void initTopTabs() {
// 顶部Fragment列表
topFragments.add(ViewFeatured.newInstance()); // 精选
topFragments.add(ViewMain.newInstance(0)); // 分类
// 设置顶部ViewPager
vb.topViewpager.setAdapter(new FragmentStateAdapter(this) {
@NonNull
@Override
public Fragment createFragment(int position) {
return topFragments.get(position);
}
@Override
public int getItemCount() {
return topFragments.size();
}
});
vb.topViewpager.setUserInputEnabled(true);
// 设置顶部TabLayout
vb.topTab.addTab(vb.topTab.newTab().setText("精选"));
vb.topTab.addTab(vb.topTab.newTab().setText("分类"));
// 顶部Tab切换监听
vb.topTab.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
vb.topViewpager.setCurrentItem(tab.getPosition(), true);
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
// ViewPager切换时同步Tab
vb.topViewpager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
vb.topTab.selectTab(vb.topTab.getTabAt(position));
}
});
}
}

View File

@ -0,0 +1,109 @@
package com.wall.dream.wallpapers.View;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import com.wall.dream.wallpapers.DreamWallpaper;
import com.wall.dream.wallpapers.LianXi.OnItemXianClick;
import com.wall.dream.wallpapers.R;
import com.wall.dream.wallpapers.acacctivity.WallpaperViewActivity;
import com.wall.dream.wallpapers.databinding.View1LikeBinding;
import com.wall.dream.wallpapers.GJ.ComUtilsGJ;
import com.wall.dream.wallpapers.GJ.ObectBoxManagerGJ;
import com.wall.dream.wallpapers.GJ.ItemHelperGJ;
import com.wall.dream.wallpapers.LianXi.OnLikeDeList;
import com.wall.dream.wallpapers.data.DataBase;
import com.wall.dream.wallpapers.ItemPag.ItemLikePag;
import java.util.List;
import io.objectbox.reactive.DataSubscription;
public class ViewLike extends Fragment implements OnItemXianClick {
private View1LikeBinding vb;
private DataSubscription dataSubscription;
public ViewLike() {
}
public static ViewLike newInstance() {
ViewLike fragment = new ViewLike();
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
vb = View1LikeBinding.inflate(getLayoutInflater());
vb.tvTitle.setText(getString(R.string.no_like_data));
initList();
return vb.getRoot();
}
private void initList() {
// 动态计算item高度与精选页面保持一致
int screenWidth = getResources().getDisplayMetrics().widthPixels;
int padding = (int) (12 * getResources().getDisplayMetrics().density);
int spacing = (int) (12 * getResources().getDisplayMetrics().density);
int columnCount = 2;
int itemWidth = (screenWidth - padding * 2 - spacing * (columnCount - 1)) / columnCount;
int itemHeight = (int) (itemWidth * 1.15); // 使用1.15:1的宽高比平衡高度和宽度
ItemLikePag itemLikePag = new ItemLikePag(requireContext(), itemHeight);
dataSubscription = ObectBoxManagerGJ.setLikeDataListener(new OnLikeDeList() {
@Override
public void onLikeList(List<DataBase> dataList) {
Log.d(DreamWallpaper.TAG, "------size = " + dataList.size());
if(dataList.size()==0){
vb.layoutNoData.setVisibility(View.VISIBLE);
vb.listRecycler.setVisibility(View.GONE);
}else {
vb.layoutNoData.setVisibility(View.GONE);
vb.listRecycler.setVisibility(View.VISIBLE);
itemLikePag.setDataInfo(dataList);
}
}
});
ItemHelperGJ itemHelperGJ = new ItemHelperGJ(12, 12, 12);
GridLayoutManager gridLayoutManager = new GridLayoutManager(requireContext(), columnCount);
vb.listRecycler.setLayoutManager(gridLayoutManager);
vb.listRecycler.addItemDecoration(itemHelperGJ);
itemLikePag.setInfoWallpaperListener(this);
vb.listRecycler.setAdapter(itemLikePag);
}
@Override
public void onItemClickAction(DataBase info) {
Intent intent = new Intent(requireContext(), WallpaperViewActivity.class);
intent.putExtra(ComUtilsGJ.key_info, info);
startActivity(intent);
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (dataSubscription != null) {
dataSubscription.cancel();
}
Log.d(DreamWallpaper.TAG,"------favoriteFragment-onDestroyView");
}
}

View File

@ -0,0 +1,88 @@
package com.wall.dream.wallpapers.View;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.wall.dream.wallpapers.DreamWallpaper;
import com.wall.dream.wallpapers.acacctivity.ListViewActivity;
import com.wall.dream.wallpapers.acacctivity.WallpaperViewActivity;
import com.wall.dream.wallpapers.databinding.View1MainBinding;
import com.wall.dream.wallpapers.GJ.ComUtilsGJ;
import com.wall.dream.wallpapers.GJ.ItemHelperGJ;
import com.wall.dream.wallpapers.LianXi.OnItemXianClick;
import com.wall.dream.wallpapers.data.DataBase;
import com.wall.dream.wallpapers.ItemPag.ItemCategoryPag;
import java.util.ArrayList;
import java.util.List;
public class ViewMain extends Fragment implements OnItemXianClick {
private View1MainBinding vb;
public ViewMain() {
}
public static ViewMain newInstance(int type) {
Bundle bundle = new Bundle();
bundle.putInt(ComUtilsGJ.key_index, type);
ViewMain fragment = new ViewMain();
fragment.setArguments(bundle);
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
vb = View1MainBinding.inflate(getLayoutInflater());
initTabVp();
return vb.getRoot();
}
private void initTabVp() {
List<String> data = new ArrayList<>();
while (data.size() < 8) {
data = DreamWallpaper.getCategoryNames();
}
vb.loadingPb.setVisibility(View.GONE);
initList(data);
}
private void initList(List<String> data) {
// 使用新的宽卡片样式适配器
ItemCategoryPag categoryAdapter = new ItemCategoryPag();
categoryAdapter.setData(data);
categoryAdapter.setOnItemClickListener(this);
// 设置间距装饰器 - 适合宽卡片布局
ItemHelperGJ itemHelperGJ = new ItemHelperGJ(0, 0, 8);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(requireContext());
vb.classRecycler.setLayoutManager(linearLayoutManager);
vb.classRecycler.addItemDecoration(itemHelperGJ);
vb.classRecycler.setAdapter(categoryAdapter);
}
@Override
public void onItemClickAction(DataBase info) {
Intent intent = new Intent(requireContext(), WallpaperViewActivity.class);
intent.putExtra(ComUtilsGJ.key_info, info);
startActivity(intent);
}
@Override
public void onClickMore(String name) {
Intent intent = new Intent(requireContext(), ListViewActivity.class);
intent.putExtra(ListViewActivity.key_index, name);
startActivity(intent);
}
}

View File

@ -0,0 +1,102 @@
package com.wall.dream.wallpapers.View;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import com.wall.dream.wallpapers.databinding.View1SettingsBinding;
public class ViewSettings extends Fragment {
private View1SettingsBinding vb;
private RateUsDialogHelper rateUsDialogHelper;
private boolean isDialogShowing = false;
public ViewSettings() {
}
public static ViewSettings newInstance() {
return new ViewSettings();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
vb = View1SettingsBinding.inflate(inflater, container, false);
initViews();
return vb.getRoot();
}
private void initViews() {
// 设置版本号 - 使用后台线程避免阻塞UI
new Thread(() -> {
try {
String versionName = requireContext().getPackageManager()
.getPackageInfo(requireContext().getPackageName(), 0).versionName;
new Handler(Looper.getMainLooper()).post(() -> {
if (vb != null && vb.tvVersion != null) {
vb.tvVersion.setText(versionName);
}
});
} catch (PackageManager.NameNotFoundException e) {
new Handler(Looper.getMainLooper()).post(() -> {
if (vb != null && vb.tvVersion != null) {
vb.tvVersion.setText("1.1");
}
});
}
}).start();
// Rate Us 点击事件 - 使用轻量Dialog添加防抖处理
vb.layoutRate.setOnClickListener(v -> {
if (isDialogShowing || getContext() == null) {
return;
}
isDialogShowing = true;
try {
if (rateUsDialogHelper == null) {
rateUsDialogHelper = new RateUsDialogHelper();
}
rateUsDialogHelper.show(requireContext());
} catch (Exception e) {
// 忽略异常避免崩溃
e.printStackTrace();
} finally {
// 重置标志允许再次点击
new Handler(Looper.getMainLooper()).postDelayed(() -> {
isDialogShowing = false;
}, 300);
}
});
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (rateUsDialogHelper != null) {
rateUsDialogHelper.cleanup();
rateUsDialogHelper = null;
}
vb = null;
}
}

View File

@ -0,0 +1,79 @@
package com.wall.dream.wallpapers.View;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import com.wall.dream.wallpapers.acacctivity.WallpaperViewActivity;
import com.wall.dream.wallpapers.databinding.View1MainBinding;
import com.wall.dream.wallpapers.GJ.ComUtilsGJ;
import com.wall.dream.wallpapers.GJ.ItemHelperGJ;
import com.wall.dream.wallpapers.LianXi.OnItemXianClick;
import com.wall.dream.wallpapers.data.DataBase;
import com.wall.dream.wallpapers.ItemPag.ItemListPag;
import java.util.ArrayList;
import java.util.List;
public class ViewWallpaperGrid extends Fragment implements OnItemXianClick {
private View1MainBinding vb;
public ViewWallpaperGrid() {
}
public static ViewWallpaperGrid newInstance() {
return new ViewWallpaperGrid();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
vb = View1MainBinding.inflate(getLayoutInflater());
initWallpaperGrid();
return vb.getRoot();
}
private void initWallpaperGrid() {
// 获取壁纸数据
List<DataBase> data = new ArrayList<>();
// 这里应该从数据源获取壁纸列表
// data = MyApp.getWallpapers();
vb.loadingPb.setVisibility(View.GONE);
initGridList(data);
}
private void initGridList(List<DataBase> data) {
// ItemList需要Context, itemHeight, showSpace三个参数
// 180dp高度适合网格布局
int itemHeight = (int) (180 * getResources().getDisplayMetrics().density);
ItemListPag itemListPag = new ItemListPag(requireContext(), itemHeight, false);
itemListPag.setDataInfo(data);
itemListPag.setInfoWallpaperListener(this);
// 使用3列网格布局
GridLayoutManager gridLayoutManager = new GridLayoutManager(requireContext(), 3);
ItemHelperGJ itemHelperGJ = new ItemHelperGJ(6, 6, 0);
vb.classRecycler.addItemDecoration(itemHelperGJ);
vb.classRecycler.setLayoutManager(gridLayoutManager);
vb.classRecycler.setAdapter(itemListPag);
}
@Override
public void onItemClickAction(DataBase info) {
Intent intent = new Intent(requireContext(), WallpaperViewActivity.class);
intent.putExtra(ComUtilsGJ.key_info, info);
startActivity(intent);
}
@Override
public void onClickMore(String name) {
// 网格模式下不需要此功能
}
}

View File

@ -0,0 +1,36 @@
package com.wall.dream.wallpapers.acacctivity
import android.os.Bundle
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AppCompatActivity
open class BaseActivity: AppCompatActivity() {
protected var backPressedCallback: OnBackPressedCallback? = null
/** 子类是否需要拦截返回 */
protected open fun shouldInterceptBackPress(): Boolean = false
/** 子类定义拦截后的操作(例如弹窗) */
protected open fun onInterceptBackPressed() {}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setupBackPressedCallback()//初始化back事件
}
private fun setupBackPressedCallback() {
backPressedCallback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (shouldInterceptBackPress()) {
// 由子类处理拦截动作
onInterceptBackPressed()
} else {
// 不拦截:关闭自己
isEnabled = false
onBackPressedDispatcher.onBackPressed()
}
}
}
onBackPressedDispatcher.addCallback(this, backPressedCallback!!)
}
}

View File

@ -0,0 +1,121 @@
package com.wall.dream.wallpapers.acacctivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import com.tradplus.ads.base.bean.TPAdInfo;
import com.wall.dream.wallpapers.ad.AdsInsUtil;
import com.wall.dream.wallpapers.ad.LoadListener;
import com.wall.dream.wallpapers.ad.ShowListener;
import com.wall.dream.wallpapers.databinding.ViewListBinding;
import com.wall.dream.wallpapers.GJ.ComUtilsGJ;
import com.wall.dream.wallpapers.GJ.ObectBoxManagerGJ;
import com.wall.dream.wallpapers.GJ.ItemHelperGJ;
import com.wall.dream.wallpapers.LianXi.OnItemXianClick;
import com.wall.dream.wallpapers.data.DataBase;
import com.wall.dream.wallpapers.ItemPag.ItemListPag;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class ListViewActivity extends BaseActivity implements OnItemXianClick {
private ViewListBinding vb;
private String categoryName;
public static final String key_index = "index";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
vb = ViewListBinding.inflate(getLayoutInflater());
setContentView(vb.getRoot());
ComUtilsGJ.initFull(this, false);
categoryName = getIntent().getStringExtra(key_index);
// 显示时隐藏后面的Good
String displayName = removeGoodSuffix(categoryName);
vb.name.setText(displayName);
initList();
vb.imageviewBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onInterceptBackPressed();
}
});
}
private void initList() {
List<DataBase> data = ObectBoxManagerGJ.queryCategoryAll(categoryName);
// 减少间距让图片挨在一起
ItemHelperGJ itemHelperGJ = new ItemHelperGJ(4, 4, 0);
// StaggeredGridLayoutManager gridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);
vb.list.addItemDecoration(itemHelperGJ);
vb.list.setLayoutManager(gridLayoutManager);
// 增加图片高度让图片更大
int height = ComUtilsGJ.dp2Px(240);
ItemListPag itemListPag = new ItemListPag(this, height,false);
itemListPag.setDataInfo(data);
itemListPag.setInfoWallpaperListener(this);
vb.list.setAdapter(itemListPag);
}
/**
* 移除分类名称后面的"Good"后缀不区分大小写
*/
private String removeGoodSuffix(String categoryName) {
if (categoryName == null || categoryName.isEmpty()) {
return categoryName;
}
// 使用正则表达式不区分大小写地移除末尾的"Good"
return categoryName.replaceAll("(?i)good$", "");
}
@Override
public void onItemClickAction(DataBase info) {
Intent intent = new Intent(this, WallpaperViewActivity.class);
intent.putExtra(ComUtilsGJ.key_info, info);
startActivity(intent);
}
@Override
protected boolean shouldInterceptBackPress() {
return true;
}
@Override
protected void onInterceptBackPressed() {
AdsInsUtil.INSTANCE.showAd(this, AdsInsUtil.Placement.TOP_ON_AD_TOW, new ShowListener() {
@Override
public void onAdShown(@Nullable TPAdInfo ad) {
loadAd();
}
@Override
public void onAdClosed() {
loadAd();
}
});
if (getBackPressedCallback() != null) {
getBackPressedCallback().setEnabled(false);
}
getOnBackPressedDispatcher().onBackPressed();
}
private void loadAd(){
AdsInsUtil.INSTANCE.loadAd(this, AdsInsUtil.Placement.TOP_ON_AD_TOW, new LoadListener() {
@Override
public void loadFailed(@NotNull String error) {
}
});
}
}

View File

@ -0,0 +1,409 @@
package com.wall.dream.wallpapers.acacctivity;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.google.android.material.tabs.TabLayout;
import com.tradplus.ads.base.bean.TPAdInfo;
import com.wall.dream.wallpapers.R;
import com.wall.dream.wallpapers.ad.AdsInsUtil;
import com.wall.dream.wallpapers.ad.LoadListener;
import com.wall.dream.wallpapers.databinding.ViewMainBinding;
import com.wall.dream.wallpapers.databinding.PagTabBinding;
import com.wall.dream.wallpapers.View.ViewFeatured;
import com.wall.dream.wallpapers.View.ViewLike;
import com.wall.dream.wallpapers.View.ViewMain;
import com.wall.dream.wallpapers.View.ViewSettings;
import com.wall.dream.wallpapers.GJ.ComUtilsGJ;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public class MainViewActivity extends AppCompatActivity {
private ViewMainBinding vb;
private List<Fragment> topFragments = new ArrayList<>();
private Fragment currentTopFragment;
private List<Fragment> bottomFragments = new ArrayList<>();
private Fragment currentBottomFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
vb = ViewMainBinding.inflate(getLayoutInflater());
ComUtilsGJ.initFull(this, false);
setContentView(vb.getRoot());
// 初始化顶部Tab精选/收藏
initTopTabs();
// 初始化底部导航首页/分类/设置
initBottomTabs();
// 确保初始状态显示顶部导航栏和搜索按钮默认显示首页
vb.topBar.setVisibility(View.VISIBLE);
vb.imSearch.setVisibility(View.VISIBLE);
}
@SuppressLint("SetTextI18n")
private void initTopTabs() {
// 顶部Fragment列表
Fragment featuredFragment = ViewFeatured.newInstance(); // 精选
Fragment likeFragment = ViewLike.newInstance(); // 收藏
topFragments.add(featuredFragment);
topFragments.add(likeFragment);
// 使用FragmentManager添加Fragment不使用ViewPager2
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
// 添加所有Fragment默认显示第一个
for (int i = 0; i < topFragments.size(); i++) {
Fragment fragment = topFragments.get(i);
String tag = "top_fragment_" + i;
transaction.add(R.id.top_content_container, fragment, tag);
if (i != 0) {
transaction.hide(fragment);
} else {
currentTopFragment = fragment;
}
}
transaction.commit();
// 设置顶部TabLayout - 参考图片4D LIVE 4K风格英文
// 创建自定义Tab视图
for (int i = 0; i < 2; i++) {
TabLayout.Tab tab = vb.topTab.newTab();
View customView = getLayoutInflater().inflate(R.layout.pag_top_tab, null);
android.widget.TextView mainText = customView.findViewById(R.id.tab_main_text);
android.widget.TextView subText = customView.findViewById(R.id.tab_sub_text);
View indicator = customView.findViewById(R.id.tab_indicator);
if (i == 0) {
// 第一个TabFEATURED类似4D风格- 白色加粗突出显示 + 显示指示器
mainText.setText(R.string.featured);
mainText.setTextSize(26);
mainText.setTextColor(ContextCompat.getColor(this, R.color.white));
mainText.setTypeface(null, android.graphics.Typeface.BOLD);
mainText.setAlpha(1.0f);
// 显示选中指示器
if (indicator != null) {
indicator.setVisibility(View.VISIBLE);
}
} else {
// 第二个TabFAVORITE类似LIVE/4K风格- 白色降低透明度 + 隐藏指示器
mainText.setText("LIKE");
mainText.setTextSize(20);
mainText.setTextColor(ContextCompat.getColor(this, R.color.white));
mainText.setTypeface(null, android.graphics.Typeface.NORMAL);
mainText.setAlpha(0.5f);
// 隐藏选中指示器
if (indicator != null) {
indicator.setVisibility(View.GONE);
}
}
tab.setCustomView(customView);
vb.topTab.addTab(tab);
}
// 顶部Tab切换监听 - 使用Fragment show/hide不使用ViewPager2
vb.topTab.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
int position = tab.getPosition();
switchTopFragment(position);
// 更新选中Tab样式大字体粗体白色突出显示 + 显示指示器
View customView = tab.getCustomView();
if (customView != null) {
android.widget.TextView mainText = customView.findViewById(R.id.tab_main_text);
View indicator = customView.findViewById(R.id.tab_indicator);
if (mainText != null) {
mainText.setTextSize(26);
mainText.setTextColor(ContextCompat.getColor(MainViewActivity.this, R.color.white));
mainText.setTypeface(null, android.graphics.Typeface.BOLD);
mainText.setAlpha(1.0f);
}
// 显示选中指示器
if (indicator != null) {
indicator.setVisibility(View.VISIBLE);
}
}
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
// 更新未选中Tab样式小字体白色50%透明度 + 隐藏指示器
View customView = tab.getCustomView();
if (customView != null) {
android.widget.TextView mainText = customView.findViewById(R.id.tab_main_text);
View indicator = customView.findViewById(R.id.tab_indicator);
if (mainText != null) {
mainText.setTextSize(20);
mainText.setTextColor(ContextCompat.getColor(MainViewActivity.this, R.color.white));
mainText.setTypeface(null, android.graphics.Typeface.NORMAL);
mainText.setAlpha(0.5f);
}
// 隐藏选中指示器
if (indicator != null) {
indicator.setVisibility(View.GONE);
}
}
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
/**
* 切换顶部Fragment使用show/hide不使用ViewPager2
*/
private void switchTopFragment(int position) {
if (position < 0 || position >= topFragments.size()) {
return;
}
Fragment targetFragment = topFragments.get(position);
if (targetFragment == currentTopFragment) {
return;
}
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
// 隐藏当前Fragment
if (currentTopFragment != null) {
transaction.hide(currentTopFragment);
}
// 显示目标Fragment
transaction.show(targetFragment);
transaction.commit();
currentTopFragment = targetFragment;
}
/**
* 切换底部Fragment使用show/hide不使用ViewPager2
*/
private void switchBottomFragment(int position) {
if (position < 0 || position >= bottomFragments.size()) {
return;
}
Fragment targetFragment = bottomFragments.get(position);
if (targetFragment == currentBottomFragment) {
return;
}
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
// 隐藏当前Fragment
if (currentBottomFragment != null) {
transaction.hide(currentBottomFragment);
}
// 显示目标Fragment
transaction.show(targetFragment);
transaction.commit();
currentBottomFragment = targetFragment;
}
private void initBottomTabs() {
// 底部Fragment列表 - 分类和设置
Fragment categoryFragment = ViewMain.newInstance(0); // 分类
Fragment settingsFragment = ViewSettings.newInstance(); // 设置
bottomFragments.add(categoryFragment);
bottomFragments.add(settingsFragment);
int[] ints = {R.drawable.selector_home, R.drawable.selector_tab_category, R.drawable.selector_settings};
// 使用FragmentManager添加Fragment不使用ViewPager2
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
// 添加所有Fragment默认隐藏因为默认显示首页
for (int i = 0; i < bottomFragments.size(); i++) {
Fragment fragment = bottomFragments.get(i);
String tag = "bottom_fragment_" + i;
transaction.add(R.id.bottom_content_container, fragment, tag);
transaction.hide(fragment);
}
transaction.commit();
// 创建3个底部Tab首页分类设置
for (int i = 0; i < 3; i++) {
TabLayout.Tab tab = vb.tab.newTab();
PagTabBinding tabVb = PagTabBinding.inflate(getLayoutInflater());
tabVb.imageIcon.setImageDrawable(ContextCompat.getDrawable(this, ints[i]));
tab.setCustomView(tabVb.getRoot());
if (i == 0) {
// 首页初始选中状态
applySelectedEffect(tabVb);
} else {
// 未选中状态
applyUnselectedEffect(tabVb);
}
vb.tab.addTab(tab);
}
vb.tab.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
int position = tab.getPosition();
View customView = tab.getCustomView();
if (customView == null) return;
PagTabBinding tabVb = PagTabBinding.bind(customView);
// 应用统一的选中效果
applySelectedEffect(tabVb);
// 显示/隐藏顶部Tab和内容容器
if (position == 0) {
// 首页显示顶部Tab和内容容器显示搜索按钮
vb.topTab.setVisibility(View.VISIBLE);
vb.topContentContainer.setVisibility(View.VISIBLE);
vb.bottomContentContainer.setVisibility(View.GONE);
vb.topBar.setVisibility(View.VISIBLE);
vb.imSearch.setVisibility(View.VISIBLE);
// 隐藏所有底部Fragment
if (currentBottomFragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.hide(currentBottomFragment);
transaction.commit();
currentBottomFragment = null;
}
} else {
// 分类或设置显示底部容器隐藏搜索按钮
vb.topTab.setVisibility(View.GONE);
vb.topContentContainer.setVisibility(View.GONE);
vb.bottomContentContainer.setVisibility(View.VISIBLE);
vb.topBar.setVisibility(View.GONE);
// 切换到对应的Fragmentposition-1因为底部只有2个Fragment
switchBottomFragment(position - 1);
}
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
View customView = tab.getCustomView();
if (customView == null) return;
PagTabBinding tabVb = PagTabBinding.bind(customView);
// 应用未选中效果
applyUnselectedEffect(tabVb);
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
vb.imSearch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainViewActivity.this, SearchViewActivity.class);
startActivity(intent);
}
});
}
/**
* 应用统一的选中效果显示背景框 + 图标放大
*/
private void applySelectedEffect(com.wall.dream.wallpapers.databinding.PagTabBinding tabVb) {
if (tabVb == null) return;
// 显示统一的背景框
if (tabVb.bgFrame != null) {
tabVb.bgFrame.setVisibility(View.VISIBLE);
}
// 图标效果放大一点完全不透明
if (tabVb.imageIcon != null) {
tabVb.imageIcon.setColorFilter(ContextCompat.getColor(this, R.color.white));
tabVb.imageIcon.setAlpha(1.0f);
tabVb.imageIcon.setScaleX(1.1f);
tabVb.imageIcon.setScaleY(1.1f);
}
}
/**
* 应用未选中效果隐藏背景框 + 图标恢复原始大小
*/
private void applyUnselectedEffect(com.wall.dream.wallpapers.databinding.PagTabBinding tabVb) {
if (tabVb == null) return;
// 隐藏背景框
if (tabVb.bgFrame != null) {
tabVb.bgFrame.setVisibility(View.GONE);
}
// 图标效果恢复原始大小降低透明度
if (tabVb.imageIcon != null) {
tabVb.imageIcon.setColorFilter(ContextCompat.getColor(this, R.color.white));
tabVb.imageIcon.setAlpha(0.85f);
tabVb.imageIcon.setScaleX(1.0f);
tabVb.imageIcon.setScaleY(1.0f);
}
}
@Override
protected void onResume() {
super.onResume();
loadAd();
}
private void loadAd() {
AdsInsUtil.INSTANCE.loadAd(this, AdsInsUtil.Placement.TOP_ON_AD_THREE, new LoadListener() {
@Override
public void loaded(@NotNull TPAdInfo ad) {
}
@Override
public void loadFailed(@NotNull String error) {
}
});
AdsInsUtil.INSTANCE.loadAd(this, AdsInsUtil.Placement.TOP_ON_AD_TOW, new LoadListener() {
@Override
public void loaded(@NotNull TPAdInfo ad) {
}
@Override
public void loadFailed(@NotNull String error) {
}
});
}
}

View File

@ -0,0 +1,105 @@
package com.wall.dream.wallpapers.acacctivity
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.TextView.OnEditorActionListener
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.GridLayoutManager
import com.wall.dream.wallpapers.R
import com.wall.dream.wallpapers.databinding.ViewSearchBinding
import com.wall.dream.wallpapers.GJ.ComUtilsGJ
import com.wall.dream.wallpapers.GJ.ObectBoxManagerGJ
import com.wall.dream.wallpapers.GJ.ItemHelperGJ
import com.wall.dream.wallpapers.LianXi.OnItemXianClick
import com.wall.dream.wallpapers.data.DataBase
import com.wall.dream.wallpapers.ItemPag.ItemListPag
class SearchViewActivity : AppCompatActivity() ,
OnItemXianClick {
private lateinit var adapterWallapper: ItemListPag
private lateinit var binding: ViewSearchBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ViewSearchBinding.inflate(layoutInflater)
setContentView(binding.root)
ComUtilsGJ.initFull(this, false)
initList()
binding.imageviewBack.setOnClickListener {
finish()
}
}
private fun initList() {
val height = ComUtilsGJ.dp2Px(180)
adapterWallapper =
ItemListPag(this, height, true)
adapterWallapper.setInfoWallpaperListener(this)
val recyclerItemHelperGJ = ItemHelperGJ(10, 10, 15)
val gridLayoutManager = GridLayoutManager(this, 2)
binding.resultRecycler.run {
layoutManager = gridLayoutManager
addItemDecoration(recyclerItemHelperGJ)
adapter = adapterWallapper
}
binding.et.setOnEditorActionListener(OnEditorActionListener { v, actionId, event ->
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
startSearch()
return@OnEditorActionListener true
}
false
})
binding.btnSearch.setOnClickListener { startSearch() }
}
private fun closeKeyboard() {
val imm = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(binding.et.windowToken, 0)
}
private fun startSearch() {
closeKeyboard()
binding.searchPb.visibility = View.VISIBLE
val string: String = binding.et.text.toString()
if (string.isNotEmpty()) {
val search = ObectBoxManagerGJ.search(string)
if (search.size > 0) {
showEmpty(false)
adapterWallapper.setDataInfo(search)
binding.searchPb.visibility = View.GONE
} else {
binding.searchPb.visibility = View.GONE
showEmpty(true)
}
} else {
binding.searchPb.visibility = View.GONE
Toast.makeText(
this,
getString(R.string.please_input_keyword),
Toast.LENGTH_SHORT
).show()
}
}
private fun showEmpty(showEmpty: Boolean) {
if (showEmpty) {
binding.emptyLayout.visibility = View.VISIBLE
binding.resultRecycler.visibility = View.GONE
} else {
binding.emptyLayout.visibility = View.GONE
binding.resultRecycler.visibility = View.VISIBLE
}
}
override fun onItemClickAction(info: DataBase?) {
val intent = Intent(this, WallpaperViewActivity::class.java)
intent.putExtra(ComUtilsGJ.key_info, info)
startActivity(intent)
}
}

View File

@ -0,0 +1,173 @@
package com.wall.dream.wallpapers.acacctivity
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.os.CountDownTimer
import android.widget.Toast
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import com.tradplus.ads.base.bean.TPAdInfo
import com.wall.dream.wallpapers.R
import com.wall.dream.wallpapers.ad.AdShowFailed
import com.wall.dream.wallpapers.ad.AdsInsUtil
import com.wall.dream.wallpapers.ad.LoadListener
import com.wall.dream.wallpapers.ad.ShowListener
import com.wall.dream.wallpapers.databinding.ViewSplashBinding
import kotlin.jvm.java
class SplashActivity : BaseActivity() {
private var countDownTimer: CountDownTimer? = null
private lateinit var vb: ViewSplashBinding
private val tickInterval = 100L
private val totalTime = 15_000L
/**
* tick 次数 15
*/
private val totalTicks = totalTime / tickInterval
/**
* tick 增加的进度 0.6666~
*/
private val normalStep = 100f / totalTicks
private val fastStep = normalStep * 4 // 加速倍率
private var currentStep = normalStep
// 进度控制
private var progress = 0f
// 广告状态
private var adAvailable = false
private var hasNavigated = false
@SuppressLint("MissingInflatedId")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
vb = ViewSplashBinding.inflate(layoutInflater)
setContentView(vb.root)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView)
windowInsetsController.isAppearanceLightStatusBars = true//状态栏文字颜色
// 1. 进来就 load 广告
loadSplashAd()
// 2. 启动进度条(只启动一次)
startProgressTimer()
}
private fun startProgressTimer() {
countDownTimer?.cancel()
countDownTimer = object : CountDownTimer(totalTime, tickInterval) {
override fun onTick(millisUntilFinished: Long) {
progress += currentStep
if (progress >= 100f) {
progress = 100f
vb.progressbar.progress = 100
cancel()
onProgressFinished()
} else {
vb.progressbar.progress = progress.toInt()
}
}
override fun onFinish() {
// 不使用
}
}.start()
}
// 进度走完后的统一出口
private fun onProgressFinished() {
if (hasNavigated) return
if (adAvailable) {
showSplashAd()
} else {
navigateToNext()
}
}
private fun loadSplashAd() {
AdsInsUtil.loadAd(
act = this,
adID = AdsInsUtil.Placement.TOP_ON_AD_ONE,
loadListener = object : LoadListener {
override fun loaded(ad: TPAdInfo) {
adAvailable = true
accelerateProgress()
}
override fun loadFailed(error: String) {
adAvailable = false
accelerateProgress()
}
}
)
}
// 广告 load 完 → 加速
private fun accelerateProgress() {
currentStep = fastStep
}
private fun showSplashAd() {
AdsInsUtil.showAd(
act = this,
adID = AdsInsUtil.Placement.TOP_ON_AD_ONE,
listener = object : ShowListener {
override fun onAdShown(ad: TPAdInfo?) {}
override fun onAdShowFailed(error: AdShowFailed?) {
navigateToNext()
}
override fun onAdClosed() {
navigateToNext()
}
}
)
}
private fun navigateToNext() {
if (hasNavigated) return
hasNavigated = true
navigateToMainActivity()
}
override fun shouldInterceptBackPress(): Boolean = true
override fun onInterceptBackPressed() {}
@SuppressLint("QueryPermissionsNeeded")
private fun navigateToMainActivity() {
try {
startActivity(Intent(this, MainViewActivity::class.java))
finish()
} catch (e: Exception) {
Toast.makeText(this, "跳转失败", Toast.LENGTH_SHORT).show()
e.printStackTrace()
finish()
}
}
override fun onDestroy() {
super.onDestroy()
countDownTimer?.cancel()
countDownTimer = null
}
}

View File

@ -0,0 +1,445 @@
package com.wall.dream.wallpapers.acacctivity;
import android.app.WallpaperManager;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.DecodeFormat;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
import com.tradplus.ads.base.bean.TPAdInfo;
import com.wall.dream.wallpapers.DreamWallpaper;
import com.wall.dream.wallpapers.LianXi.OnSelectDeType;
import com.wall.dream.wallpapers.R;
import com.wall.dream.wallpapers.ad.AdsInsUtil;
import com.wall.dream.wallpapers.ad.LoadListener;
import com.wall.dream.wallpapers.ad.ShowListener;
import com.wall.dream.wallpapers.databinding.ViewWallapperBinding;
import com.wall.dream.wallpapers.View.MyDialogView;
import com.wall.dream.wallpapers.GJ.ComUtilsGJ;
import com.wall.dream.wallpapers.GJ.ObectBoxManagerGJ;
import com.wall.dream.wallpapers.GJ.JsonDataBase;
import com.wall.dream.wallpapers.data.DataBase;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import kotlin.Unit;
import kotlin.jvm.functions.Function2;
import okhttp3.Call;
public class WallpaperViewActivity extends AppCompatActivity implements OnSelectDeType {
private WeakReference<WallpaperViewActivity> weakReference;
private DataBase data;
private WallpaperManager wallpaperManager;
private int permissionCode = 1;
private String mSavePath;
private String imId;
private String fullUrl;
private MyDialogView dialogType;
private File downloadFile;
private Call call;
private ViewWallapperBinding vb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
vb = ViewWallapperBinding.inflate(getLayoutInflater());
ComUtilsGJ.initFull(this, true);
setContentView(vb.getRoot());
AdsInsUtil.INSTANCE.showAd(this, AdsInsUtil.Placement.TOP_ON_AD_THREE, new ShowListener() {
@Override
public void onAdShown(@org.jetbrains.annotations.Nullable TPAdInfo ad) {
loadAd();
}
@Override
public void onAdClosed() {
loadAd();
}
});
weakReference = new WeakReference<>(this);
data = (DataBase) getIntent().getSerializableExtra(ComUtilsGJ.key_info);
if (data == null) {
return;
}
imId = data.getImId();
mSavePath = JsonDataBase.INSTANCE.getSaveFilePath(this, imId);
wallpaperManager = WallpaperManager.getInstance(this);
initClick();
loadDetail();
vb.tvContent.setText(data.getDescription());
}
private void loadDetail() {
String previewUrl400 = data.getPreviewUrl400();
String previewUrl1080 = data.getPreviewUrl1080();
// String previewUrl200 = data.getPreviewUrl200();
// String authorHeader = data.getAuthorHeader();
// String authorName = data.getAuthorName();
// String authorHtml = data.getAuthorHtml();
fullUrl = data.getFullUrl();
File file = new File(mSavePath);
RequestOptions options = new RequestOptions()
.format(DecodeFormat.PREFER_RGB_565);
int[] screenWidthHeight = ComUtilsGJ.getScreenWidthHeight(this);
Log.d(DreamWallpaper.TAG, "--------width=" + screenWidthHeight[0] + "----height=" + screenWidthHeight[1]);
if (file.exists()) {
Glide.with(this)
.load(file)
.apply(options)
.placeholder(R.mipmap.im_placeholder)
// .override(screenWidthHeight[0], screenWidthHeight[1])
.transition(DrawableTransitionOptions.withCrossFade(500))
.into(vb.imageviewPreview);
} else {
Glide.with(this)
.asDrawable()
.load(previewUrl1080)
.apply(options)
.skipMemoryCache(true)
.placeholder(R.mipmap.im_placeholder)
.thumbnail(
Glide.with(WallpaperViewActivity.this)
.asDrawable()
.load(previewUrl400)
.apply(options)
.placeholder(R.mipmap.im_placeholder)
.centerCrop()
)
.transition(DrawableTransitionOptions.withCrossFade(500)) // 500ms 淡入效果
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<Drawable> target, boolean isFirstResource) {
Log.d(DreamWallpaper.TAG, "-----------onLoadFailed e" + e.getMessage());
return false;
}
@Override
public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target<Drawable> target, @NonNull DataSource dataSource, boolean isFirstResource) {
// fullDrawable = resource;
return false;
}
})
.centerCrop()
.into(vb.imageviewPreview);
}
boolean b = ObectBoxManagerGJ.queryIsLike(imId);
vb.imageFavorite.setSelected(b);
}
private void initClick() {
vb.imageviewBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
vb.buttonSet.setOnClickListener(v -> {
if (dialogType == null) {
dialogType = new MyDialogView();
dialogType.setListener(WallpaperViewActivity.this);
}
if (!dialogType.isAdded()) {
dialogType.show(getSupportFragmentManager(), "");
}
});
vb.imageFavorite.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean selected = vb.imageFavorite.isSelected();
vb.imageFavorite.setSelected(!selected);
boolean selectedNew = vb.imageFavorite.isSelected();
data.setLike(selectedNew);
ObectBoxManagerGJ.updateLike(data);
}
});
vb.layoutDownload.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean permission = JsonDataBase.INSTANCE.requestPermission(WallpaperViewActivity.this, permissionCode);
if (!permission) {
return;
}
startSaveToAlbum();
}
});
}
private void startSaveToAlbum() {
showDownloadLoading(true);
// File file = new File(mSavePath);
// if (file.exists()) {
// Log.d(MyWallpaper.TAG, "-----------Download 1");
// startSave(file);
// return;
// }
if (downloadFile != null && downloadFile.exists()) {
Log.d(DreamWallpaper.TAG, "-----------Download 2");
startSave(downloadFile);
return;
}
Log.d(DreamWallpaper.TAG, "-----------Download 3");
doDownload(true, true);
}
private void doDownload(boolean showMsg, boolean save) {
call = JsonDataBase.INSTANCE.downloadFile(fullUrl, mSavePath, new Function2<Boolean, InputStream, Unit>() {
@Override
public Unit invoke(Boolean aBoolean, InputStream inputStream) {
File file = new File(mSavePath);
if (aBoolean && file.exists()) {
downloadFile = file;
if (save) {
startSave(downloadFile);
}
runOnUiThread(new Runnable() {
@Override
public void run() {
WallpaperViewActivity activity = weakReference.get();
if (activity != null && !activity.isDestroyed()) {
Log.d(DreamWallpaper.TAG, "-------weakReference !=null");
// Glide.with(activity)
// .asDrawable()
// .load(downloadFile)
// .into(vb.imageviewPreview);
} else {
Log.d(DreamWallpaper.TAG, "-------weakReference null");
}
}
});
} else {
runOnUiThread(new Runnable() {
@Override
public void run() {
showDownloadLoading(false);
if (showMsg) {
Toast.makeText(WallpaperViewActivity.this, getString(R.string.download_fail), Toast.LENGTH_SHORT).show();
}
}
});
}
return null;
}
});
}
private void showDownloadLoading(boolean show) {
if (show) {
vb.pbDownload.setVisibility(View.VISIBLE);
vb.imageDownload.setVisibility(View.GONE);
} else {
vb.pbDownload.setVisibility(View.GONE);
vb.imageDownload.setVisibility(View.VISIBLE);
}
}
private void showSetWallpaperLoading(boolean show) {
Log.d(DreamWallpaper.TAG, "-----------showSetWallpaperLoading" + show);
if (show) {
vb.pbSet.setVisibility(View.VISIBLE);
vb.buttonSet.setVisibility(View.GONE);
} else {
vb.pbSet.setVisibility(View.GONE);
vb.buttonSet.setVisibility(View.VISIBLE);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == permissionCode && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startSaveToAlbum();
}
}
private void startSave(File file) {
ObectBoxManagerGJ.insertOrUpdateDownload(data);
Uri uri = JsonDataBase.INSTANCE.saveToGallery(WallpaperViewActivity.this, file);
runOnUiThread(new Runnable() {
@Override
public void run() {
showDownloadLoading(false);
if (uri == null) {
Toast.makeText(WallpaperViewActivity.this, getString(R.string.save_fail), Toast.LENGTH_SHORT).show();
} else {
// deleteCacheFile();
Toast.makeText(WallpaperViewActivity.this, getString(R.string.save_success), Toast.LENGTH_LONG).show();
}
Log.d(DreamWallpaper.TAG, "--------path=" + file.getAbsolutePath() + "---uri=" + uri);
}
});
}
@Override
public void onSelectType(int type) {
showSetWallpaperLoading(true);
if (downloadFile != null && downloadFile.exists()) {
new Thread(new Runnable() {
@Override
public void run() {
Log.d(DreamWallpaper.TAG, "--------downloadFile=" + downloadFile.exists());
setWallpaper(downloadFile, type);
}
}).start();
}
// else if (fullDrawable != null) {
// new Thread(new Runnable() {
// @Override
// public void run() {
// File file = new File(CommonHelper.saveDrawableToFile(fullDrawable, mSavePath));
// setWallpaper(file, type);
// }
// }).start();
// }
else {
call = JsonDataBase.INSTANCE.downloadFile(fullUrl, mSavePath, new Function2<Boolean, InputStream, Unit>() {
@Override
public Unit invoke(Boolean aBoolean, InputStream inputStream) {
Log.d(DreamWallpaper.TAG, "--------downloadFile=" + Thread.currentThread().getName());
File file = new File(mSavePath);
if (aBoolean && file.exists()) {
downloadFile = file;
setWallpaper(downloadFile, type);
} else {
runOnUiThread(new Runnable() {
@Override
public void run() {
showSetWallpaperLoading(false);
Toast.makeText(WallpaperViewActivity.this, getString(R.string.set_fail), Toast.LENGTH_SHORT).show();
}
});
}
return null;
}
});
}
}
private void setWallpaper(File file, int type) {
try {
FileInputStream fileInputStream = new FileInputStream(file);
switch (type) {
case MyDialogView.type_home:
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
wallpaperManager.setStream(fileInputStream);
} else {
wallpaperManager.setStream(
fileInputStream,
null,
true,
WallpaperManager.FLAG_SYSTEM
);
}
break;
case MyDialogView.type_lock:
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
wallpaperManager.setStream(fileInputStream);
} else {
wallpaperManager.setStream(
fileInputStream,
null,
true,
WallpaperManager.FLAG_LOCK
);
}
break;
case MyDialogView.type_both:
wallpaperManager.setStream(fileInputStream);
break;
}
deleteCacheFile();
runOnUiThread(new Runnable() {
@Override
public void run() {
showSetWallpaperLoading(false);
Toast.makeText(WallpaperViewActivity.this, getString(R.string.set_success), Toast.LENGTH_SHORT).show();
}
});
} catch (Exception exception) {
runOnUiThread(new Runnable() {
@Override
public void run() {
showSetWallpaperLoading(false);
Toast.makeText(WallpaperViewActivity.this, getString(R.string.set_fail), Toast.LENGTH_SHORT).show();
}
});
}
}
private void deleteCacheFile() {
if (downloadFile != null && downloadFile.exists()) {
boolean delete = downloadFile.delete();
Log.d(DreamWallpaper.TAG, "--------delete=" + delete);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (call != null) {
call.cancel();
}
}
private void loadAd(){
AdsInsUtil.INSTANCE.loadAd(this, AdsInsUtil.Placement.TOP_ON_AD_THREE, new LoadListener() {
@Override
public void loadFailed(@NotNull String error) {
}
});
}
}

View File

@ -0,0 +1,81 @@
package com.wall.dream.wallpapers.ad
import android.app.Activity
import android.util.Log
import com.tradplus.ads.base.bean.TPAdError
import com.tradplus.ads.base.bean.TPAdInfo
import com.tradplus.ads.open.interstitial.InterstitialAdListener
import com.tradplus.ads.open.interstitial.TPInterstitial
class AdInstLoad {
private var mPlace: String
private var adLoadListener: LoadListener? = null
private var activity: Activity? = null
constructor(activity: Activity, place: String, listener: LoadListener?) {
this.mPlace = place
this.adLoadListener = listener
this.activity = activity
init()
}
constructor(place: String, listener: LoadListener?) {
this.mPlace = place
this.adLoadListener = listener
init()
}
private fun init() {
val tpInterstitial = TPInterstitial(activity, mPlace)
tpInterstitial.setAdListener(object : InterstitialAdListener {
//广告加载完成 首个广告源加载成功时回调 一次加载流程只会回调一次
override fun onAdLoaded(tpAdInfo: TPAdInfo?) {
if (tpAdInfo != null) {
Log.d("ocean", "$mPlace 广告load成功tpAdInfo有值")
InstAdCacheManager.Companion.instance.setAdCache(mPlace, tpInterstitial)
adLoadListener?.loaded(tpAdInfo)
} else {
adLoadListener?.loadFailed("tpAdInfo没有值")
Log.d("ocean", "$mPlace tpAdInfo没有值")
}
}
// 广告被点击
override fun onAdClicked(tpAdInfo: TPAdInfo?) {
Log.d("ocean", "$mPlace tradplus onAdClicked")
}
// 广告成功展示在页面上
override fun onAdImpression(tpAdInfo: TPAdInfo?) {
Log.d("ocean", "$mPlace tradplus onAdImpression")
}
// 广告加载失败
override fun onAdFailed(error: TPAdError?) {
adLoadListener?.loadFailed("code->${error?.errorCode}message->${error?.errorMsg}")
Log.d("ocean", "$mPlace load ad onError->code->${error?.errorCode}message->${error?.errorMsg}")
}
// 广告被关闭
override fun onAdClosed(tpAdInfo: TPAdInfo?) {
Log.d("ocean", "$mPlace tradplus onAdClosed")
}
// 视频播放开始(部分广告源支持)
override fun onAdVideoStart(tpAdInfo: TPAdInfo?) {
Log.d("ocean", "$mPlace tradplus onAdVideoStart")
}
//视频播放结束(部分广告源支持)
override fun onAdVideoEnd(tpAdInfo: TPAdInfo?) {
Log.d("ocean", "$mPlace tradplus onAdVideoEnd")
}
//视频播放失败(部分广告源支持)
override fun onAdVideoError(tpAdInfo: TPAdInfo?, error: TPAdError?) {
Log.d("ocean", "$mPlace onAdVideoError code->${error?.errorCode}message->${error?.errorMsg}")
}
})
tpInterstitial.loadAd()
}
}

View File

@ -0,0 +1,69 @@
package com.wall.dream.wallpapers.ad
import android.app.Activity
import android.util.Log
import com.tradplus.ads.base.bean.TPAdError
import com.tradplus.ads.base.bean.TPAdInfo
import com.tradplus.ads.open.interstitial.InterstitialAdListener
class AdInstShower {
private var mPlace: String
private var showListener: ShowListener? = null
private var activity: Activity? = null
constructor(activity: Activity, place: String, showListener: ShowListener?) {
this.mPlace = place
this.showListener = showListener
this.activity = activity
init()
}
constructor(place: String, showListener: ShowListener?) {
this.mPlace = place
this.showListener = showListener
init()
}
private fun init() {
val interstitialAd = InstAdCacheManager.Companion.instance.getAdCache(mPlace)
interstitialAd?.setAdListener(object : InterstitialAdListener {
//广告加载完成 首个广告源加载成功时回调 一次加载流程只会回调一次
override fun onAdLoaded(tpAdInfo: TPAdInfo?) {}
// 广告被点击
override fun onAdClicked(tpAdInfo: TPAdInfo?) {
showListener?.onAdClicked()
Log.d("ocean", "AdInstShower 广告点击回调")
}
// 广告成功展示在页面上
override fun onAdImpression(tpAdInfo: TPAdInfo?) {
showListener?.onAdShown(tpAdInfo)
Log.d("ocean", "AdInstShower 广告展示回调")
}
// 广告加载失败
override fun onAdFailed(error: TPAdError?) {}
// 广告被关闭
override fun onAdClosed(tpAdInfo: TPAdInfo?) {
showListener?.onAdClosed()
Log.d("ocean", "AdInstShower 广告关闭回调")
}
// 视频播放开始(部分广告源支持)
override fun onAdVideoStart(tpAdInfo: TPAdInfo?) {}
//视频播放结束(部分广告源支持)
override fun onAdVideoEnd(tpAdInfo: TPAdInfo?) {}
//视频播放失败(部分广告源支持)
override fun onAdVideoError(tpAdInfo: TPAdInfo?, error: TPAdError?) {
Log.d("ocean", "AdInstShower 视频广告播放失败回调->${error}")
showListener?.onAdShowFailed(AdShowFailed(error?.errorMsg.toString()))
}
})
interstitialAd?.showAd(activity!!, mPlace)
}
}

View File

@ -0,0 +1,5 @@
package com.wall.dream.wallpapers.ad
data class AdShowFailed(
val msg: String = "",
)

View File

@ -0,0 +1,28 @@
package com.wall.dream.wallpapers.ad
import android.app.Activity
object AdsInsUtil {
object Placement {
const val TOP_ON_AD_ONE = "7B5D16975984B52277ED07237550F212"
const val TOP_ON_AD_TOW = "028F7A0076C3128FFFD8019A15A6C312"
const val TOP_ON_AD_THREE = "9D6307EA4CCAE767AFE991533F0BA212"
}
fun loadAd(
act: Activity,
adID: String,
loadListener: LoadListener?
): AdInstLoad {
return AdInstLoad(act, adID, loadListener)
}
fun showAd(
act: Activity,
adID: String,
listener: ShowListener?
): AdInstShower {
return AdInstShower(act, adID, listener)
}
}

View File

@ -0,0 +1,35 @@
package com.wall.dream.wallpapers.ad
import com.tradplus.ads.open.interstitial.TPInterstitial
class InstAdCacheManager {
private val mAdCacheDict: MutableMap<String, TPInterstitial> = mutableMapOf()
companion object {
val instance: InstAdCacheManager by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
InstAdCacheManager()
}
}
fun setAdCache(place: String, adCache: TPInterstitial) {
mAdCacheDict[place] = adCache
}
fun getAdCache(place: String): TPInterstitial? {
return mAdCacheDict[place]
}
fun getLoadedInstCount(): Int {
var count = 0
try {
mAdCacheDict.forEach { (key, value) ->
if (value.isReady) {
count += 1
}
}
} catch (_: Exception) {
}
return count
}
}

View File

@ -0,0 +1,8 @@
package com.wall.dream.wallpapers.ad
import com.tradplus.ads.base.bean.TPAdInfo
interface LoadListener {
fun loadFailed(error: String) {}
fun loaded(ad: TPAdInfo) {}
}

View File

@ -0,0 +1,10 @@
package com.wall.dream.wallpapers.ad
import com.tradplus.ads.base.bean.TPAdInfo
interface ShowListener {
fun onAdShown(ad: TPAdInfo?) {}
fun onAdShowFailed(error: AdShowFailed?) {}
fun onAdClosed() {}
fun onAdClicked() {}
}

View File

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

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 箭头图标 -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/tech_blue"
android:pathData="M12,4l-1.41,1.41L16.17,11H4v2h12.17l-5.58,5.59L12,20l8,-8z"/>
</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">
<gradient
android:type="linear"
android:angle="135"
android:startColor="#E0FFAB91"
android:centerColor="#E0F48FB1"
android:endColor="#E0CE93D8" />
</shape>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 分类卡片右侧渐变装饰条 - 柔和低调版本 -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:startColor="#3A4A5A"
android:centerColor="#4A5A6A"
android:endColor="#5A6A7A"
android:angle="90"
android:type="linear" />
<corners android:radius="2dp" />
</shape>

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">
<solid android:color="#FAFAFA" />
<corners android:radius="16dp" />
<stroke
android:width="0.5dp"
android:color="#F0F0F0" />
</shape>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 分类网格图标 -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/tech_blue"
android:pathData="M4,4h6v6h-6zM14,4h6v6h-6zM4,14h6v6h-6zM14,14h6v6h-6z"/>
</vector>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 分类详情页信息卡片背景 - 更白的背景 + 更深的阴影 -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 阴影层 - 0 4px 14px rgba(0,0,0,0.10) -->
<item
android:left="0dp"
android:top="4dp"
android:right="0dp"
android:bottom="-10dp">
<shape android:shape="rectangle">
<solid android:color="#1A000000" />
<corners android:radius="12dp" />
</shape>
</item>
<!-- 卡片主体背景 - 更接近纯白 (#FFFFFF, 96%不透明 = 4%透明) -->
<item
android:left="0dp"
android:top="0dp"
android:right="0dp"
android:bottom="0dp">
<shape android:shape="rectangle">
<corners android:radius="12dp"/>
<solid android:color="#F5FFFFFF"/>
</shape>
</item>
</layer-list>

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 自然分类图标 -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/tech_blue"
android:pathData="M17,8C8,10 5.9,16.17 3.82,21.34l1.89,0.66C7.84,17.7 9.74,12.47 17,11V8zM3.95,19.74C3.98,19.83 4.01,19.92 4.05,20H4C4,19.91 3.97,19.83 3.95,19.74z"/>
<path
android:fillColor="@color/tech_blue"
android:pathData="M9,4C9,5.1 9.9,6 11,6C12.1,6 13,5.1 13,4C13,2.9 12.1,2 11,2C9.9,2 9,2.9 9,4z"/>
<path
android:fillColor="@color/tech_blue"
android:pathData="M20.5,10C19.1,10 18,8.9 18,7.5C18,6.1 19.1,5 20.5,5C21.9,5 23,6.1 23,7.5C23,8.9 21.9,10 20.5,10z"/>
</vector>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 圆形背景 - 分类选中状态 -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<gradient
android:type="linear"
android:angle="135"
android:startColor="@color/gradient_blue"
android:endColor="@color/gradient_pink" />
<size android:width="40dp" android:height="40dp"/>
</shape>

View File

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

View File

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

View File

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

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 收藏按钮小条 - 带极轻柔阴影 (0 2 6 rgba(0,0,0,0.12)) -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 阴影层 - y偏移2dp模糊6dp -->
<item
android:left="0dp"
android:top="4dp"
android:right="0dp"
android:bottom="-2dp">
<shape android:shape="rectangle">
<solid android:color="#1F000000" />
<corners android:radius="12dp" />
</shape>
</item>
<!-- 主体背景 - 白色30%透明度 (#4DFFFFFF = 30%) -->
<item
android:left="0dp"
android:top="0dp"
android:right="0dp"
android:bottom="2dp">
<shape android:shape="rectangle">
<solid android:color="#4DFFFFFF" />
<corners android:radius="12dp" />
</shape>
</item>
</layer-list>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 现代渐变活力风装饰条 -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:type="linear"
android:angle="0"
android:startColor="@color/gradient_blue"
android:centerColor="@color/gradient_pink"
android:endColor="@color/gradient_orange_yellow" />
</shape>

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 现代渐变活力风按钮背景 -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 阴影 -->
<item
android:top="1dp"
android:left="1dp">
<shape android:shape="oval">
<solid android:color="@color/shadow_light"/>
<size android:width="48dp" android:height="48dp"/>
</shape>
</item>
<!-- 渐变边框 -->
<item
android:bottom="1dp"
android:right="1dp">
<shape android:shape="oval">
<gradient
android:type="linear"
android:angle="135"
android:startColor="#3A4A5A"
android:centerColor="#4A5A6A"
android:endColor="#5A6A7A" />
<size android:width="48dp" android:height="48dp"/>
</shape>
</item>
<!-- 主体 -->
<item
android:top="2dp"
android:bottom="2dp"
android:left="2dp"
android:right="2dp">
<shape android:shape="oval">
<solid android:color="@color/cold_silver"/>
<size android:width="46dp" android:height="46dp"/>
</shape>
</item>
<!-- 高光 -->
<item
android:top="2dp"
android:bottom="24dp"
android:left="2dp"
android:right="2dp">
<shape android:shape="oval">
<solid android:color="@color/texture_highlight"/>
<size android:width="46dp" android:height="22dp"/>
</shape>
</item>
</layer-list>

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 现代渐变活力风卡片背景 -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 阴影层 -->
<item android:top="2dp">
<shape android:shape="rectangle">
<corners android:radius="16dp"/>
<solid android:color="@color/shadow_light"/>
</shape>
</item>
<!-- 渐变边框 -->
<item android:bottom="2dp">
<shape android:shape="rectangle">
<corners android:radius="16dp"/>
<gradient
android:type="linear"
android:angle="135"
android:startColor="@color/gradient_blue"
android:centerColor="@color/gradient_pink"
android:endColor="@color/gradient_orange_yellow" />
</shape>
</item>
<!-- 卡片主体 -->
<item
android:top="1dp"
android:bottom="3dp"
android:left="1dp"
android:right="1dp">
<shape android:shape="rectangle">
<corners android:radius="16dp"/>
<solid android:color="@color/card_bg"/>
</shape>
</item>
<!-- 渐变质感叠加 -->
<item
android:top="1dp"
android:bottom="3dp"
android:left="1dp"
android:right="1dp">
<shape android:shape="rectangle">
<corners android:radius="16dp"/>
<solid android:color="@color/tech_blue_subtle"/>
</shape>
</item>
</layer-list>

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 森林清新悬浮卡片 - 用于列表项 -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 深阴影 -->
<item
android:top="3dp"
android:left="2dp">
<shape android:shape="rectangle">
<corners android:radius="14dp"/>
<solid android:color="@color/shadow_light"/>
</shape>
</item>
<!-- 清新绿色边框 -->
<item
android:bottom="1dp"
android:right="1dp">
<shape android:shape="rectangle">
<corners android:radius="14dp"/>
<solid android:color="@color/tech_blue_light"/>
</shape>
</item>
<!-- 卡片主体 -->
<item
android:top="2dp"
android:bottom="2dp"
android:left="1dp"
android:right="2dp">
<shape android:shape="rectangle">
<corners android:radius="14dp"/>
<solid android:color="@color/sand_surface"/>
</shape>
</item>
<!-- 清新质感叠加 -->
<item
android:top="2dp"
android:bottom="2dp"
android:left="1dp"
android:right="2dp">
<shape android:shape="rectangle">
<corners android:radius="14dp"/>
<solid android:color="@color/sand_grain"/>
</shape>
</item>
</layer-list>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 森林清新搜索框背景 -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<corners android:radius="20dp"/>
<solid android:color="@color/cold_silver"/>
</shape>
</item>
<item
android:top="1dp"
android:bottom="10dp">
<shape android:shape="rectangle">
<corners android:radius="20dp"/>
<solid android:color="@color/texture_highlight"/>
</shape>
</item>
</layer-list>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 六边形背景 - 选中状态 -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="48"
android:viewportHeight="48">
<path
android:fillColor="@color/tech_blue"
android:pathData="M24,4 L36,10 L36,22 L24,28 L12,22 L12,10 Z"/>
<path
android:fillColor="@color/white"
android:pathData="M24,8 L32,12 L32,20 L24,24 L16,20 L16,12 Z"/>
</vector>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 信息卡片背景 - 完全扁平,无阴影,无圆角,纯信息展示 -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FFFFFF"/>
<!-- 移除圆角,让它看起来更像信息条而不是卡片 -->
</shape>

View File

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

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 现代渐变活力风背景 - 从蓝色到粉色到橙黄色 -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:type="linear"
android:angle="135"
android:startColor="@color/gradient_blue"
android:centerColor="@color/gradient_pink"
android:endColor="@color/gradient_orange_yellow" />
</shape>

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