接入TradPlus

This commit is contained in:
yuqian 2025-12-18 10:36:44 +08:00
commit 6720c7a136
132 changed files with 171134 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 @@
ProShotWallpapers

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>

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

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

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

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

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

@ -0,0 +1,20 @@
<?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>
<option name="resolveExternalAnnotations" value="false" />
</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>

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/ProShotWallPapers Normal file

Binary file not shown.

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

@ -0,0 +1,61 @@
import java.text.SimpleDateFormat
import java.util.Date
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("io.objectbox")
kotlin("kapt")
}
val timestamp = SimpleDateFormat("MM_dd_HH_mm").format(Date())
android {
namespace = "com.wall.proshot.wallpapers"
compileSdk = 36
defaultConfig {
applicationId = "com.proshot.wallpapers.wallpapers"
minSdk = 24
targetSdk = 36
versionCode = 1
versionName = "1.0"
project.setProperty("archivesBaseName", "proshotwallpapers" + versionName + "(${versionCode})_$timestamp")
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_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")
implementation("com.squareup.okhttp3:okhttp:5.3.1")
}

View File

@ -0,0 +1,130 @@
{
"_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": "5:5860158647763216966",
"lastPropertyId": "13:9116459565289884652",
"name": "Data",
"properties": [
{
"id": "1:3842249719658497221",
"name": "id",
"type": 6,
"flags": 1
},
{
"id": "2:7656668900039559696",
"name": "categoryName",
"type": 9
},
{
"id": "3:2993670133306655828",
"name": "imId",
"type": 9
},
{
"id": "4:2976976858020722437",
"name": "description",
"type": 9
},
{
"id": "5:4970800682946357505",
"name": "fullUrl",
"type": 9
},
{
"id": "6:402403201842829795",
"name": "previewUrl1080",
"type": 9
},
{
"id": "7:1377095352851663880",
"name": "previewUrl400",
"type": 9
},
{
"id": "8:4605994455125070811",
"name": "previewUrl200",
"type": 9
},
{
"id": "9:8907678727101552112",
"name": "authorName",
"type": 9
},
{
"id": "10:409606889961149348",
"name": "authorHeader",
"type": 9
},
{
"id": "11:4539572102818742294",
"name": "authorHtml",
"type": 9
},
{
"id": "12:5893189528971555506",
"name": "isLike",
"type": 1
},
{
"id": "13:9116459565289884652",
"name": "isDownload",
"type": 1
}
],
"relations": []
}
],
"lastEntityId": "5:5860158647763216966",
"lastIndexId": "0:0",
"lastRelationId": "0:0",
"lastSequenceId": "0:0",
"modelVersion": 5,
"modelVersionParserMinimum": 5,
"retiredEntityUids": [
8119453540460508569,
8776066878034520742,
817335537070466014,
5374318059423987080
],
"retiredIndexUids": [],
"retiredPropertyUids": [
8848640050018073106,
4870222079156330783,
4966768060561274983,
8892036187720267027,
1670319685727744805,
3855211567189961055,
7567671966987007993,
2590164264280025677,
8912833100894718986,
7138929457594592554,
3957870060050722570,
2943285943884558608,
7262008615134929676,
7105947400861196483,
1954934496493857304,
8582031355111471002,
8410380097928190493,
3380197792593924336,
5750724995960958985,
5907193265594068445,
7643711915014989832,
5454072153734548882,
8866886314389627366,
6647852625511577303,
8481286751506557167,
615207224772228883,
2114128640869665061,
4004858028833616093,
1649948666606108567,
4925649389754620618,
6869613325061909824,
1127054227079914732
],
"retiredRelationUids": [],
"version": 1
}

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": "MyData",
"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
}

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

@ -0,0 +1,28 @@
# 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.proshot.wallpaper.wallpaper.mybean.** { *; }
-keep class com.google.gson.** { *; }
-keepattributes Signature
-keepattributes AnnotationDefault,RuntimeVisibleAnnotations

View File

@ -0,0 +1,20 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.proshot.wallpapers.wallpapers",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0",
"outputFile": "proshotwallpapers1.0(1)_12_04_14_03-release.apk"
}
],
"elementType": "File"
}

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,49 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<application
android:name="com.wall.proshot.wallpapers.FreeWallPaper"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/logo7"
android:label="@string/app_name"
android:roundIcon="@mipmap/logo7"
android:supportsRtl="true"
android:theme="@style/Theme.Wallpaper"
tools:targetApi="31">
<activity
android:name="com.wall.proshot.wallpapers.myacctivity.SearchActivity"
android:exported="false" />
<activity
android:name="com.wall.proshot.wallpapers.myacctivity.ListActivity"
android:exported="false" />
<activity
android:name="com.wall.proshot.wallpapers.myacctivity.MySplashActivity"
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.proshot.wallpapers.myacctivity.WallPaperActivity"
android:exported="false" />
<activity
android:name="com.wall.proshot.wallpapers.myacctivity.MyMainActivity"
android:exported="false" />
<activity
android:name="com.wall.proshot.wallpapers.myacctivity.MySettingActivity"
android:exported="false" />
</application>
</manifest>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,87 @@
package com.wall.proshot.wallpapers;
import android.app.Application;
import android.content.Context;
import android.graphics.Typeface;
import android.util.Log;
import com.wall.proshot.wallpapers.bean.Data;
import com.wall.proshot.wallpapers.mytool.MyComUtils;
import com.wall.proshot.wallpapers.mytool.MyObectBoxManager;
import com.wall.proshot.wallpapers.mytool.JsonData;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FreeWallPaper extends Application {
public static Context mAppContext;
public static String TAG = "-------MyApp---------";
public static Typeface defaultFont;
private String animasName = "Animals.json";
private String exName = "Experimental.json";
private String filmName = "Film.json";
private String natureName = "Nature.json";
private String pattName = "Patterns.json";
private String streetName = "Street.json";
private String travelName = "Travel.json";
private String wallpaperName = "Featured.json";
private ExecutorService executor;
private static List<String> CategoryNames = new ArrayList<>();
private int i = 0;
@Override
public void onCreate() {
super.onCreate();
mAppContext = this;
defaultFont = Typeface.createFromAsset(getAssets(), "custfont.ttf");
MyObectBoxManager.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 = MyComUtils.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(FreeWallPaper.TAG, "------------111");
List<Data> data = JsonData.INSTANCE.getData(covertStr, realName);
Collections.shuffle(data);
for (Data data1:data){
MyObectBoxManager.addData(data1);
}
// }
}
});
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static List<String> getCategoryNames() {
return CategoryNames;
}
}

View File

@ -0,0 +1,160 @@
package com.wall.proshot.wallpapers.bean;
import androidx.annotation.Nullable;
import java.io.Serializable;
import io.objectbox.annotation.Entity;
import io.objectbox.annotation.Id;
@Entity
public class Data 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 Data() {}
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) {
Data obj1 = (Data) obj;
if (obj1 != null) {
if (obj1.getImId().equals(imId)) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,98 @@
package com.wall.proshot.wallpapers.myacctivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.wall.proshot.wallpapers.R;
import com.wall.proshot.wallpapers.databinding.ActivityMyListBinding;
import com.wall.proshot.wallpapers.myconnector.OnItemClick;
import com.wall.proshot.wallpapers.myitem.MyItemList;
import com.wall.proshot.wallpapers.bean.Data;
import com.wall.proshot.wallpapers.mytool.MyComUtils;
import com.wall.proshot.wallpapers.mytool.MyObectBoxManager;
import java.util.List;
public class ListActivity extends AppCompatActivity implements OnItemClick {
private ActivityMyListBinding vb;
private String categoryName;
public static final String key_index = "index";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
vb = ActivityMyListBinding.inflate(getLayoutInflater());
setContentView(vb.getRoot());
MyComUtils.initFull(this, false);
// 获取分类名称容错处理
categoryName = getIntent().getStringExtra(key_index);
if (categoryName == null || categoryName.isEmpty()) {
categoryName = getString(R.string.app_name);
}
vb.name.setText(categoryName);
vb.imageviewBack.setOnClickListener(v -> finish());
initList();
}
private void initList() {
// 查询分类数据容错处理
List<Data> data = MyObectBoxManager.queryCategoryAll(categoryName);
GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return 1; // 每个item占1列两列布局
}
});
vb.list.setLayoutManager(gridLayoutManager);
int spacing = MyComUtils.dp2Px(10); // 间距10dp转px
vb.list.addItemDecoration(new RecyclerView.ItemDecoration() {
@Override
public void getItemOffsets(android.graphics.Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
int column = position % 2; // 0=左列1=右列
// 左右间距左列左边0右边spacing/2右列左边spacing/2右边0
outRect.left = column == 0 ? 0 : spacing / 2;
outRect.right = column == 0 ? spacing / 2 : 0;
// 上下间距第一行顶部spacing其余行上下各spacing/2
if (position < 2) {
outRect.top = spacing;
} else {
outRect.top = spacing / 2;
}
outRect.bottom = spacing / 2;
}
});
// 3. 设置Adapteritem高度优化适配两列
int itemHeight = MyComUtils.dp2Px(220); // 调整item高度220dp更协调
MyItemList myItemList = new MyItemList(this, itemHeight, false);
myItemList.setDataInfo(data);
myItemList.setInfoWallpaperListener(this);
vb.list.setAdapter(myItemList);
// 4. 优化RecyclerView滚动性能
vb.list.setHasFixedSize(true); // 固定item大小提升滚动流畅度
vb.list.setItemViewCacheSize(20); // 增加缓存item数量
}
@Override
public void onItemClickAction(Data info) {
Intent intent = new Intent(this, WallPaperActivity.class);
intent.putExtra(MyComUtils.key_info, info);
startActivity(intent);
}
}

View File

@ -0,0 +1,179 @@
package com.wall.proshot.wallpapers.myacctivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import androidx.activity.EdgeToEdge;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import com.wall.proshot.wallpapers.myfragment.FragmentLike;
import com.wall.proshot.wallpapers.myfragment.FragmentMain;
import com.wall.proshot.wallpapers.mytool.MyComUtils;
import com.wall.proshot.wallpapers.R;
import com.wall.proshot.wallpapers.databinding.ActivityMyMainBinding;
import com.wall.proshot.wallpapers.databinding.MyItemTabBinding;
import java.util.ArrayList;
import java.util.List;
public class MyMainActivity extends AppCompatActivity {
private ActivityMyMainBinding vb;
private List<Fragment> fragmentList = new ArrayList<>();
// Tab 图标选择器主页home_0选中 / home_1未选中收藏对应选中/未选中图
private int[] tabIcons = {
R.drawable.selector_tab_home,
R.drawable.selector_tab_like
};
private String[] tabTitles;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
vb = ActivityMyMainBinding.inflate(getLayoutInflater());
MyComUtils.initFull(this, false);
setContentView(vb.getRoot());
// 初始化顶部标题
tabTitles = new String[]{
getString(R.string.app_name),
getString(R.string.collections)
};
// 初始化 Fragment 列表
initFragments();
// 修复 Tab 初始选中状态逻辑
initViewPagerAndTab();
// 初始化点击事件
initClickEvents();
}
private void initFragments() {
fragmentList.clear();
fragmentList.add(FragmentMain.newInstance(0));
fragmentList.add(FragmentLike.newInstance());
}
private void initViewPagerAndTab() {
// ViewPager2 适配器
vb.viewpager2.setAdapter(new FragmentStateAdapter(this) {
@NonNull
@Override
public Fragment createFragment(int position) {
return fragmentList.get(position);
}
@Override
public int getItemCount() {
return fragmentList.size();
}
});
vb.viewpager2.setUserInputEnabled(false);
// 绑定 TabLayout ViewPager2
new TabLayoutMediator(vb.tab, vb.viewpager2, new TabLayoutMediator.TabConfigurationStrategy() {
@Override
public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
MyItemTabBinding tabBinding = MyItemTabBinding.inflate(getLayoutInflater());
// 设置 Tab 图标选择器自动处理选中/未选中状态
tabBinding.imageIcon.setImageDrawable(ContextCompat.getDrawable(
MyMainActivity.this, tabIcons[position]
));
// 初始状态 0 Tab主页显示指示器无需 setSelected
tabBinding.imageIndicator.setVisibility(position == 0 ? View.VISIBLE : View.GONE);
tab.setCustomView(tabBinding.getRoot());
}
}).attach();
if (vb.tab.getTabCount() > 0) {
vb.tab.selectTab(vb.tab.getTabAt(0));
// 同步顶部标题
vb.textviewWallpaper.setText(tabTitles[0]);
}
// Tab 选中状态监听
vb.tab.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
View customView = tab.getCustomView();
if (customView != null) {
// 显示选中指示器
View indicator = customView.findViewById(R.id.image_indicator);
indicator.setVisibility(View.VISIBLE);
// 触发图标选择器切换到选中状态通过设置 ImageView selected 属性
ImageView icon = customView.findViewById(R.id.image_icon);
icon.setSelected(true);
}
// 同步 ViewPager2 页面
int position = tab.getPosition();
vb.viewpager2.setCurrentItem(position, false);
// 更新顶部标题
vb.textviewWallpaper.setText(tabTitles[position]);
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
View customView = tab.getCustomView();
if (customView != null) {
// 隐藏选中指示器
View indicator = customView.findViewById(R.id.image_indicator);
indicator.setVisibility(View.INVISIBLE);
// 触发图标选择器切换到未选中状态
ImageView icon = customView.findViewById(R.id.image_icon);
icon.setSelected(false);
}
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
// 重选 Tab 滚动到顶部可选
int position = tab.getPosition();
if (position == 0) {
FragmentMain homeFragment = (FragmentMain) fragmentList.get(0);
homeFragment.scrollToTop();
} else if (position == 1) {
FragmentLike likeFragment = (FragmentLike) fragmentList.get(1);
likeFragment.scrollToTop();
}
}
});
// ViewPager2 页面切换监听防止状态不同步
vb.viewpager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
TabLayout.Tab tab = vb.tab.getTabAt(position);
if (tab != null && !tab.isSelected()) {
vb.tab.selectTab(tab);
}
}
});
}
private void initClickEvents() {
// 搜索图标点击
vb.imSearch.setOnClickListener(v -> {
Intent intent = new Intent(MyMainActivity.this, SearchActivity.class);
startActivity(intent);
});
// 设置图标点击
vb.imSetting.setOnClickListener(v -> {
Intent intent = new Intent(MyMainActivity.this, MySettingActivity.class);
startActivity(intent);
});
}
}

View File

@ -0,0 +1,208 @@
package com.wall.proshot.wallpapers.myacctivity;
import android.app.Dialog;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import com.wall.proshot.wallpapers.R;
public class MySettingActivity extends AppCompatActivity {
// 声明星星控件方便统一管理
private ImageView star1, star2, star3, star4, star5;
// 记录用户选择的星级
private int selectedStar = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_my_setting);
LinearLayout llRateUs = findViewById(R.id.ll_rate_us);
ImageView ivBack = findViewById(R.id.iv_back3);
initVersionName();
// 设置点击事件
llRateUs.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 弹出评分弹窗
showRateUsDialog();
}
});
if (ivBack != null) {
ivBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 构建跳转 Intent
Intent intent = new Intent(MySettingActivity.this, MyMainActivity.class);
//关闭
finish();
}
});
}
}
private void showRateUsDialog() {
Dialog rateDialog = new Dialog(this);
rateDialog.setContentView(R.layout.my_rate_us);
// 关键取消窗口默认背景设为null仅显示CardView的圆角区域
rateDialog.getWindow().setBackgroundDrawable(null);
// 1. 找到弹窗中的所有星星和按钮
star1 = rateDialog.findViewById(R.id.star1);
star2 = rateDialog.findViewById(R.id.star2);
star3 = rateDialog.findViewById(R.id.star3);
star4 = rateDialog.findViewById(R.id.star4);
star5 = rateDialog.findViewById(R.id.star5);
//TextView tvSelectedStar = rateDialog.findViewById(R.id.tv_selected_star);
View btnCancel = rateDialog.findViewById(R.id.btn_cancel);
View btnRateIt = rateDialog.findViewById(R.id.btn_rate_it);
// 2. 给每个星星设置点击事件
setStarClickListener();
// 3. 取消按钮点击事件
btnCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
rateDialog.dismiss(); // 关闭弹窗
// 引用字符串资源
Toast.makeText(MySettingActivity.this,
getString(R.string.toast_cancel_rate),
Toast.LENGTH_SHORT).show();
}
});
// 4. 评分按钮点击事件
btnRateIt.setOnClickListener(v -> {
if (selectedStar > 0) {
// 格式化字符串替换星级占位符
String rateToast = String.format(getString(R.string.toast_thank_for_rate), selectedStar);
Toast.makeText(MySettingActivity.this, rateToast, Toast.LENGTH_SHORT).show();
} else {
// 引用字符串资源
Toast.makeText(MySettingActivity.this,
getString(R.string.toast_please_select_star),
Toast.LENGTH_SHORT).show();
return; // 未选星级时不关闭弹窗
}
rateDialog.dismiss();
});
rateDialog.show();
}
// 封装星星点击事件的方法
private void setStarClickListener() {
// 星星1点击事件
star1.setOnClickListener(v -> {
selectedStar = 1;
updateStarState();
});
// 星星2点击事件
star2.setOnClickListener(v -> {
selectedStar = 2;
updateStarState();
});
// 星星3点击事件
star3.setOnClickListener(v -> {
selectedStar = 3;
updateStarState();
});
// 星星4点击事件
star4.setOnClickListener(v -> {
selectedStar = 4;
updateStarState();
});
// 星星5点击事件
star5.setOnClickListener(v -> {
selectedStar = 5;
updateStarState();
});
}
// 更新星星的显示状态黄色/灰色
private void updateStarState() {
// 先重置所有星星为灰色
resetAllStarsToGray();
// 根据选中的星级设置对应星星为黄色
switch (selectedStar) {
case 1:
star1.setImageResource(R.drawable.star_y);
break;
case 2:
star1.setImageResource(R.drawable.star_y);
star2.setImageResource(R.drawable.star_y);
break;
case 3:
star1.setImageResource(R.drawable.star_y);
star2.setImageResource(R.drawable.star_y);
star3.setImageResource(R.drawable.star_y);
break;
case 4:
star1.setImageResource(R.drawable.star_y);
star2.setImageResource(R.drawable.star_y);
star3.setImageResource(R.drawable.star_y);
star4.setImageResource(R.drawable.star_y);
break;
case 5:
star1.setImageResource(R.drawable.star_y);
star2.setImageResource(R.drawable.star_y);
star3.setImageResource(R.drawable.star_y);
star4.setImageResource(R.drawable.star_y);
star5.setImageResource(R.drawable.star_y);
break;
default:
break;
}
}
// 重置所有星星为灰色
private void resetAllStarsToGray() {
star1.setImageResource(R.drawable.star_g);
star2.setImageResource(R.drawable.star_g);
star3.setImageResource(R.drawable.star_g);
star4.setImageResource(R.drawable.star_g);
star5.setImageResource(R.drawable.star_g);
}
private void initVersionName() {
TextView tvVersion = findViewById(R.id.tv_version); // 注意需要给布局中的版本TextView设置id为tv_version
try {
// 获取包管理器
PackageManager packageManager = getPackageManager();
// 获取当前应用的包信息第二个参数传0表示获取基本信息
PackageInfo packageInfo = packageManager.getPackageInfo(getPackageName(), 0);
// 获取版本名
String versionName = packageInfo.versionName;
// 设置版本名拼接V前缀和原布局风格一致
tvVersion.setText("V" + versionName);
} catch (PackageManager.NameNotFoundException e) {
// 异常处理获取失败时显示默认值
e.printStackTrace();
tvVersion.setText(getString(R.string.setting_version));
}
}
}

View File

@ -0,0 +1,62 @@
package com.wall.proshot.wallpapers.myacctivity;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.os.CountDownTimer;
import androidx.appcompat.app.AppCompatActivity;
import com.wall.proshot.wallpapers.mytool.MyComUtils;
import com.wall.proshot.wallpapers.databinding.ActivityMySplashBinding;
public class MySplashActivity extends AppCompatActivity {
private CountDownTimer countDownTimer;
private ActivityMySplashBinding vb;
private long totalTime = 2000;
@SuppressLint("MissingInflatedId")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
vb = ActivityMySplashBinding.inflate(getLayoutInflater());
MyComUtils.initFull(this,true);
setContentView(vb.getRoot());
countDownTimer = new CountDownTimer(totalTime,100) {
@Override
public void onTick(long millisUntilFinished) {
int progressPercentage = (int) ((100 * millisUntilFinished) / totalTime);
int countdownPercentage = 100 - progressPercentage;
vb.progressbar.setProgress(countdownPercentage);
}
@Override
public void onFinish() {
vb.progressbar.setProgress(100);
Intent intent = new Intent(MySplashActivity.this, MyMainActivity.class);
startActivity(intent);
finish();
}
};
countDownTimer.start();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (countDownTimer != null) {
countDownTimer.cancel();
countDownTimer = null;
}
}
}

View File

@ -0,0 +1,105 @@
package com.wall.proshot.wallpapers.myacctivity
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.proshot.wallpapers.R
import com.wall.proshot.wallpapers.bean.Data
import com.wall.proshot.wallpapers.myconnector.OnItemClick
import com.wall.proshot.wallpapers.databinding.ActivityMySearchBinding
import com.wall.proshot.wallpapers.myitem.MyItemList
import com.wall.proshot.wallpapers.mytool.MyComUtils
import com.wall.proshot.wallpapers.mytool.MyItemHelper
import com.wall.proshot.wallpapers.mytool.MyObectBoxManager
class SearchActivity : AppCompatActivity() ,
OnItemClick {
private lateinit var adapterWallapper: MyItemList
private lateinit var binding:ActivityMySearchBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMySearchBinding.inflate(layoutInflater)
setContentView(binding.root)
MyComUtils.initFull(this, false)
initList()
binding.imageviewBack.setOnClickListener {
finish()
}
}
private fun initList() {
val height = MyComUtils.dp2Px(180)
adapterWallapper =
MyItemList(this, height, true)
adapterWallapper.setInfoWallpaperListener(this)
val recyclerMyItemHelper = MyItemHelper(10, 10, 15)
val gridLayoutManager = GridLayoutManager(this, 2)
binding.resultRecycler.run {
layoutManager = gridLayoutManager
addItemDecoration(recyclerMyItemHelper)
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 = MyObectBoxManager.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: Data?) {
val intent = Intent(this, WallPaperActivity::class.java)
intent.putExtra(MyComUtils.key_info, info)
startActivity(intent)
}
}

View File

@ -0,0 +1,407 @@
package com.wall.proshot.wallpapers.myacctivity;
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.wall.proshot.wallpapers.FreeWallPaper;
import com.wall.proshot.wallpapers.bean.Data;
import com.wall.proshot.wallpapers.myconnector.OnSelectType;
import com.wall.proshot.wallpapers.myfragment.Dialog;
import com.wall.proshot.wallpapers.mytool.MyComUtils;
import com.wall.proshot.wallpapers.mytool.MyObectBoxManager;
import com.wall.proshot.wallpapers.R;
import com.wall.proshot.wallpapers.databinding.ActivityMyWallapperBinding;
import com.wall.proshot.wallpapers.mytool.JsonData;
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 WallPaperActivity extends AppCompatActivity implements OnSelectType {
private WeakReference<WallPaperActivity> weakReference;
private Data data;
private WallpaperManager wallpaperManager;
private int permissionCode = 1;
private String mSavePath;
private String imId;
private String fullUrl;
private Dialog dialogType;
private File downloadFile;
private Call call;
private ActivityMyWallapperBinding vb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
vb = ActivityMyWallapperBinding.inflate(getLayoutInflater());
MyComUtils.initFull(this, true);
setContentView(vb.getRoot());
weakReference = new WeakReference<>(this);
data = (Data) getIntent().getSerializableExtra(MyComUtils.key_info);
if (data == null) {
return;
}
imId = data.getImId();
mSavePath = JsonData.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 = MyComUtils.getScreenWidthHeight(this);
Log.d(FreeWallPaper.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(WallPaperActivity.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(FreeWallPaper.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 = MyObectBoxManager.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 Dialog();
dialogType.setListener(WallPaperActivity.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);
MyObectBoxManager.updateLike(data);
}
});
vb.layoutDownload.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean permission = JsonData.INSTANCE.requestPermission(WallPaperActivity.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(FreeWallPaper.TAG, "-----------Download 2");
startSave(downloadFile);
return;
}
Log.d(FreeWallPaper.TAG, "-----------Download 3");
doDownload(true, true);
}
private void doDownload(boolean showMsg, boolean save) {
call = JsonData.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() {
WallPaperActivity activity = weakReference.get();
if (activity != null && !activity.isDestroyed()) {
Log.d(FreeWallPaper.TAG, "-------weakReference !=null");
// Glide.with(activity)
// .asDrawable()
// .load(downloadFile)
// .into(vb.imageviewPreview);
} else {
Log.d(FreeWallPaper.TAG, "-------weakReference null");
}
}
});
} else {
runOnUiThread(new Runnable() {
@Override
public void run() {
showDownloadLoading(false);
if (showMsg) {
Toast.makeText(WallPaperActivity.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(FreeWallPaper.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) {
MyObectBoxManager.insertOrUpdateDownload(data);
Uri uri = JsonData.INSTANCE.saveToGallery(WallPaperActivity.this, file);
runOnUiThread(new Runnable() {
@Override
public void run() {
showDownloadLoading(false);
if (uri == null) {
Toast.makeText(WallPaperActivity.this, getString(R.string.save_fail), Toast.LENGTH_SHORT).show();
} else {
// deleteCacheFile();
Toast.makeText(WallPaperActivity.this, getString(R.string.save_success), Toast.LENGTH_LONG).show();
}
Log.d(FreeWallPaper.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(FreeWallPaper.TAG, "--------downloadFile=" + downloadFile.exists());
setWallpaper(downloadFile, type);
}
}).start();
}
else {
call = JsonData.INSTANCE.downloadFile(fullUrl, mSavePath, new Function2<Boolean, InputStream, Unit>() {
@Override
public Unit invoke(Boolean aBoolean, InputStream inputStream) {
Log.d(FreeWallPaper.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(WallPaperActivity.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 Dialog.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 Dialog.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 Dialog.type_both:
wallpaperManager.setStream(fileInputStream);
break;
}
deleteCacheFile();
runOnUiThread(new Runnable() {
@Override
public void run() {
showSetWallpaperLoading(false);
Toast.makeText(WallPaperActivity.this, getString(R.string.set_success), Toast.LENGTH_SHORT).show();
}
});
} catch (Exception exception) {
runOnUiThread(new Runnable() {
@Override
public void run() {
showSetWallpaperLoading(false);
Toast.makeText(WallPaperActivity.this, getString(R.string.set_fail), Toast.LENGTH_SHORT).show();
}
});
}
}
private void deleteCacheFile() {
if (downloadFile != null && downloadFile.exists()) {
boolean delete = downloadFile.delete();
Log.d(FreeWallPaper.TAG, "--------delete=" + delete);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (call != null) {
call.cancel();
}
}
}

View File

@ -0,0 +1,10 @@
package com.wall.proshot.wallpapers.myconnector;
import com.wall.proshot.wallpapers.bean.Data;
public interface OnItemClick {
void onItemClickAction(Data info);
default void onClickMore(String name){}
}

View File

@ -0,0 +1,9 @@
package com.wall.proshot.wallpapers.myconnector;
import com.wall.proshot.wallpapers.bean.Data;
import java.util.List;
public interface OnLikeList {
void onLikeList(List<Data> dataList);
}

View File

@ -0,0 +1,6 @@
package com.wall.proshot.wallpapers.myconnector;
public interface OnSelectType {
void onSelectType(int type);
}

View File

@ -0,0 +1,8 @@
package com.wall.proshot.wallpapers.myconnector;
import com.wall.proshot.wallpapers.bean.Data;
public interface OnUpdateLike {
void onAdd(Data data);
void onRemove(Data data);
}

View File

@ -0,0 +1,88 @@
package com.wall.proshot.wallpapers.myfragment;
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.proshot.wallpapers.myconnector.OnSelectType;
import com.wall.proshot.wallpapers.databinding.DialogBinding;
public class Dialog extends DialogFragment {
private DialogBinding vb;
private OnSelectType listener;
public static final int type_home =0;
public static final int type_lock =1;
public static final int type_both =2;
public void setListener(OnSelectType listener) {
this.listener = listener;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
vb = DialogBinding.inflate(getLayoutInflater());
init();
return vb.getRoot();
}
@Override
public void onStart() {
super.onStart();
android.app.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,167 @@
package com.wall.proshot.wallpapers.myfragment;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.wall.proshot.wallpapers.FreeWallPaper;
import com.wall.proshot.wallpapers.bean.Data;
import com.wall.proshot.wallpapers.myacctivity.WallPaperActivity;
import com.wall.proshot.wallpapers.myconnector.OnItemClick;
import com.wall.proshot.wallpapers.myconnector.OnLikeList;
import com.wall.proshot.wallpapers.myitem.MyItemLike;
import com.wall.proshot.wallpapers.mytool.MyComUtils;
import com.wall.proshot.wallpapers.mytool.MyObectBoxManager;
import com.wall.proshot.wallpapers.R;
import com.wall.proshot.wallpapers.databinding.MyFragmentLikeBinding;
import java.util.ArrayList;
import java.util.List;
import io.objectbox.reactive.DataSubscription;
public class FragmentLike extends Fragment implements OnItemClick {
private MyFragmentLikeBinding vb;
private DataSubscription dataSubscription;
private MyItemLike myItemLike; // 收藏列表适配器
private List<Data> likedDataList = new ArrayList<>(); // 收藏数据缓存
// 单例创建方法
public static FragmentLike newInstance() {
return new FragmentLike();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 初始化数据缓存避免旋转屏幕数据丢失
if (savedInstanceState != null) {
likedDataList = (List<Data>) savedInstanceState.getSerializable("liked_data");
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
// 绑定布局正确传递 container attachToRoot 参数
vb = MyFragmentLikeBinding.inflate(inflater, container, false);
// 设置空状态提示文字
vb.tvTitle.setText(getString(R.string.no_like_data));
// 初始化两列网格列表
initRecyclerView();
// 注册收藏数据监听
registerLikeDataListener();
// 首次加载数据loadLikedData();
return vb.getRoot();
}
/**
* 初始化 RecyclerView两列网格布局
*/
private void initRecyclerView() {
// 1. 两列网格布局管理器核心配置
GridLayoutManager gridLayoutManager = new GridLayoutManager(requireContext(), 2);
// 防止 item 大小不一致导致列错位
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return 1; // 每个 item 1
}
});
// 2. 初始化适配器传入 item 高度适配两列
int itemHeight = MyComUtils.dp2Px(220);
myItemLike = new MyItemLike(requireContext(), itemHeight, true); // 第三个参数 true显示收藏图标
myItemLike.setInfoWallpaperListener(this); // 设置 item 点击监听
// 3. 自定义 item 间距左右 10dp上下 10dp两列均匀分布
int spacing = MyComUtils.dp2Px(10);
vb.listRecycler.addItemDecoration(new RecyclerView.ItemDecoration() {
@Override
public void getItemOffsets(@NonNull android.graphics.Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
int column = position % 2; // 0=左列1=右列
// 左右间距左列右边 5dp右列左边 5dp
outRect.left = column == 0 ? 0 : spacing / 2;
outRect.right = column == 0 ? spacing / 2 : 0;
// 上下间距第一行顶部 10dp其余行上下各 5dp
outRect.top = position < 2 ? spacing : spacing / 2;
outRect.bottom = spacing / 2;
}
});
// 4. 设置 RecyclerView 配置优化滚动性能
vb.listRecycler.setLayoutManager(gridLayoutManager);
vb.listRecycler.setAdapter(myItemLike);
vb.listRecycler.setHasFixedSize(true); // 固定 item 大小
vb.listRecycler.setItemViewCacheSize(20); // 增加缓存数量
vb.listRecycler.setNestedScrollingEnabled(false); // 禁用嵌套滚动提升流畅度
}
/**
* 注册收藏数据监听实时接收收藏状态变化
*/
private void registerLikeDataListener() {
// 取消之前的监听避免内存泄漏
if (dataSubscription != null && !dataSubscription.isCanceled()) {
dataSubscription.cancel();
}
// 注册新监听接收 ObectBoxManager 的数据更新通知
dataSubscription = MyObectBoxManager.setLikeDataListener(new OnLikeList() {
@Override
public void onLikeList(List<Data> dataList) {
Log.d(FreeWallPaper.TAG, "收藏数据更新size = " + (dataList != null ? dataList.size() : 0));
// 更新数据缓存
likedDataList.clear();
if (dataList != null && !dataList.isEmpty()) {
likedDataList.addAll(dataList);
}
// 刷新 UI必须在主线程
requireActivity().runOnUiThread(() -> updateUI());
}
});
}
private void updateUI() {
if (likedDataList.isEmpty()) {
// 空状态显示图标+提示文字
vb.layoutNoData.setVisibility(View.VISIBLE);
vb.listRecycler.setVisibility(View.GONE);
} else {
// 有数据显示两列网格列表
vb.layoutNoData.setVisibility(View.GONE);
vb.listRecycler.setVisibility(View.VISIBLE);
// 更新适配器数据
myItemLike.setDataInfo(likedDataList);
}
}
@Override
public void onItemClickAction(Data info) {
if (info == null) return;
Intent intent = new Intent(requireContext(), WallPaperActivity.class);
intent.putExtra(MyComUtils.key_info, info);
startActivity(intent);
}
public void scrollToTop() {
if (vb.listRecycler != null) {
vb.listRecycler.scrollToPosition(0);
}
}
}

View File

@ -0,0 +1,132 @@
package com.wall.proshot.wallpapers.myfragment;
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 androidx.recyclerview.widget.RecyclerView;
import com.wall.proshot.wallpapers.FreeWallPaper;
import com.wall.proshot.wallpapers.myacctivity.ListActivity;
import com.wall.proshot.wallpapers.myacctivity.WallPaperActivity;
import com.wall.proshot.wallpapers.myconnector.OnItemClick;
import com.wall.proshot.wallpapers.myitem.MyItemMain;
import com.wall.proshot.wallpapers.bean.Data;
import com.wall.proshot.wallpapers.mytool.MyComUtils;
import com.wall.proshot.wallpapers.databinding.MyFragmentMainBinding;
import java.util.ArrayList;
import java.util.List;
public class FragmentMain extends Fragment implements OnItemClick {
private MyFragmentMainBinding vb;
public FragmentMain() {
}
public static FragmentMain newInstance(int type) {
Bundle bundle = new Bundle();
bundle.putInt(MyComUtils.key_index, type);
FragmentMain fragment = new FragmentMain();
fragment.setArguments(bundle);
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// 修复布局绑定传入 container attachToRoot=false避免布局层级异常
vb = MyFragmentMainBinding.inflate(inflater, container, false);
initTabVp();
return vb.getRoot();
}
private void initTabVp() {
List<String> data = new ArrayList<>();
// 循环获取分类名称直到获取到数据避免空列表
while (data.isEmpty()) {
data = FreeWallPaper.getCategoryNames();
// 防止无限循环若获取失败最多循环3次
if (data.isEmpty() && FreeWallPaper.getCategoryNames() == null) {
break;
}
}
vb.loadingPb.setVisibility(View.GONE);
// 初始化两列分类列表
initList(data);
}
private void initList(List<String> data) {
// 1. 初始化分类适配器
MyItemMain adHomeParent = new MyItemMain();
adHomeParent.setData(data);
adHomeParent.setInfoWallpaperListener(this);
// 2. 核心两列网格布局管理器
GridLayoutManager gridLayoutManager = new GridLayoutManager(requireContext(), 2);
// 确保每个分类item占1列避免某些item占满两列
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return 1;
}
});
// 3. 自定义两列间距优化视觉效果与其他页面保持一致
int spacing = MyComUtils.dp2Px(10); // 10dp间距转px适配不同屏幕
vb.classRecycler.addItemDecoration(new RecyclerView.ItemDecoration() {
@Override
public void getItemOffsets(android.graphics.Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
int column = position % 2; // 0=左列1=右列
// 左右间距左列右边5dp右列左边5dp总间距10dp
outRect.left = column == 0 ? 0 : spacing / 2;
outRect.right = column == 0 ? spacing / 2 : 0;
// 上下间距第一行顶部10dp其余行上下各5dp
outRect.top = position < 2 ? spacing : spacing / 2;
outRect.bottom = spacing / 2;
}
});
// 4. 设置RecyclerView配置优化性能+两列布局
vb.classRecycler.setLayoutManager(gridLayoutManager);
vb.classRecycler.setAdapter(adHomeParent);
vb.classRecycler.setHasFixedSize(true); // 固定item大小提升滚动流畅度
vb.classRecycler.setItemViewCacheSize(20); // 增加缓存数量
vb.classRecycler.setNestedScrollingEnabled(false); // 禁用嵌套滚动避免卡顿
// 保留原有item装饰器若ItemHelper是间距装饰器可根据需求选择保留/替换
// 注意避免重复添加间距若ItemHelper已设置间距可注释上面的自定义ItemDecoration
// ItemHelper itemHelper = new ItemHelper(10, 10, 0);
// vb.classRecycler.addItemDecoration(itemHelper);
}
@Override
public void onItemClickAction(Data info) {
if (info == null) return; // 空数据容错
Intent intent = new Intent(requireContext(), WallPaperActivity.class);
intent.putExtra(MyComUtils.key_info, info);
startActivity(intent);
}
@Override
public void onClickMore(String name) {
if (name == null || name.isEmpty()) return; // 空名称容错
Intent intent = new Intent(requireContext(), ListActivity.class);
intent.putExtra(ListActivity.key_index, name);
startActivity(intent);
}
public void scrollToTop() {
if (vb.classRecycler != null) {
vb.classRecycler.scrollToPosition(0);
}
}
}

View File

@ -0,0 +1,140 @@
package com.wall.proshot.wallpapers.myitem;
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.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.proshot.wallpapers.FreeWallPaper;
import com.wall.proshot.wallpapers.bean.Data;
import com.wall.proshot.wallpapers.myconnector.OnItemClick;
import com.wall.proshot.wallpapers.mytool.MyComUtils;
import com.wall.proshot.wallpapers.mytool.MyObectBoxManager;
import com.wall.proshot.wallpapers.R;
import java.util.ArrayList;
import java.util.List;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
public class MyItemLike extends RecyclerView.Adapter<MyItemLike.LikeVh> {
private List<Data> dataInfo = new ArrayList<>();
private Context myContext;
private OnItemClick onItemClick;
public void setInfoWallpaperListener(OnItemClick onItemClick) {
this.onItemClick = onItemClick;
}
public MyItemLike(Context myCon, int itemHeight, boolean b) {
myContext = myCon;
}
public void setDataInfo(List<Data> dataInfo) {
this.dataInfo = dataInfo;
notifyDataSetChanged();
}
@NonNull
@Override
public LikeVh onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(myContext).inflate(R.layout.my_item_like, parent, false);
return new LikeVh(itemView);
}
@Override
public void onBindViewHolder(@NonNull LikeVh holder, int position) {
Data info = dataInfo.get(position);
ImageView imageView = holder.getImageView();
ImageView imFavorite = holder.getImFavorite();
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(MyComUtils.dp2Px(12), 0) // 圆角效果
);
Glide.with(myContext)
.load(previewUrl400)
.placeholder(R.mipmap.im_placeholder)
.transform(multiTransformation)
.into(imageView);
imFavorite.setSelected(true);
imFavorite.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
imFavorite.setSelected(false);
info.setLike(false);
MyObectBoxManager.updateLike(info);
int adapterPosition = holder.getAdapterPosition();
notifyItemRemoved(adapterPosition);
Log.d(FreeWallPaper.TAG, "----------notifyItemRemoved-adapterPosition=" + adapterPosition);
}
});
holder.getLayout().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onItemClick != null) {
onItemClick.onItemClickAction(info);
}
}
});
}
@Override
public int getItemCount() {
return dataInfo.size();
}
public class LikeVh extends RecyclerView.ViewHolder {
private ImageView imageView;
private RelativeLayout layout;
private ImageView imFavorite;
private View spaceView;
public LikeVh(@NonNull View itemView) {
super(itemView);
imageView = itemView.findViewById(R.id.wallpaper);
layout = itemView.findViewById(R.id.layout);
imFavorite = itemView.findViewById(R.id.image_favorite);
spaceView = itemView.findViewById(R.id.space_view);
}
public View getSpaceView() {
return spaceView;
}
public ImageView getImFavorite() {
return imFavorite;
}
public RelativeLayout getLayout() {
return layout;
}
public ImageView getImageView() {
return imageView;
}
}
}

View File

@ -0,0 +1,229 @@
package com.wall.proshot.wallpapers.myitem;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.DecodeFormat;
import com.bumptech.glide.load.MultiTransformation;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target;
import com.wall.proshot.wallpapers.bean.Data;
import com.wall.proshot.wallpapers.myconnector.OnItemClick;
import com.wall.proshot.wallpapers.mytool.MyComUtils;
import com.wall.proshot.wallpapers.R;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
public class MyItemList extends RecyclerView.Adapter<MyItemList.MyViewHolder> {
private List<Data> dataInfo = new ArrayList<>();
private OnItemClick onItemClick;
private WeakReference<Context> weakReference;
private int itemHeight;
private boolean showSpace = false;
public void setInfoWallpaperListener(OnItemClick onItemClick) {
this.onItemClick = onItemClick;
}
public MyItemList(Context myCon, int itemHeight, boolean show) {
weakReference = new WeakReference<>(myCon);
this.itemHeight = itemHeight;
showSpace = show;
}
public void setDataInfo(List<Data> 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.my_item_list, parent, false);
ImageView imageView = itemView.findViewById(R.id.wallpaper);
ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams();
layoutParams.height = itemHeight;
imageView.setLayoutParams(layoutParams);
return new MyViewHolder(itemView);
}
return null;
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
Data 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(MyComUtils.dp2Px(12), 0) // 圆角效果
);
RequestOptions options = new RequestOptions()
.format(DecodeFormat.PREFER_RGB_565);
Context context = weakReference.get();
if (context != null) {
Glide.with(context)
.asDrawable()
.skipMemoryCache(true)
.apply(options)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.load(previewUrl400)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<Drawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target<Drawable> target, @NonNull DataSource dataSource, boolean isFirstResource) {
return false;
}
})
.placeholder(R.mipmap.im_placeholder)
.transform(multiTransformation)
.into(imageView);
}
item.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onItemClick != null) {
onItemClick.onItemClickAction(info);
}
}
});
}
@Override
public int getItemCount() {
return dataInfo.size();
}
@Override
public void onViewRecycled(@NonNull MyViewHolder holder) {
super.onViewRecycled(holder);
}
private static DiffUtil.ItemCallback<Data> diff = new DiffUtil.ItemCallback<Data>() {
@Override
public boolean areItemsTheSame(@NonNull Data oldItem, @NonNull Data newItem) {
return oldItem.getImId().equals(newItem.getImId());
}
@Override
public boolean areContentsTheSame(@NonNull Data oldItem, @NonNull Data newItem) {
return oldItem.getImId().equals(newItem.getImId());
}
};
private static class MyCallback extends DiffUtil.Callback {
private List<Data> mOldList;
private List<Data> mNewList;
public MyCallback(List<Data> oldList, List<Data> 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,140 @@
package com.wall.proshot.wallpapers.myitem;
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.proshot.wallpapers.FreeWallPaper;
import com.wall.proshot.wallpapers.myconnector.OnItemClick;
import com.wall.proshot.wallpapers.bean.Data;
import com.wall.proshot.wallpapers.mytool.MyComUtils;
import com.wall.proshot.wallpapers.mytool.MyObectBoxManager;
import com.wall.proshot.wallpapers.R;
import com.wall.proshot.wallpapers.databinding.MyItemMainBinding;
import java.util.ArrayList;
import java.util.List;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
public class MyItemMain extends RecyclerView.Adapter<MyItemMain.HomeParentHolder> {
private List<String> data = new ArrayList<>();
private Context mContext;
private OnItemClick listener;
private MultiTransformation<Bitmap> multiTransformation = new MultiTransformation<>(
new CenterCrop(),
new RoundedCornersTransformation(MyComUtils.dp2Px(12), 0)
);
// 修复1设置数据时避免null
public void setData(List<String> data) {
this.data = data != null ? data : new ArrayList<>();
notifyDataSetChanged();
}
public void setInfoWallpaperListener(OnItemClick onItemClick) {
this.listener = onItemClick;
}
@NonNull
@Override
public HomeParentHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
mContext = parent.getContext();
MyItemMainBinding inflate = MyItemMainBinding.inflate(LayoutInflater.from(mContext), parent, false);
return new HomeParentHolder(inflate);
}
@Override
public void onBindViewHolder(@NonNull HomeParentHolder holder, int position) {
// 修复2position合法性校验
if (position < 0 || position >= data.size()) {
holder.itemBing.tvClassName.setText("");
holder.itemBing.preview.setImageResource(R.mipmap.im_placeholder);
return;
}
String name = data.get(position);
List<Data> data1 = MyObectBoxManager.queryHome(name);
// 修复3data1空判断核心避免get(0)越界
if (data1 == null || data1.isEmpty()) {
holder.itemBing.tvClassName.setText(name);
holder.itemBing.preview.setImageResource(R.mipmap.im_placeholder);
return;
}
// 到这里data1一定非空可安全调用get(0)
Data firstData = data1.get(0);
String previewUrl = firstData.getPreviewUrl1080();
// 降级备用地址
if (previewUrl == null || previewUrl.isEmpty()) {
previewUrl = firstData.getPreviewUrl400();
}
// 设置分类名称
holder.itemBing.tvClassName.setText(name);
// 设置底部间距
holder.itemBing.spaceView.setVisibility(position == data.size() - 1 ? View.VISIBLE : View.GONE);
// 加载图片
Glide.with(mContext)
.asDrawable()
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.load(previewUrl != null ? previewUrl : R.mipmap.im_placeholder)
.listener(new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, @Nullable Object model, @NonNull Target<Drawable> target, boolean isFirstResource) {
Log.e(FreeWallPaper.TAG, "图片加载失败:" + (e != null ? e.getMessage() : "未知错误"));
holder.itemBing.preview.setImageResource(R.mipmap.im_placeholder);
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);
// 点击事件修复4listener空判断
holder.itemBing.preview.setOnClickListener(v -> {
if (listener != null) {
listener.onClickMore(name);
}
});
}
// 修复5返回实际数据大小
@Override
public int getItemCount() {
return data == null ? 0 : data.size();
}
static class HomeParentHolder extends RecyclerView.ViewHolder {
private MyItemMainBinding itemBing;
public HomeParentHolder(@NonNull MyItemMainBinding itemView) {
super(itemView.getRoot());
itemBing = itemView;
}
}
}

View File

@ -0,0 +1,228 @@
package com.wall.proshot.wallpapers.mytool
import android.Manifest
import android.app.Activity
import android.content.ContentValues
import android.content.Context
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import android.util.Log
import androidx.core.app.ActivityCompat
import com.wall.proshot.wallpapers.FreeWallPaper
import com.wall.proshot.wallpapers.bean.Data
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.json.JSONArray
import org.json.JSONObject
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
object JsonData {
fun getData(jsonStr: String, category: String): MutableList<Data> {
val jsonArray = JSONArray(jsonStr)
var data = mutableListOf<Data>()
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: Data
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 = Data().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(FreeWallPaper.TAG, "-----------------e=${e.printStackTrace()}")
return null
}
} ?: run {
Log.d(FreeWallPaper.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,144 @@
package com.wall.proshot.wallpapers.mytool;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Debug;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import com.wall.proshot.wallpapers.FreeWallPaper;
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 MyComUtils {
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 = FreeWallPaper.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.proshot.wallpapers.mytool;
import android.graphics.Rect;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class MyItemHelper 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 MyItemHelper(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,159 @@
package com.wall.proshot.wallpapers.mytool;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import com.wall.proshot.wallpapers.FreeWallPaper;
import com.wall.proshot.wallpapers.bean.Data;
import com.wall.proshot.wallpapers.myconnector.OnLikeList;
import com.wall.proshot.wallpapers.myconnector.OnUpdateLike;
import com.wall.proshot.wallpapers.bean.Data_;
import com.wall.proshot.wallpapers.bean.MyObjectBox;
import java.util.ArrayList;
import java.util.List;
import io.objectbox.Box;
import io.objectbox.BoxStore;
import io.objectbox.android.AndroidScheduler;
import io.objectbox.query.Query;
import io.objectbox.query.QueryBuilder;
import io.objectbox.reactive.DataObserver;
import io.objectbox.reactive.DataSubscription;
import io.objectbox.reactive.DataSubscriptionList;
public class MyObectBoxManager {
private static BoxStore boxStore;
private static Box<Data> LikeBox;
private static List<OnUpdateLike> list = new ArrayList<>();
public static void init(Context context) {
boxStore = MyObjectBox.builder().androidContext(context).build();
}
public static Box<Data> getObjectBoxLike() {
if (LikeBox == null) {
LikeBox = boxStore.boxFor(Data.class);
}
return LikeBox;
}
public static void addData(Data data) {
Box<Data> objectBoxLike = getObjectBoxLike();
String imId = data.getImId();
Data first = objectBoxLike.query()
.equal(Data_.imId, imId, QueryBuilder.StringOrder.CASE_SENSITIVE)
.build()
.findFirst();
if (first == null) {
Log.d(FreeWallPaper.TAG, "-----------addData " + imId);
objectBoxLike.put(data);
}else {
Log.d(FreeWallPaper.TAG, "-----------忽略添加 ");
}
}
public static DataSubscription setLikeDataListener(OnLikeList listener) {
Query<Data> build = getObjectBoxLike().query()
.equal(Data_.isLike, true)
.build();
return build.subscribe(new DataSubscriptionList())
.on(AndroidScheduler.mainThread())
.observer(new DataObserver<List<Data>>() {
@Override
public void onData(@NonNull List<Data> data) {
Log.d(FreeWallPaper.TAG, "------data=" + data.size());
listener.onLikeList(data);
}
});
}
public static void updateLike(Data boxLike) {
Box<Data> objectBoxLike = getObjectBoxLike();
String imId = boxLike.getImId();
objectBoxLike.put(boxLike);
for (OnUpdateLike listener : list) {
listener.onAdd(boxLike);
}
}
public static void insertOrUpdateDownload(Data boxLike) {
Box<Data> objectBoxLike = getObjectBoxLike();
String imId = boxLike.getImId();
Data first = objectBoxLike.query()
.equal(Data_.imId, imId, QueryBuilder.StringOrder.CASE_SENSITIVE)
.build()
.findFirst();
if (first == null) {
Log.d(FreeWallPaper.TAG, "-----------添加11 Download=" + imId);
boxLike.setDownload(true);
objectBoxLike.put(boxLike);
} else {
first.setDownload(true);
objectBoxLike.put(first);
Log.d(FreeWallPaper.TAG, "-----------已经存在添加22 Download=" + imId);
}
}
public static List<Data> search(String name) {
Box<Data> objectBoxLike = getObjectBoxLike();
List<Data> data = objectBoxLike.query()
.contains(Data_.description, name, QueryBuilder.StringOrder.CASE_SENSITIVE)
.build()
.find();
return data;
}
public static List<Data> queryHome(String name) {
Box<Data> objectBoxLike = getObjectBoxLike();
List<Data> data = objectBoxLike.query()
.equal(Data_.categoryName, name, QueryBuilder.StringOrder.CASE_SENSITIVE)
.build()
.find(10, 1); // 修复offset=0从第一条数据开始
Log.d(FreeWallPaper.TAG, "查询分类[" + name + "]结果:" + data.size() + "");
return data;
}
public static List<Data> queryCategoryAll(String name) {
Box<Data> objectBoxLike = getObjectBoxLike();
List<Data> data = objectBoxLike.query()
.equal(Data_.categoryName, name, QueryBuilder.StringOrder.CASE_SENSITIVE)
.build()
.find(0, 200);
return data;
}
public static boolean queryIsLike(String imId) {
Box<Data> objectBoxLike = getObjectBoxLike();
Data first = objectBoxLike.query()
.equal(Data_.imId, imId, QueryBuilder.StringOrder.CASE_SENSITIVE)
.build()
.findFirst();
if (first != null && first.isLike()) {
return true;
} else {
return false;
}
}
}

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:startColor="#ffffff"
android:endColor="#30ffc103"
android:centerX="0.5"
android:centerY="0.5"
android:angle="270" />
</shape>

View File

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

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF" />
<corners android:radius="30dp" />
<stroke
android:width="2dp"
android:color="#FFFFFF"
>
</stroke>
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" />
</shape>

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

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,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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

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

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

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

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 第1层外层光晕圆形、白色柔和发光 -->
<item
android:width="100dp"
android:height="100dp"
android:gravity="center">
<shape android:shape="oval">
<gradient
android:type="radial"
android:gradientRadius="50dp"
android:startColor="#80FFC103"
android:endColor="#00FFC103"
android:centerX="0.5"
android:centerY="0.5"/>
</shape>
</item>
<item
android:width="80dp"
android:height="80dp"
android:gravity="center">
<bitmap
android:src="@drawable/mapleleave"
android:gravity="fill"
android:tint="#99FFC103"
android:filter="true"/>
</item>
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

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

View File

@ -0,0 +1,6 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#87CEEB"/>
<size android:height="5dp" android:width="5dp"/>
</shape>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#30FFC107" />
<corners android:radius="10dp" />
<stroke
android:width="2dp"
android:color="#30FFC107" >
</stroke>
</shape>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 纯色铺满背景层 -->
<item>
<shape android:shape="rectangle">
<solid android:color="#40FFC103" /> <!-- 自定义背景色 -->
</shape>
</item>
<!-- 眼睛图案铺满层 -->
<item>
<bitmap
android:src="@drawable/eye"
android:gravity="fill"
android:tint="@android:color/black"
android:filter="true"/>
</item>
</layer-list>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 纯色铺满背景层 -->
<item>
<shape android:shape="rectangle">
<solid android:color="#40FFC103" />
</shape>
</item>
<!-- 眼睛图案铺满层 -->
<item>
<bitmap
android:src="@drawable/star"
android:gravity="fill"
android:tint="@android:color/black"
android:filter="true"/>
</item>
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

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