commit d0f5fb716ab06a6b74f2b3256a4d1e9808c4c1f2 Author: tongchao Date: Wed May 28 10:07:57 2025 +0800 first commit diff --git a/.gradle/6.7.1/executionHistory/executionHistory.bin b/.gradle/6.7.1/executionHistory/executionHistory.bin new file mode 100644 index 0000000..0b21c4c Binary files /dev/null and b/.gradle/6.7.1/executionHistory/executionHistory.bin differ diff --git a/.gradle/6.7.1/executionHistory/executionHistory.lock b/.gradle/6.7.1/executionHistory/executionHistory.lock new file mode 100644 index 0000000..d5f19d4 Binary files /dev/null and b/.gradle/6.7.1/executionHistory/executionHistory.lock differ diff --git a/.gradle/6.7.1/fileChanges/last-build.bin b/.gradle/6.7.1/fileChanges/last-build.bin new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/.gradle/6.7.1/fileChanges/last-build.bin differ diff --git a/.gradle/6.7.1/fileHashes/fileHashes.bin b/.gradle/6.7.1/fileHashes/fileHashes.bin new file mode 100644 index 0000000..040e0f4 Binary files /dev/null and b/.gradle/6.7.1/fileHashes/fileHashes.bin differ diff --git a/.gradle/6.7.1/fileHashes/fileHashes.lock b/.gradle/6.7.1/fileHashes/fileHashes.lock new file mode 100644 index 0000000..f38af9c Binary files /dev/null and b/.gradle/6.7.1/fileHashes/fileHashes.lock differ diff --git a/.gradle/6.7.1/fileHashes/resourceHashesCache.bin b/.gradle/6.7.1/fileHashes/resourceHashesCache.bin new file mode 100644 index 0000000..3be765b Binary files /dev/null and b/.gradle/6.7.1/fileHashes/resourceHashesCache.bin differ diff --git a/.gradle/6.7.1/gc.properties b/.gradle/6.7.1/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/6.7.1/javaCompile/classAnalysis.bin b/.gradle/6.7.1/javaCompile/classAnalysis.bin new file mode 100644 index 0000000..c5d528e Binary files /dev/null and b/.gradle/6.7.1/javaCompile/classAnalysis.bin differ diff --git a/.gradle/6.7.1/javaCompile/jarAnalysis.bin b/.gradle/6.7.1/javaCompile/jarAnalysis.bin new file mode 100644 index 0000000..82ceb31 Binary files /dev/null and b/.gradle/6.7.1/javaCompile/jarAnalysis.bin differ diff --git a/.gradle/6.7.1/javaCompile/javaCompile.lock b/.gradle/6.7.1/javaCompile/javaCompile.lock new file mode 100644 index 0000000..0e99267 Binary files /dev/null and b/.gradle/6.7.1/javaCompile/javaCompile.lock differ diff --git a/.gradle/6.7.1/javaCompile/taskHistory.bin b/.gradle/6.7.1/javaCompile/taskHistory.bin new file mode 100644 index 0000000..485061f Binary files /dev/null and b/.gradle/6.7.1/javaCompile/taskHistory.bin differ diff --git a/.gradle/7.3.3/checksums/checksums.lock b/.gradle/7.3.3/checksums/checksums.lock new file mode 100644 index 0000000..f8fccb3 Binary files /dev/null and b/.gradle/7.3.3/checksums/checksums.lock differ diff --git a/.gradle/7.3.3/checksums/md5-checksums.bin b/.gradle/7.3.3/checksums/md5-checksums.bin new file mode 100644 index 0000000..f9ab64e Binary files /dev/null and b/.gradle/7.3.3/checksums/md5-checksums.bin differ diff --git a/.gradle/7.3.3/checksums/sha1-checksums.bin b/.gradle/7.3.3/checksums/sha1-checksums.bin new file mode 100644 index 0000000..ca4e394 Binary files /dev/null and b/.gradle/7.3.3/checksums/sha1-checksums.bin differ diff --git a/.gradle/7.3.3/dependencies-accessors/dependencies-accessors.lock b/.gradle/7.3.3/dependencies-accessors/dependencies-accessors.lock new file mode 100644 index 0000000..914498e Binary files /dev/null and b/.gradle/7.3.3/dependencies-accessors/dependencies-accessors.lock differ diff --git a/.gradle/7.3.3/dependencies-accessors/gc.properties b/.gradle/7.3.3/dependencies-accessors/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/7.3.3/executionHistory/executionHistory.bin b/.gradle/7.3.3/executionHistory/executionHistory.bin new file mode 100644 index 0000000..88088b5 Binary files /dev/null and b/.gradle/7.3.3/executionHistory/executionHistory.bin differ diff --git a/.gradle/7.3.3/executionHistory/executionHistory.lock b/.gradle/7.3.3/executionHistory/executionHistory.lock new file mode 100644 index 0000000..a5a398a Binary files /dev/null and b/.gradle/7.3.3/executionHistory/executionHistory.lock differ diff --git a/.gradle/7.3.3/fileChanges/last-build.bin b/.gradle/7.3.3/fileChanges/last-build.bin new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/.gradle/7.3.3/fileChanges/last-build.bin differ diff --git a/.gradle/7.3.3/fileHashes/fileHashes.bin b/.gradle/7.3.3/fileHashes/fileHashes.bin new file mode 100644 index 0000000..5646ec2 Binary files /dev/null and b/.gradle/7.3.3/fileHashes/fileHashes.bin differ diff --git a/.gradle/7.3.3/fileHashes/fileHashes.lock b/.gradle/7.3.3/fileHashes/fileHashes.lock new file mode 100644 index 0000000..f6bd9bc Binary files /dev/null and b/.gradle/7.3.3/fileHashes/fileHashes.lock differ diff --git a/.gradle/7.3.3/fileHashes/resourceHashesCache.bin b/.gradle/7.3.3/fileHashes/resourceHashesCache.bin new file mode 100644 index 0000000..b1d137e Binary files /dev/null and b/.gradle/7.3.3/fileHashes/resourceHashesCache.bin differ diff --git a/.gradle/7.3.3/gc.properties b/.gradle/7.3.3/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000..4a57957 Binary files /dev/null and b/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000..222963c --- /dev/null +++ b/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Tue May 20 10:45:30 CST 2025 +gradle.version=7.3.3 diff --git a/.gradle/buildOutputCleanup/outputFiles.bin b/.gradle/buildOutputCleanup/outputFiles.bin new file mode 100644 index 0000000..3990b99 Binary files /dev/null and b/.gradle/buildOutputCleanup/outputFiles.bin differ diff --git a/.gradle/checksums/checksums.lock b/.gradle/checksums/checksums.lock new file mode 100644 index 0000000..51c8b3b Binary files /dev/null and b/.gradle/checksums/checksums.lock differ diff --git a/.gradle/checksums/md5-checksums.bin b/.gradle/checksums/md5-checksums.bin new file mode 100644 index 0000000..1c60440 Binary files /dev/null and b/.gradle/checksums/md5-checksums.bin differ diff --git a/.gradle/checksums/sha1-checksums.bin b/.gradle/checksums/sha1-checksums.bin new file mode 100644 index 0000000..48d0996 Binary files /dev/null and b/.gradle/checksums/sha1-checksums.bin differ diff --git a/.gradle/configuration-cache/gc.properties b/.gradle/configuration-cache/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/file-system.probe b/.gradle/file-system.probe new file mode 100644 index 0000000..650902a Binary files /dev/null and b/.gradle/file-system.probe differ diff --git a/.gradle/vcs-1/gc.properties b/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/assetWizardSettings.xml b/.idea/assetWizardSettings.xml new file mode 100644 index 0000000..fcf75f4 --- /dev/null +++ b/.idea/assetWizardSettings.xml @@ -0,0 +1,32 @@ + + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..f861765 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..1f254f1 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..b268ef3 --- /dev/null +++ b/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..97626ba --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..1fa2bc5 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,22 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..b0adc45 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml new file mode 100644 index 0000000..7e340a7 --- /dev/null +++ b/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__C__Users_nopsp_work_android_sdk_build_tools_30_0_3_renderscript_lib_androidx_rs_jar.xml b/.idea/libraries/Gradle__C__Users_nopsp_work_android_sdk_build_tools_30_0_3_renderscript_lib_androidx_rs_jar.xml new file mode 100644 index 0000000..a15b289 --- /dev/null +++ b/.idea/libraries/Gradle__C__Users_nopsp_work_android_sdk_build_tools_30_0_3_renderscript_lib_androidx_rs_jar.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_activity_activity_1_2_4_aar.xml b/.idea/libraries/Gradle__androidx_activity_activity_1_2_4_aar.xml new file mode 100644 index 0000000..f40617a --- /dev/null +++ b/.idea/libraries/Gradle__androidx_activity_activity_1_2_4_aar.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_annotation_annotation_1_3_0.xml b/.idea/libraries/Gradle__androidx_annotation_annotation_1_3_0.xml new file mode 100644 index 0000000..4cfd514 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_annotation_annotation_1_3_0.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_annotation_annotation_experimental_1_1_0_aar.xml b/.idea/libraries/Gradle__androidx_annotation_annotation_experimental_1_1_0_aar.xml new file mode 100644 index 0000000..d41be02 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_annotation_annotation_experimental_1_1_0_aar.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_appcompat_appcompat_1_4_1_aar.xml b/.idea/libraries/Gradle__androidx_appcompat_appcompat_1_4_1_aar.xml new file mode 100644 index 0000000..2521050 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_appcompat_appcompat_1_4_1_aar.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_appcompat_appcompat_resources_1_4_1_aar.xml b/.idea/libraries/Gradle__androidx_appcompat_appcompat_resources_1_4_1_aar.xml new file mode 100644 index 0000000..10fdc02 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_appcompat_appcompat_resources_1_4_1_aar.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_arch_core_core_common_2_1_0.xml b/.idea/libraries/Gradle__androidx_arch_core_core_common_2_1_0.xml new file mode 100644 index 0000000..ce7fa42 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_arch_core_core_common_2_1_0.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_arch_core_core_runtime_2_0_0_aar.xml b/.idea/libraries/Gradle__androidx_arch_core_core_runtime_2_0_0_aar.xml new file mode 100644 index 0000000..73651ba --- /dev/null +++ b/.idea/libraries/Gradle__androidx_arch_core_core_runtime_2_0_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_arch_core_core_runtime_2_1_0_aar.xml b/.idea/libraries/Gradle__androidx_arch_core_core_runtime_2_1_0_aar.xml new file mode 100644 index 0000000..8ca4890 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_arch_core_core_runtime_2_1_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_asynclayoutinflater_asynclayoutinflater_1_0_0_aar.xml b/.idea/libraries/Gradle__androidx_asynclayoutinflater_asynclayoutinflater_1_0_0_aar.xml new file mode 100644 index 0000000..4dae3cc --- /dev/null +++ b/.idea/libraries/Gradle__androidx_asynclayoutinflater_asynclayoutinflater_1_0_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_cardview_cardview_1_0_0_aar.xml b/.idea/libraries/Gradle__androidx_cardview_cardview_1_0_0_aar.xml new file mode 100644 index 0000000..9a1c5b0 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_cardview_cardview_1_0_0_aar.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_collection_collection_1_1_0.xml b/.idea/libraries/Gradle__androidx_collection_collection_1_1_0.xml new file mode 100644 index 0000000..6b589c5 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_collection_collection_1_1_0.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_constraintlayout_constraintlayout_2_0_4_aar.xml b/.idea/libraries/Gradle__androidx_constraintlayout_constraintlayout_2_0_4_aar.xml new file mode 100644 index 0000000..03a2fb7 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_constraintlayout_constraintlayout_2_0_4_aar.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_constraintlayout_constraintlayout_2_1_3_aar.xml b/.idea/libraries/Gradle__androidx_constraintlayout_constraintlayout_2_1_3_aar.xml new file mode 100644 index 0000000..fd4bf23 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_constraintlayout_constraintlayout_2_1_3_aar.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_constraintlayout_constraintlayout_solver_2_0_4.xml b/.idea/libraries/Gradle__androidx_constraintlayout_constraintlayout_solver_2_0_4.xml new file mode 100644 index 0000000..cba1dae --- /dev/null +++ b/.idea/libraries/Gradle__androidx_constraintlayout_constraintlayout_solver_2_0_4.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_coordinatorlayout_coordinatorlayout_1_1_0_aar.xml b/.idea/libraries/Gradle__androidx_coordinatorlayout_coordinatorlayout_1_1_0_aar.xml new file mode 100644 index 0000000..682b57e --- /dev/null +++ b/.idea/libraries/Gradle__androidx_coordinatorlayout_coordinatorlayout_1_1_0_aar.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_core_core_1_7_0_aar.xml b/.idea/libraries/Gradle__androidx_core_core_1_7_0_aar.xml new file mode 100644 index 0000000..19aa7cd --- /dev/null +++ b/.idea/libraries/Gradle__androidx_core_core_1_7_0_aar.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_cursoradapter_cursoradapter_1_0_0_aar.xml b/.idea/libraries/Gradle__androidx_cursoradapter_cursoradapter_1_0_0_aar.xml new file mode 100644 index 0000000..73bac0a --- /dev/null +++ b/.idea/libraries/Gradle__androidx_cursoradapter_cursoradapter_1_0_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_customview_customview_1_0_0_aar.xml b/.idea/libraries/Gradle__androidx_customview_customview_1_0_0_aar.xml new file mode 100644 index 0000000..1d5f865 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_customview_customview_1_0_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_customview_customview_1_1_0_aar.xml b/.idea/libraries/Gradle__androidx_customview_customview_1_1_0_aar.xml new file mode 100644 index 0000000..c0b8087 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_customview_customview_1_1_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_databinding_viewbinding_7_1_0_aar.xml b/.idea/libraries/Gradle__androidx_databinding_viewbinding_7_1_0_aar.xml new file mode 100644 index 0000000..1f8e13f --- /dev/null +++ b/.idea/libraries/Gradle__androidx_databinding_viewbinding_7_1_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_documentfile_documentfile_1_0_0_aar.xml b/.idea/libraries/Gradle__androidx_documentfile_documentfile_1_0_0_aar.xml new file mode 100644 index 0000000..c0258cd --- /dev/null +++ b/.idea/libraries/Gradle__androidx_documentfile_documentfile_1_0_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_drawerlayout_drawerlayout_1_0_0_aar.xml b/.idea/libraries/Gradle__androidx_drawerlayout_drawerlayout_1_0_0_aar.xml new file mode 100644 index 0000000..7c1a05a --- /dev/null +++ b/.idea/libraries/Gradle__androidx_drawerlayout_drawerlayout_1_0_0_aar.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_drawerlayout_drawerlayout_1_1_1_aar.xml b/.idea/libraries/Gradle__androidx_drawerlayout_drawerlayout_1_1_1_aar.xml new file mode 100644 index 0000000..4afd6e1 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_drawerlayout_drawerlayout_1_1_1_aar.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_dynamicanimation_dynamicanimation_1_0_0_aar.xml b/.idea/libraries/Gradle__androidx_dynamicanimation_dynamicanimation_1_0_0_aar.xml new file mode 100644 index 0000000..0436bd5 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_dynamicanimation_dynamicanimation_1_0_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_exifinterface_exifinterface_1_2_0_aar.xml b/.idea/libraries/Gradle__androidx_exifinterface_exifinterface_1_2_0_aar.xml new file mode 100644 index 0000000..b1878d9 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_exifinterface_exifinterface_1_2_0_aar.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_fragment_fragment_1_3_6_aar.xml b/.idea/libraries/Gradle__androidx_fragment_fragment_1_3_6_aar.xml new file mode 100644 index 0000000..e4f4021 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_fragment_fragment_1_3_6_aar.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_interpolator_interpolator_1_0_0_aar.xml b/.idea/libraries/Gradle__androidx_interpolator_interpolator_1_0_0_aar.xml new file mode 100644 index 0000000..87643dd --- /dev/null +++ b/.idea/libraries/Gradle__androidx_interpolator_interpolator_1_0_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_legacy_legacy_support_core_ui_1_0_0_aar.xml b/.idea/libraries/Gradle__androidx_legacy_legacy_support_core_ui_1_0_0_aar.xml new file mode 100644 index 0000000..f599b45 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_legacy_legacy_support_core_ui_1_0_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_legacy_legacy_support_core_utils_1_0_0_aar.xml b/.idea/libraries/Gradle__androidx_legacy_legacy_support_core_utils_1_0_0_aar.xml new file mode 100644 index 0000000..c8d7d2a --- /dev/null +++ b/.idea/libraries/Gradle__androidx_legacy_legacy_support_core_utils_1_0_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_legacy_legacy_support_v4_1_0_0_aar.xml b/.idea/libraries/Gradle__androidx_legacy_legacy_support_v4_1_0_0_aar.xml new file mode 100644 index 0000000..ec46d14 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_legacy_legacy_support_v4_1_0_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_common_2_3_1.xml b/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_common_2_3_1.xml new file mode 100644 index 0000000..c0972be --- /dev/null +++ b/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_common_2_3_1.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_common_2_4_0.xml b/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_common_2_4_0.xml new file mode 100644 index 0000000..40ef930 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_common_2_4_0.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_livedata_2_0_0_aar.xml b/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_livedata_2_0_0_aar.xml new file mode 100644 index 0000000..622bf65 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_livedata_2_0_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_livedata_core_2_3_1_aar.xml b/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_livedata_core_2_3_1_aar.xml new file mode 100644 index 0000000..a6f41b1 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_livedata_core_2_3_1_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_runtime_2_3_1_aar.xml b/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_runtime_2_3_1_aar.xml new file mode 100644 index 0000000..182fae9 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_runtime_2_3_1_aar.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_runtime_2_4_0_aar.xml b/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_runtime_2_4_0_aar.xml new file mode 100644 index 0000000..7b851ea --- /dev/null +++ b/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_runtime_2_4_0_aar.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_viewmodel_2_3_1_aar.xml b/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_viewmodel_2_3_1_aar.xml new file mode 100644 index 0000000..bd0c23b --- /dev/null +++ b/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_viewmodel_2_3_1_aar.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_viewmodel_savedstate_2_3_1_aar.xml b/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_viewmodel_savedstate_2_3_1_aar.xml new file mode 100644 index 0000000..adf90ba --- /dev/null +++ b/.idea/libraries/Gradle__androidx_lifecycle_lifecycle_viewmodel_savedstate_2_3_1_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_loader_loader_1_0_0_aar.xml b/.idea/libraries/Gradle__androidx_loader_loader_1_0_0_aar.xml new file mode 100644 index 0000000..23d1636 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_loader_loader_1_0_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_localbroadcastmanager_localbroadcastmanager_1_0_0_aar.xml b/.idea/libraries/Gradle__androidx_localbroadcastmanager_localbroadcastmanager_1_0_0_aar.xml new file mode 100644 index 0000000..3d78477 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_localbroadcastmanager_localbroadcastmanager_1_0_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_media_media_1_0_0_aar.xml b/.idea/libraries/Gradle__androidx_media_media_1_0_0_aar.xml new file mode 100644 index 0000000..d234d3a --- /dev/null +++ b/.idea/libraries/Gradle__androidx_media_media_1_0_0_aar.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_print_print_1_0_0_aar.xml b/.idea/libraries/Gradle__androidx_print_print_1_0_0_aar.xml new file mode 100644 index 0000000..10adb6e --- /dev/null +++ b/.idea/libraries/Gradle__androidx_print_print_1_0_0_aar.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_recyclerview_recyclerview_1_2_1_aar.xml b/.idea/libraries/Gradle__androidx_recyclerview_recyclerview_1_2_1_aar.xml new file mode 100644 index 0000000..1cdc440 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_recyclerview_recyclerview_1_2_1_aar.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_savedstate_savedstate_1_1_0_aar.xml b/.idea/libraries/Gradle__androidx_savedstate_savedstate_1_1_0_aar.xml new file mode 100644 index 0000000..dc259fd --- /dev/null +++ b/.idea/libraries/Gradle__androidx_savedstate_savedstate_1_1_0_aar.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_slidingpanelayout_slidingpanelayout_1_0_0_aar.xml b/.idea/libraries/Gradle__androidx_slidingpanelayout_slidingpanelayout_1_0_0_aar.xml new file mode 100644 index 0000000..93acc56 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_slidingpanelayout_slidingpanelayout_1_0_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_swiperefreshlayout_swiperefreshlayout_1_0_0_aar.xml b/.idea/libraries/Gradle__androidx_swiperefreshlayout_swiperefreshlayout_1_0_0_aar.xml new file mode 100644 index 0000000..567030c --- /dev/null +++ b/.idea/libraries/Gradle__androidx_swiperefreshlayout_swiperefreshlayout_1_0_0_aar.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_transition_transition_1_2_0_aar.xml b/.idea/libraries/Gradle__androidx_transition_transition_1_2_0_aar.xml new file mode 100644 index 0000000..d9ff967 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_transition_transition_1_2_0_aar.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_vectordrawable_vectordrawable_1_1_0_aar.xml b/.idea/libraries/Gradle__androidx_vectordrawable_vectordrawable_1_1_0_aar.xml new file mode 100644 index 0000000..6d8a8c0 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_vectordrawable_vectordrawable_1_1_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_vectordrawable_vectordrawable_animated_1_1_0_aar.xml b/.idea/libraries/Gradle__androidx_vectordrawable_vectordrawable_animated_1_1_0_aar.xml new file mode 100644 index 0000000..cb39044 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_vectordrawable_vectordrawable_animated_1_1_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_versionedparcelable_versionedparcelable_1_1_1_aar.xml b/.idea/libraries/Gradle__androidx_versionedparcelable_versionedparcelable_1_1_1_aar.xml new file mode 100644 index 0000000..f07a972 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_versionedparcelable_versionedparcelable_1_1_1_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_viewpager2_viewpager2_1_0_0_aar.xml b/.idea/libraries/Gradle__androidx_viewpager2_viewpager2_1_0_0_aar.xml new file mode 100644 index 0000000..9d8b9ba --- /dev/null +++ b/.idea/libraries/Gradle__androidx_viewpager2_viewpager2_1_0_0_aar.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__androidx_viewpager_viewpager_1_0_0_aar.xml b/.idea/libraries/Gradle__androidx_viewpager_viewpager_1_0_0_aar.xml new file mode 100644 index 0000000..5977f70 --- /dev/null +++ b/.idea/libraries/Gradle__androidx_viewpager_viewpager_1_0_0_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_amap_api_3dmap_10_0_600.xml b/.idea/libraries/Gradle__com_amap_api_3dmap_10_0_600.xml new file mode 100644 index 0000000..bcaacf8 --- /dev/null +++ b/.idea/libraries/Gradle__com_amap_api_3dmap_10_0_600.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_contrarywind_Android_PickerView_4_1_9_aar.xml b/.idea/libraries/Gradle__com_contrarywind_Android_PickerView_4_1_9_aar.xml new file mode 100644 index 0000000..bd9bc92 --- /dev/null +++ b/.idea/libraries/Gradle__com_contrarywind_Android_PickerView_4_1_9_aar.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_contrarywind_wheelview_4_1_0_aar.xml b/.idea/libraries/Gradle__com_contrarywind_wheelview_4_1_0_aar.xml new file mode 100644 index 0000000..d968369 --- /dev/null +++ b/.idea/libraries/Gradle__com_contrarywind_wheelview_4_1_0_aar.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_facebook_conceal_conceal_1_1_3_aar.xml b/.idea/libraries/Gradle__com_facebook_conceal_conceal_1_1_3_aar.xml new file mode 100644 index 0000000..05949fe --- /dev/null +++ b/.idea/libraries/Gradle__com_facebook_conceal_conceal_1_1_3_aar.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_flyco_tablayout_FlycoTabLayout_Lib_2_1_2_aar.xml b/.idea/libraries/Gradle__com_flyco_tablayout_FlycoTabLayout_Lib_2_1_2_aar.xml new file mode 100644 index 0000000..4f787d1 --- /dev/null +++ b/.idea/libraries/Gradle__com_flyco_tablayout_FlycoTabLayout_Lib_2_1_2_aar.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_github_CymChad_BaseRecyclerViewAdapterHelper_2_9_50_aar.xml b/.idea/libraries/Gradle__com_github_CymChad_BaseRecyclerViewAdapterHelper_2_9_50_aar.xml new file mode 100644 index 0000000..fc9b137 --- /dev/null +++ b/.idea/libraries/Gradle__com_github_CymChad_BaseRecyclerViewAdapterHelper_2_9_50_aar.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_github_bumptech_glide_annotations_4_12_0.xml b/.idea/libraries/Gradle__com_github_bumptech_glide_annotations_4_12_0.xml new file mode 100644 index 0000000..6cddbd1 --- /dev/null +++ b/.idea/libraries/Gradle__com_github_bumptech_glide_annotations_4_12_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_github_bumptech_glide_disklrucache_4_12_0.xml b/.idea/libraries/Gradle__com_github_bumptech_glide_disklrucache_4_12_0.xml new file mode 100644 index 0000000..303f77a --- /dev/null +++ b/.idea/libraries/Gradle__com_github_bumptech_glide_disklrucache_4_12_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_github_bumptech_glide_gifdecoder_4_12_0_aar.xml b/.idea/libraries/Gradle__com_github_bumptech_glide_gifdecoder_4_12_0_aar.xml new file mode 100644 index 0000000..584c9a4 --- /dev/null +++ b/.idea/libraries/Gradle__com_github_bumptech_glide_gifdecoder_4_12_0_aar.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_github_bumptech_glide_glide_4_12_0_aar.xml b/.idea/libraries/Gradle__com_github_bumptech_glide_glide_4_12_0_aar.xml new file mode 100644 index 0000000..7473fec --- /dev/null +++ b/.idea/libraries/Gradle__com_github_bumptech_glide_glide_4_12_0_aar.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_github_getActivity_XXPermissions_21_3_aar.xml b/.idea/libraries/Gradle__com_github_getActivity_XXPermissions_21_3_aar.xml new file mode 100644 index 0000000..c4daa9b --- /dev/null +++ b/.idea/libraries/Gradle__com_github_getActivity_XXPermissions_21_3_aar.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_github_li_xiaojun_XPopup_v2_2_23_aar.xml b/.idea/libraries/Gradle__com_github_li_xiaojun_XPopup_v2_2_23_aar.xml new file mode 100644 index 0000000..febad2e --- /dev/null +++ b/.idea/libraries/Gradle__com_github_li_xiaojun_XPopup_v2_2_23_aar.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_google_android_material_material_1_3_0_aar.xml b/.idea/libraries/Gradle__com_google_android_material_material_1_3_0_aar.xml new file mode 100644 index 0000000..6de853a --- /dev/null +++ b/.idea/libraries/Gradle__com_google_android_material_material_1_3_0_aar.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_google_android_material_material_1_5_0_aar.xml b/.idea/libraries/Gradle__com_google_android_material_material_1_5_0_aar.xml new file mode 100644 index 0000000..348fc08 --- /dev/null +++ b/.idea/libraries/Gradle__com_google_android_material_material_1_5_0_aar.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_google_code_gson_gson_2_8_7.xml b/.idea/libraries/Gradle__com_google_code_gson_gson_2_8_7.xml new file mode 100644 index 0000000..b0ed237 --- /dev/null +++ b/.idea/libraries/Gradle__com_google_code_gson_gson_2_8_7.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_gyf_immersionbar_immersionbar_3_0_0_aar.xml b/.idea/libraries/Gradle__com_gyf_immersionbar_immersionbar_3_0_0_aar.xml new file mode 100644 index 0000000..3a8f533 --- /dev/null +++ b/.idea/libraries/Gradle__com_gyf_immersionbar_immersionbar_3_0_0_aar.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_kongzue_dialogx_DialogX_0_0_49_aar.xml b/.idea/libraries/Gradle__com_kongzue_dialogx_DialogX_0_0_49_aar.xml new file mode 100644 index 0000000..f7d1480 --- /dev/null +++ b/.idea/libraries/Gradle__com_kongzue_dialogx_DialogX_0_0_49_aar.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_kongzue_dialogx_style_DialogXInterface_5_aar.xml b/.idea/libraries/Gradle__com_kongzue_dialogx_style_DialogXInterface_5_aar.xml new file mode 100644 index 0000000..02c3a42 --- /dev/null +++ b/.idea/libraries/Gradle__com_kongzue_dialogx_style_DialogXInterface_5_aar.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_kongzue_dialogx_style_DialogXMaterialYouStyle_0_0_49_aar.xml b/.idea/libraries/Gradle__com_kongzue_dialogx_style_DialogXMaterialYouStyle_0_0_49_aar.xml new file mode 100644 index 0000000..9c280ce --- /dev/null +++ b/.idea/libraries/Gradle__com_kongzue_dialogx_style_DialogXMaterialYouStyle_0_0_49_aar.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_ljx_rxhttp_rxhttp_2_5_7.xml b/.idea/libraries/Gradle__com_ljx_rxhttp_rxhttp_2_5_7.xml new file mode 100644 index 0000000..adcaca8 --- /dev/null +++ b/.idea/libraries/Gradle__com_ljx_rxhttp_rxhttp_2_5_7.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_ljx_rxhttp_rxhttp_annotation_1_0_1.xml b/.idea/libraries/Gradle__com_ljx_rxhttp_rxhttp_annotation_1_0_1.xml new file mode 100644 index 0000000..21d3320 --- /dev/null +++ b/.idea/libraries/Gradle__com_ljx_rxhttp_rxhttp_annotation_1_0_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_orhanobut_hawk_2_0_1_aar.xml b/.idea/libraries/Gradle__com_orhanobut_hawk_2_0_1_aar.xml new file mode 100644 index 0000000..7fc8760 --- /dev/null +++ b/.idea/libraries/Gradle__com_orhanobut_hawk_2_0_1_aar.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_rxjava_rxlife_rxlife_2_0_0_aar.xml b/.idea/libraries/Gradle__com_rxjava_rxlife_rxlife_2_0_0_aar.xml new file mode 100644 index 0000000..af72e92 --- /dev/null +++ b/.idea/libraries/Gradle__com_rxjava_rxlife_rxlife_2_0_0_aar.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_scwang_smart_refresh_drawable_paint_2_0_1_aar.xml b/.idea/libraries/Gradle__com_scwang_smart_refresh_drawable_paint_2_0_1_aar.xml new file mode 100644 index 0000000..5ca5cfe --- /dev/null +++ b/.idea/libraries/Gradle__com_scwang_smart_refresh_drawable_paint_2_0_1_aar.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_scwang_smart_refresh_footer_classics_2_0_1_aar.xml b/.idea/libraries/Gradle__com_scwang_smart_refresh_footer_classics_2_0_1_aar.xml new file mode 100644 index 0000000..06c5210 --- /dev/null +++ b/.idea/libraries/Gradle__com_scwang_smart_refresh_footer_classics_2_0_1_aar.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_scwang_smart_refresh_header_classics_2_0_1_aar.xml b/.idea/libraries/Gradle__com_scwang_smart_refresh_header_classics_2_0_1_aar.xml new file mode 100644 index 0000000..d331ef9 --- /dev/null +++ b/.idea/libraries/Gradle__com_scwang_smart_refresh_header_classics_2_0_1_aar.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_scwang_smart_refresh_header_material_2_0_1_aar.xml b/.idea/libraries/Gradle__com_scwang_smart_refresh_header_material_2_0_1_aar.xml new file mode 100644 index 0000000..40fbf70 --- /dev/null +++ b/.idea/libraries/Gradle__com_scwang_smart_refresh_header_material_2_0_1_aar.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_scwang_smart_refresh_layout_kernel_2_0_1_aar.xml b/.idea/libraries/Gradle__com_scwang_smart_refresh_layout_kernel_2_0_1_aar.xml new file mode 100644 index 0000000..4f33ba2 --- /dev/null +++ b/.idea/libraries/Gradle__com_scwang_smart_refresh_layout_kernel_2_0_1_aar.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_squareup_okhttp3_okhttp_4_8_1.xml b/.idea/libraries/Gradle__com_squareup_okhttp3_okhttp_4_8_1.xml new file mode 100644 index 0000000..a8fb848 --- /dev/null +++ b/.idea/libraries/Gradle__com_squareup_okhttp3_okhttp_4_8_1.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__com_squareup_okio_okio_2_7_0.xml b/.idea/libraries/Gradle__com_squareup_okio_okio_2_7_0.xml new file mode 100644 index 0000000..751ae6b --- /dev/null +++ b/.idea/libraries/Gradle__com_squareup_okio_okio_2_7_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__io_reactivex_rxjava2_rxandroid_2_1_1_aar.xml b/.idea/libraries/Gradle__io_reactivex_rxjava2_rxandroid_2_1_1_aar.xml new file mode 100644 index 0000000..7cc2ffd --- /dev/null +++ b/.idea/libraries/Gradle__io_reactivex_rxjava2_rxandroid_2_1_1_aar.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__io_reactivex_rxjava2_rxjava_2_2_8.xml b/.idea/libraries/Gradle__io_reactivex_rxjava2_rxjava_2_2_8.xml new file mode 100644 index 0000000..c798b7c --- /dev/null +++ b/.idea/libraries/Gradle__io_reactivex_rxjava2_rxjava_2_2_8.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_greenrobot_eventbus_3_2_0.xml b/.idea/libraries/Gradle__org_greenrobot_eventbus_3_2_0.xml new file mode 100644 index 0000000..a4f4db6 --- /dev/null +++ b/.idea/libraries/Gradle__org_greenrobot_eventbus_3_2_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_jetbrains_annotations_13_0.xml b/.idea/libraries/Gradle__org_jetbrains_annotations_13_0.xml new file mode 100644 index 0000000..012775f --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_annotations_13_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_4_0.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_4_0.xml new file mode 100644 index 0000000..86e4019 --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_1_4_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_common_1_4_0.xml b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_common_1_4_0.xml new file mode 100644 index 0000000..02b8dca --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlin_kotlin_stdlib_common_1_4_0.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlinx_kotlinx_coroutines_android_1_3_9.xml b/.idea/libraries/Gradle__org_jetbrains_kotlinx_kotlinx_coroutines_android_1_3_9.xml new file mode 100644 index 0000000..0f1ee54 --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlinx_kotlinx_coroutines_android_1_3_9.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_jetbrains_kotlinx_kotlinx_coroutines_core_jvm_1_3_9.xml b/.idea/libraries/Gradle__org_jetbrains_kotlinx_kotlinx_coroutines_core_jvm_1_3_9.xml new file mode 100644 index 0000000..2fb608a --- /dev/null +++ b/.idea/libraries/Gradle__org_jetbrains_kotlinx_kotlinx_coroutines_core_jvm_1_3_9.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Gradle__org_reactivestreams_reactive_streams_1_0_2.xml b/.idea/libraries/Gradle__org_reactivestreams_reactive_streams_1_0_2.xml new file mode 100644 index 0000000..2d8f97a --- /dev/null +++ b/.idea/libraries/Gradle__org_reactivestreams_reactive_streams_1_0_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..e0a6f4d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..d4d3a67 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/AlbumDialog/gov_affairs_cloud.AlbumDialog.androidTest.iml b/.idea/modules/AlbumDialog/gov_affairs_cloud.AlbumDialog.androidTest.iml new file mode 100644 index 0000000..e0d0990 --- /dev/null +++ b/.idea/modules/AlbumDialog/gov_affairs_cloud.AlbumDialog.androidTest.iml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/AlbumDialog/gov_affairs_cloud.AlbumDialog.iml b/.idea/modules/AlbumDialog/gov_affairs_cloud.AlbumDialog.iml new file mode 100644 index 0000000..1502471 --- /dev/null +++ b/.idea/modules/AlbumDialog/gov_affairs_cloud.AlbumDialog.iml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/AlbumDialog/gov_affairs_cloud.AlbumDialog.main.iml b/.idea/modules/AlbumDialog/gov_affairs_cloud.AlbumDialog.main.iml new file mode 100644 index 0000000..4ae0d86 --- /dev/null +++ b/.idea/modules/AlbumDialog/gov_affairs_cloud.AlbumDialog.main.iml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/AlbumDialog/gov_affairs_cloud.AlbumDialog.unitTest.iml b/.idea/modules/AlbumDialog/gov_affairs_cloud.AlbumDialog.unitTest.iml new file mode 100644 index 0000000..db4d6d0 --- /dev/null +++ b/.idea/modules/AlbumDialog/gov_affairs_cloud.AlbumDialog.unitTest.iml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/app/gov_affairs_cloud.app.androidTest.iml b/.idea/modules/app/gov_affairs_cloud.app.androidTest.iml new file mode 100644 index 0000000..03cc816 --- /dev/null +++ b/.idea/modules/app/gov_affairs_cloud.app.androidTest.iml @@ -0,0 +1,245 @@ + + + + + + :app:main + + + + + + + + + + + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f70110d05169c7f15d8934511faf8c3b/jetified-viewbinding-4.2.2-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f02e76953440163c44af027a9884c329/jetified-kotlin-stdlib-jdk8-1.5.31.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/a11b02d2ec6c6a42e76573c80ac0b293/constraintlayout-2.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/831e97615ca129561eaec4aabc72fa0a/material-1.2.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/eee67666f92ceebeedba9efa40f957b9/appcompat-1.4.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/3a592628b928194e0d210f9b2bbec8eb/legacy-support-v4-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/5b37a1bf1bcd643cf6fea59fec5d368f/jetified-viewpager2-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/4dc0eab4b18f6d48fa7eb346dd612fbe/recyclerview-1.2.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/da8e5d1ffa0ef0e74cd484b14600b437/jetified-rxhttp-2.5.7.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/92ee91a0d834d0848e778f073704bae1/jetified-gson-2.8.7.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/068b25aaace40e3b9b1a98d63906772f/jetified-refresh-layout-kernel-2.0.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/54d2844c3a3bf41a602164c3f2ceb20f/jetified-refresh-header-classics-2.0.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/049675cda256b31ae5393d3b8bea8300/jetified-refresh-header-material-2.0.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/53ceb0209e5e57c82f47c66413144c4d/jetified-immersionbar-3.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/955345d2016b6548ef6df952ab5ee472/jetified-eventbus-3.2.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/7fc3502e06755b33a0783beefed5ff91/jetified-FlycoTabLayout_Lib-2.1.2-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/7657d921cc13a6bc74f8b6df4d28f077/jetified-BaseRecyclerViewAdapterHelper-2.9.50-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/683d986000fa9a00a94d9ff769ed5b67/jetified-okhttp-4.8.1.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/99969dfe549faeb97b10d9ea4ba86170/jetified-rxandroid-2.1.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/0035bb61d698292fca6f42a7e8879c4f/jetified-rxjava-2.2.8.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/0d7c75428ffd5a0d47df24d252c22858/jetified-rxlife-2.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/fed21c0941881cf7a5ea2d9ebf9d93d9/jetified-glide-4.12.0-api.jar + $MODULE_DIR$/../../../OXViewLib/build/intermediates/compile_library_classes_jar/debug/classes.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/773beb9f52e86fdad77e4565d134ec4d/jetified-ECharts-3.0.0.2.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/9db907c4bd9aac67adf0f7d6722972ff/fragment-1.3.6-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/21e0f23707c8390f88cc6fff2f7a2f8d/jetified-activity-1.2.4-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/0ed77ed0cd28dde3c023cddaa682239f/jetified-appcompat-resources-1.4.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f0dd4b307d197a674afb5ddba93d3c1f/legacy-support-core-ui-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/cc4fa89e862478e5b81e3f5e980bd676/drawerlayout-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/19e4792ad7df49cfb20e0da699c5c155/media-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/2738603ba7610df2a85ad8a16f1f7bd7/legacy-support-core-utils-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/b83a19006ec27dd9e455c4e1c1191846/coordinatorlayout-1.1.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/c8e01728d082920b0ffebe4c01213939/viewpager-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/53646ea64f1c7ed545b58d052e72c096/slidingpanelayout-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/09f11dc7b73b993323c0e069fd9ed1a1/customview-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/dbc07a1b3fd7027627449cf295e7eb8f/transition-1.2.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/a9d6656766833e88ba7ab540b47463f0/vectordrawable-animated-1.1.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f8d7de33de21b4db99731facb12cf7f7/vectordrawable-1.1.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/77d4d9f24d21e479d619478f6183661d/loader-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/8b11f3359779a9b57aea7fa41632e5a8/swiperefreshlayout-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/d508d2b1e0b4290ea5b2617f2abcc464/asynclayoutinflater-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/e3bc9545a4333cc301203d912594eeb2/core-1.7.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/bc98b3cb6f45f5ad4e6f935c9b13091c/cursoradapter-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/bcb269a22bf3f8c5c50b77edd298ccfc/jetified-lifecycle-viewmodel-savedstate-2.3.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/027af073f661f8dd2fd3cebb17780faf/jetified-savedstate-1.1.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/0ac3926ff5a8aa75832fd9c6f732f11f/cardview-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/74a6f876a5c1dbe398dcbfbb1ed5edf0/jetified-gifdecoder-4.12.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/c9373f65bd898c6e1ed64ed005ab88f3/exifinterface-1.2.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/e9d8dede771c5db9e36a967c8c05ca4f/lifecycle-runtime-2.3.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/7a483ec28f479d692828b6578b6423de/versionedparcelable-1.1.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/cbfa706a3c7088e2e83b5e33074bd26b/lifecycle-viewmodel-2.3.1-api.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.collection/collection/1.1.0/1f27220b47669781457de0d600849a5de0e89909/collection-1.1.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f397b047d5e5f51bdf160d0ab0e09e68/documentfile-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/89183578cba1ae9994c62329fe497184/localbroadcastmanager-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/3951bdc886169507d6deb80f9364502f/print-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/106748ecf5256e282478bf99cb8c2cb4/interpolator-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/aafa1f03e70c309cf74906d8d1e9c7ea/lifecycle-livedata-2.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f7758967043341e204510a03128d16fa/lifecycle-livedata-core-2.3.1-api.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-common/2.3.1/fc466261d52f4433863642fb40d12441ae274a98/lifecycle-common-2.3.1.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/5dfd2a845471ec40727a9a200a8359ad/core-runtime-2.0.0-api.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.arch.core/core-common/2.1.0/b3152fc64428c9354344bd89848ecddc09b6f07e/core-common-2.1.0.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.annotation/annotation/1.3.0/21f49f5f9b85fc49de712539f79123119740595/annotation-1.3.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/3dc1b9d90f3c3a5e2490c9fba766f670/jetified-kotlin-stdlib-jdk7-1.5.31.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/fda52321b6e0fab5351653623ccb7b97/jetified-kotlinx-coroutines-android-1.3.9.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/b672d2ad5a821e22844104c5c1cbac3a/jetified-okio-jvm-2.7.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/d76b9bb6dfc46ae991448f0e372f81d2/jetified-kotlinx-coroutines-core-jvm-1.3.9.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/c85b1126dbe8579b53198f68cc49b482/jetified-kotlin-stdlib-1.5.31.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.constraintlayout/constraintlayout-solver/2.0.0/f89bda02bc8f004f01f5420e2b6ca352c67c2fc3/constraintlayout-solver-2.0.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/98422ddceaa6716c9ed1f90ec98e86bd/jetified-annotation-experimental-1.1.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/fc88b5cb3fa66d8df179702297c93667/jetified-refresh-footer-classics-2.0.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/ac5a689bbb815115d783a15af6dcfc3f/jetified-rxhttp-annotation-1.0.1.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/fbb384978b612ee65f2c7fb9b82f80af/jetified-reactive-streams-1.0.2.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f452959753c49d2684d53879967e7f20/jetified-disklrucache-4.12.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/fb15355a49f930e658d02a7d61613920/jetified-annotations-4.12.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/acff37e73100ac9ea8581441736df4a3/jetified-annotations-13.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/b7bffe99d4cd3a16b74cb77e9c9d3ce4/jetified-kotlin-stdlib-common-1.5.31.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/c40858a418daf2eadeb1e4c62134edcf/jetified-refresh-drawable-paint-2.0.1-api.jar + $MODULE_DIR$/../../../../../android_sdk/platforms/android-31/android.jar + $MODULE_DIR$/../../../../../android_sdk/build-tools/30.0.2/core-lambda-stubs.jar + + + + + + + + + + + + $MODULE_DIR$/../../../app/build/tmp/kotlin-classes/debug + $MODULE_DIR$/../../../app/build/intermediates/javac/debug/classes + $MODULE_DIR$/../../../app/build/tmp/kapt3/classes/debug + $MODULE_DIR$/../../../app/build/intermediates/app_classes/debug/classes.jar + + + + + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.5.31/cc18c29253541dc57c25c3ef514d63c7953ae1a6/kotlin-compiler-embeddable-1.5.31.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-reflect/1.5.31/1523fcd842a47da0820cea772b19c51056fec8a9/kotlin-reflect-1.5.31.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.5.31/6628d61d0f5603568e72d2d5915d2c034b4f1c55/kotlin-stdlib-1.5.31.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.5.31/43331609c7de811fed085e0dfd150874b157c32/kotlin-stdlib-common-1.5.31.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-script-runtime/1.5.31/aaea854be2cfc06373dfc11be5a6ba9ca5ca84a6/kotlin-script-runtime-1.5.31.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-daemon-embeddable/1.5.31/d19b549661e28c62781683dc7c7e34bf416974f1/kotlin-daemon-embeddable-1.5.31.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.intellij.deps/trove4j/1.0.20181211/216c2e14b070f334479d800987affe4054cd563f/trove4j-1.0.20181211.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/app/gov_affairs_cloud.app.iml b/.idea/modules/app/gov_affairs_cloud.app.iml new file mode 100644 index 0000000..9c90f01 --- /dev/null +++ b/.idea/modules/app/gov_affairs_cloud.app.iml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/app/gov_affairs_cloud.app.main.iml b/.idea/modules/app/gov_affairs_cloud.app.main.iml new file mode 100644 index 0000000..96cc2b5 --- /dev/null +++ b/.idea/modules/app/gov_affairs_cloud.app.main.iml @@ -0,0 +1,249 @@ + + + + + + + + + + + + + + + + $MODULE_DIR$/../../../app/build/intermediates/compile_and_runtime_not_namespaced_r_class_jar/debug/R.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f70110d05169c7f15d8934511faf8c3b/jetified-viewbinding-4.2.2-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f02e76953440163c44af027a9884c329/jetified-kotlin-stdlib-jdk8-1.5.31.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/a11b02d2ec6c6a42e76573c80ac0b293/constraintlayout-2.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/831e97615ca129561eaec4aabc72fa0a/material-1.2.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/eee67666f92ceebeedba9efa40f957b9/appcompat-1.4.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/5b37a1bf1bcd643cf6fea59fec5d368f/jetified-viewpager2-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/4dc0eab4b18f6d48fa7eb346dd612fbe/recyclerview-1.2.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/3a592628b928194e0d210f9b2bbec8eb/legacy-support-v4-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/fed21c0941881cf7a5ea2d9ebf9d93d9/jetified-glide-4.12.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/9db907c4bd9aac67adf0f7d6722972ff/fragment-1.3.6-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/21e0f23707c8390f88cc6fff2f7a2f8d/jetified-activity-1.2.4-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/0ed77ed0cd28dde3c023cddaa682239f/jetified-appcompat-resources-1.4.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f0dd4b307d197a674afb5ddba93d3c1f/legacy-support-core-ui-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/cc4fa89e862478e5b81e3f5e980bd676/drawerlayout-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/19e4792ad7df49cfb20e0da699c5c155/media-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/2738603ba7610df2a85ad8a16f1f7bd7/legacy-support-core-utils-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/b83a19006ec27dd9e455c4e1c1191846/coordinatorlayout-1.1.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/c8e01728d082920b0ffebe4c01213939/viewpager-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/53646ea64f1c7ed545b58d052e72c096/slidingpanelayout-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/09f11dc7b73b993323c0e069fd9ed1a1/customview-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/dbc07a1b3fd7027627449cf295e7eb8f/transition-1.2.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/a9d6656766833e88ba7ab540b47463f0/vectordrawable-animated-1.1.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f8d7de33de21b4db99731facb12cf7f7/vectordrawable-1.1.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/77d4d9f24d21e479d619478f6183661d/loader-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/8b11f3359779a9b57aea7fa41632e5a8/swiperefreshlayout-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/d508d2b1e0b4290ea5b2617f2abcc464/asynclayoutinflater-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/e3bc9545a4333cc301203d912594eeb2/core-1.7.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/bc98b3cb6f45f5ad4e6f935c9b13091c/cursoradapter-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/bcb269a22bf3f8c5c50b77edd298ccfc/jetified-lifecycle-viewmodel-savedstate-2.3.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/027af073f661f8dd2fd3cebb17780faf/jetified-savedstate-1.1.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/0ac3926ff5a8aa75832fd9c6f732f11f/cardview-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/ac7ef1e8e6bec8619b2a72d60b094c92/lifecycle-runtime-2.4.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/0d7c75428ffd5a0d47df24d252c22858/jetified-rxlife-2.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/1f01cc01c2ed8e5fb0d04a6a66743a0b/lifecycle-livedata-2.2.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f7758967043341e204510a03128d16fa/lifecycle-livedata-core-2.3.1-api.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-common/2.4.0/1fdb7349701e9cf2f0a69fc10642b6fef6bb3e12/lifecycle-common-2.4.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/74a6f876a5c1dbe398dcbfbb1ed5edf0/jetified-gifdecoder-4.12.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/c9373f65bd898c6e1ed64ed005ab88f3/exifinterface-1.2.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/7a483ec28f479d692828b6578b6423de/versionedparcelable-1.1.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/cbfa706a3c7088e2e83b5e33074bd26b/lifecycle-viewmodel-2.3.1-api.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.collection/collection/1.1.0/1f27220b47669781457de0d600849a5de0e89909/collection-1.1.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f397b047d5e5f51bdf160d0ab0e09e68/documentfile-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/89183578cba1ae9994c62329fe497184/localbroadcastmanager-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/3951bdc886169507d6deb80f9364502f/print-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/106748ecf5256e282478bf99cb8c2cb4/interpolator-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/64a425f496d616da2745b52be87b1dcd/core-runtime-2.1.0-api.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.arch.core/core-common/2.1.0/b3152fc64428c9354344bd89848ecddc09b6f07e/core-common-2.1.0.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.annotation/annotation/1.3.0/21f49f5f9b85fc49de712539f79123119740595/annotation-1.3.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/683d986000fa9a00a94d9ff769ed5b67/jetified-okhttp-4.8.1.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/3dc1b9d90f3c3a5e2490c9fba766f670/jetified-kotlin-stdlib-jdk7-1.5.31.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/da8e5d1ffa0ef0e74cd484b14600b437/jetified-rxhttp-2.5.7.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/fda52321b6e0fab5351653623ccb7b97/jetified-kotlinx-coroutines-android-1.3.9.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/b672d2ad5a821e22844104c5c1cbac3a/jetified-okio-jvm-2.7.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/d76b9bb6dfc46ae991448f0e372f81d2/jetified-kotlinx-coroutines-core-jvm-1.3.9.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/c85b1126dbe8579b53198f68cc49b482/jetified-kotlin-stdlib-1.5.31.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/acff37e73100ac9ea8581441736df4a3/jetified-annotations-13.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/b7bffe99d4cd3a16b74cb77e9c9d3ce4/jetified-kotlin-stdlib-common-1.5.31.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/98422ddceaa6716c9ed1f90ec98e86bd/jetified-annotation-experimental-1.1.0-api.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.constraintlayout/constraintlayout-solver/2.0.0/f89bda02bc8f004f01f5420e2b6ca352c67c2fc3/constraintlayout-solver-2.0.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/92ee91a0d834d0848e778f073704bae1/jetified-gson-2.8.7.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/068b25aaace40e3b9b1a98d63906772f/jetified-refresh-layout-kernel-2.0.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/54d2844c3a3bf41a602164c3f2ceb20f/jetified-refresh-header-classics-2.0.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/fc88b5cb3fa66d8df179702297c93667/jetified-refresh-footer-classics-2.0.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/c40858a418daf2eadeb1e4c62134edcf/jetified-refresh-drawable-paint-2.0.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/049675cda256b31ae5393d3b8bea8300/jetified-refresh-header-material-2.0.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/53ceb0209e5e57c82f47c66413144c4d/jetified-immersionbar-3.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/955345d2016b6548ef6df952ab5ee472/jetified-eventbus-3.2.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/7fc3502e06755b33a0783beefed5ff91/jetified-FlycoTabLayout_Lib-2.1.2-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/7657d921cc13a6bc74f8b6df4d28f077/jetified-BaseRecyclerViewAdapterHelper-2.9.50-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/ac5a689bbb815115d783a15af6dcfc3f/jetified-rxhttp-annotation-1.0.1.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/99969dfe549faeb97b10d9ea4ba86170/jetified-rxandroid-2.1.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/0035bb61d698292fca6f42a7e8879c4f/jetified-rxjava-2.2.8.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/ffde41c7789384e2f1eeaea57816b82c/jetified-reactive-streams-1.0.3.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f452959753c49d2684d53879967e7f20/jetified-disklrucache-4.12.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/fb15355a49f930e658d02a7d61613920/jetified-annotations-4.12.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/773beb9f52e86fdad77e4565d134ec4d/jetified-ECharts-3.0.0.2.jar + $MODULE_DIR$/../../../OXViewLib/build/intermediates/compile_library_classes_jar/debug/classes.jar + $MODULE_DIR$/../../../../../android_sdk/platforms/android-31/android.jar + $MODULE_DIR$/../../../../../android_sdk/build-tools/30.0.2/core-lambda-stubs.jar + + + + + + + + + + + + + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.5.31/cc18c29253541dc57c25c3ef514d63c7953ae1a6/kotlin-compiler-embeddable-1.5.31.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-reflect/1.5.31/1523fcd842a47da0820cea772b19c51056fec8a9/kotlin-reflect-1.5.31.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.5.31/6628d61d0f5603568e72d2d5915d2c034b4f1c55/kotlin-stdlib-1.5.31.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.5.31/43331609c7de811fed085e0dfd150874b157c32/kotlin-stdlib-common-1.5.31.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-script-runtime/1.5.31/aaea854be2cfc06373dfc11be5a6ba9ca5ca84a6/kotlin-script-runtime-1.5.31.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-daemon-embeddable/1.5.31/d19b549661e28c62781683dc7c7e34bf416974f1/kotlin-daemon-embeddable-1.5.31.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.intellij.deps/trove4j/1.0.20181211/216c2e14b070f334479d800987affe4054cd563f/trove4j-1.0.20181211.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/app/gov_affairs_cloud.app.unitTest.iml b/.idea/modules/app/gov_affairs_cloud.app.unitTest.iml new file mode 100644 index 0000000..d557d7a --- /dev/null +++ b/.idea/modules/app/gov_affairs_cloud.app.unitTest.iml @@ -0,0 +1,241 @@ + + + + + + :app:main + + + + + + + + + + + $MODULE_DIR$/../../../app/build/intermediates/compile_and_runtime_not_namespaced_r_class_jar/debug/R.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f70110d05169c7f15d8934511faf8c3b/jetified-viewbinding-4.2.2-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f02e76953440163c44af027a9884c329/jetified-kotlin-stdlib-jdk8-1.5.31.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/a11b02d2ec6c6a42e76573c80ac0b293/constraintlayout-2.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/831e97615ca129561eaec4aabc72fa0a/material-1.2.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/eee67666f92ceebeedba9efa40f957b9/appcompat-1.4.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/5b37a1bf1bcd643cf6fea59fec5d368f/jetified-viewpager2-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/4dc0eab4b18f6d48fa7eb346dd612fbe/recyclerview-1.2.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/3a592628b928194e0d210f9b2bbec8eb/legacy-support-v4-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/fed21c0941881cf7a5ea2d9ebf9d93d9/jetified-glide-4.12.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/9db907c4bd9aac67adf0f7d6722972ff/fragment-1.3.6-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/21e0f23707c8390f88cc6fff2f7a2f8d/jetified-activity-1.2.4-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/0ed77ed0cd28dde3c023cddaa682239f/jetified-appcompat-resources-1.4.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f0dd4b307d197a674afb5ddba93d3c1f/legacy-support-core-ui-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/cc4fa89e862478e5b81e3f5e980bd676/drawerlayout-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/19e4792ad7df49cfb20e0da699c5c155/media-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/2738603ba7610df2a85ad8a16f1f7bd7/legacy-support-core-utils-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/b83a19006ec27dd9e455c4e1c1191846/coordinatorlayout-1.1.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/c8e01728d082920b0ffebe4c01213939/viewpager-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/53646ea64f1c7ed545b58d052e72c096/slidingpanelayout-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/09f11dc7b73b993323c0e069fd9ed1a1/customview-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/dbc07a1b3fd7027627449cf295e7eb8f/transition-1.2.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/a9d6656766833e88ba7ab540b47463f0/vectordrawable-animated-1.1.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f8d7de33de21b4db99731facb12cf7f7/vectordrawable-1.1.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/77d4d9f24d21e479d619478f6183661d/loader-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/8b11f3359779a9b57aea7fa41632e5a8/swiperefreshlayout-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/d508d2b1e0b4290ea5b2617f2abcc464/asynclayoutinflater-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/e3bc9545a4333cc301203d912594eeb2/core-1.7.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/bc98b3cb6f45f5ad4e6f935c9b13091c/cursoradapter-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/bcb269a22bf3f8c5c50b77edd298ccfc/jetified-lifecycle-viewmodel-savedstate-2.3.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/027af073f661f8dd2fd3cebb17780faf/jetified-savedstate-1.1.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/0ac3926ff5a8aa75832fd9c6f732f11f/cardview-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/ac7ef1e8e6bec8619b2a72d60b094c92/lifecycle-runtime-2.4.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/0d7c75428ffd5a0d47df24d252c22858/jetified-rxlife-2.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/1f01cc01c2ed8e5fb0d04a6a66743a0b/lifecycle-livedata-2.2.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f7758967043341e204510a03128d16fa/lifecycle-livedata-core-2.3.1-api.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-common/2.4.0/1fdb7349701e9cf2f0a69fc10642b6fef6bb3e12/lifecycle-common-2.4.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/74a6f876a5c1dbe398dcbfbb1ed5edf0/jetified-gifdecoder-4.12.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/c9373f65bd898c6e1ed64ed005ab88f3/exifinterface-1.2.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/7a483ec28f479d692828b6578b6423de/versionedparcelable-1.1.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/cbfa706a3c7088e2e83b5e33074bd26b/lifecycle-viewmodel-2.3.1-api.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.collection/collection/1.1.0/1f27220b47669781457de0d600849a5de0e89909/collection-1.1.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f397b047d5e5f51bdf160d0ab0e09e68/documentfile-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/89183578cba1ae9994c62329fe497184/localbroadcastmanager-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/3951bdc886169507d6deb80f9364502f/print-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/106748ecf5256e282478bf99cb8c2cb4/interpolator-1.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/64a425f496d616da2745b52be87b1dcd/core-runtime-2.1.0-api.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.arch.core/core-common/2.1.0/b3152fc64428c9354344bd89848ecddc09b6f07e/core-common-2.1.0.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.annotation/annotation/1.3.0/21f49f5f9b85fc49de712539f79123119740595/annotation-1.3.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/683d986000fa9a00a94d9ff769ed5b67/jetified-okhttp-4.8.1.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/3dc1b9d90f3c3a5e2490c9fba766f670/jetified-kotlin-stdlib-jdk7-1.5.31.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/da8e5d1ffa0ef0e74cd484b14600b437/jetified-rxhttp-2.5.7.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/fda52321b6e0fab5351653623ccb7b97/jetified-kotlinx-coroutines-android-1.3.9.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/b672d2ad5a821e22844104c5c1cbac3a/jetified-okio-jvm-2.7.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/d76b9bb6dfc46ae991448f0e372f81d2/jetified-kotlinx-coroutines-core-jvm-1.3.9.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/c85b1126dbe8579b53198f68cc49b482/jetified-kotlin-stdlib-1.5.31.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/acff37e73100ac9ea8581441736df4a3/jetified-annotations-13.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/b7bffe99d4cd3a16b74cb77e9c9d3ce4/jetified-kotlin-stdlib-common-1.5.31.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/98422ddceaa6716c9ed1f90ec98e86bd/jetified-annotation-experimental-1.1.0-api.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/androidx.constraintlayout/constraintlayout-solver/2.0.0/f89bda02bc8f004f01f5420e2b6ca352c67c2fc3/constraintlayout-solver-2.0.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/92ee91a0d834d0848e778f073704bae1/jetified-gson-2.8.7.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/068b25aaace40e3b9b1a98d63906772f/jetified-refresh-layout-kernel-2.0.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/54d2844c3a3bf41a602164c3f2ceb20f/jetified-refresh-header-classics-2.0.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/fc88b5cb3fa66d8df179702297c93667/jetified-refresh-footer-classics-2.0.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/c40858a418daf2eadeb1e4c62134edcf/jetified-refresh-drawable-paint-2.0.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/049675cda256b31ae5393d3b8bea8300/jetified-refresh-header-material-2.0.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/53ceb0209e5e57c82f47c66413144c4d/jetified-immersionbar-3.0.0-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/955345d2016b6548ef6df952ab5ee472/jetified-eventbus-3.2.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/7fc3502e06755b33a0783beefed5ff91/jetified-FlycoTabLayout_Lib-2.1.2-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/7657d921cc13a6bc74f8b6df4d28f077/jetified-BaseRecyclerViewAdapterHelper-2.9.50-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/ac5a689bbb815115d783a15af6dcfc3f/jetified-rxhttp-annotation-1.0.1.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/99969dfe549faeb97b10d9ea4ba86170/jetified-rxandroid-2.1.1-api.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/0035bb61d698292fca6f42a7e8879c4f/jetified-rxjava-2.2.8.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/ffde41c7789384e2f1eeaea57816b82c/jetified-reactive-streams-1.0.3.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/f452959753c49d2684d53879967e7f20/jetified-disklrucache-4.12.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/fb15355a49f930e658d02a7d61613920/jetified-annotations-4.12.0.jar + $USER_HOME$/.gradle/caches/transforms-2/files-2.1/773beb9f52e86fdad77e4565d134ec4d/jetified-ECharts-3.0.0.2.jar + $MODULE_DIR$/../../../OXViewLib/build/intermediates/compile_library_classes_jar/debug/classes.jar + $MODULE_DIR$/../../../../../android_sdk/platforms/android-31/android.jar + $MODULE_DIR$/../../../../../android_sdk/build-tools/30.0.2/core-lambda-stubs.jar + + + + + + + + + + + + $MODULE_DIR$/../../../app/build/tmp/kotlin-classes/debug + $MODULE_DIR$/../../../app/build/intermediates/javac/debug/classes + $MODULE_DIR$/../../../app/build/tmp/kapt3/classes/debug + $MODULE_DIR$/../../../app/build/intermediates/app_classes/debug/classes.jar + + + + + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-compiler-embeddable/1.5.31/cc18c29253541dc57c25c3ef514d63c7953ae1a6/kotlin-compiler-embeddable-1.5.31.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-reflect/1.5.31/1523fcd842a47da0820cea772b19c51056fec8a9/kotlin-reflect-1.5.31.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.5.31/6628d61d0f5603568e72d2d5915d2c034b4f1c55/kotlin-stdlib-1.5.31.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/13.0/919f0dfe192fb4e063e7dacadee7f8bb9a2672a9/annotations-13.0.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.5.31/43331609c7de811fed085e0dfd150874b157c32/kotlin-stdlib-common-1.5.31.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-script-runtime/1.5.31/aaea854be2cfc06373dfc11be5a6ba9ca5ca84a6/kotlin-script-runtime-1.5.31.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-daemon-embeddable/1.5.31/d19b549661e28c62781683dc7c7e34bf416974f1/kotlin-daemon-embeddable-1.5.31.jar + $USER_HOME$/.gradle/caches/modules-2/files-2.1/org.jetbrains.intellij.deps/trove4j/1.0.20181211/216c2e14b070f334479d800987affe4054cd563f/trove4j-1.0.20181211.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/gov_affairs_cloud.iml b/.idea/modules/gov_affairs_cloud.iml new file mode 100644 index 0000000..7da844b --- /dev/null +++ b/.idea/modules/gov_affairs_cloud.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/AlbumDialog/.gitignore b/AlbumDialog/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/AlbumDialog/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/AlbumDialog/build.gradle b/AlbumDialog/build.gradle new file mode 100644 index 0000000..e4376e2 --- /dev/null +++ b/AlbumDialog/build.gradle @@ -0,0 +1,38 @@ +plugins { + id 'com.android.library' +} + +android { + compileSdkVersion 33 + + defaultConfig { + minSdkVersion 21 + targetSdkVersion 33 + versionCode 1 + versionName "1.0" + + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + + implementation 'androidx.appcompat:appcompat:1.4.1' + def dialogx_version = "0.0.49" + api "com.kongzue.dialogx:DialogX:${dialogx_version}" + api "com.kongzue.dialogx.style:DialogXMaterialYouStyle:${dialogx_version}" + implementation 'com.github.bumptech.glide:glide:4.12.0' + implementation "androidx.recyclerview:recyclerview:1.2.1" + api 'com.github.getActivity:XXPermissions:21.3' +} \ No newline at end of file diff --git a/AlbumDialog/consumer-rules.pro b/AlbumDialog/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/AlbumDialog/proguard-rules.pro b/AlbumDialog/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/AlbumDialog/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/AlbumDialog/src/main/AndroidManifest.xml b/AlbumDialog/src/main/AndroidManifest.xml new file mode 100644 index 0000000..aeff44e --- /dev/null +++ b/AlbumDialog/src/main/AndroidManifest.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/AlbumDialog/src/main/java/com/kongzue/albumdialog/PhotoAlbumDialog.java b/AlbumDialog/src/main/java/com/kongzue/albumdialog/PhotoAlbumDialog.java new file mode 100644 index 0000000..0cc047f --- /dev/null +++ b/AlbumDialog/src/main/java/com/kongzue/albumdialog/PhotoAlbumDialog.java @@ -0,0 +1,955 @@ +package com.kongzue.albumdialog; + +import static com.kongzue.albumdialog.util.AlbumUtil.getAllAlbums; +import static com.kongzue.albumdialog.util.AlbumUtil.getPhotosByAlbum; +import static com.kongzue.dialogx.dialogs.PopTip.tip; +import static com.kongzue.dialogx.interfaces.BaseDialog.isNull; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.target.SimpleTarget; +import com.bumptech.glide.request.transition.Transition; +import com.hjq.permissions.OnPermissionCallback; +import com.hjq.permissions.Permission; +import com.hjq.permissions.XXPermissions; +import com.kongzue.albumdialog.util.AlbumAdapter; +import com.kongzue.albumdialog.util.DialogImplCallback; +import com.kongzue.albumdialog.util.GridSpacingItemDecoration; +import com.kongzue.albumdialog.util.PhotoAdapter; +import com.kongzue.albumdialog.util.SelectPhotoCallback; +import com.kongzue.albumdialog.views.PhotoSelectImageView; +import com.kongzue.albumdialog.views.ScrollableRecycleView; +import com.kongzue.albumdialog.views.crop.ClipView; +import com.kongzue.dialogx.dialogs.FullScreenDialog; +import com.kongzue.dialogx.dialogs.WaitDialog; +import com.kongzue.dialogx.interfaces.BaseDialog; +import com.kongzue.dialogx.interfaces.DialogLifecycleCallback; +import com.kongzue.dialogx.interfaces.OnBindView; +import com.kongzue.dialogx.interfaces.OnSafeInsetsChangeListener; + +import android.app.Activity; +import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.provider.MediaStore; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.view.animation.DecelerateInterpolator; +import android.widget.FrameLayout; +import android.widget.HorizontalScrollView; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.Space; +import android.widget.TextView; +import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.core.content.FileProvider; +import androidx.recyclerview.widget.GridLayoutManager; + +/** + * @author: Kongzue + * @github: https://github.com/kongzue/ + * @homepage: http://kongzue.com/ + * @mail: myzcxhh@live.cn + * @createTime: 2022/5/13 22:53 + */ +public class PhotoAlbumDialog { + + public static String fileProvider; //一般是 context.getPackageName() + ".fileprovider",请自行配置,如果不配置使用压缩、裁剪图像后默认返回 file 路径。 + + public enum SORT_MODE { + ASC, + DESC + } + + enum STEP { + SELECT_PHOTO, + CLIP_PHOTO + } + + STEP step = STEP.SELECT_PHOTO; + SORT_MODE sortMode = SORT_MODE.DESC; + String sortBy = MediaStore.Images.Media.DATE_ADDED; + String defaultSelectAlbumName; + int previewPhotoMaxColum = 4; + Integer previewPhotoMargin; + Integer previewPhotoHeight; + int errorPhotoDrawableRes = R.drawable.album_dialog_error_photo; + String dialogTipText; + String clipTipText; + String errorMaxSelectTipText; + List selectedPhotos = new ArrayList<>(); + DialogImplCallback dialogDialogImplCallback; //对话框构建回调 + int maxSelectPhotoCount; //最多选几张 + SelectPhotoCallback callback; //回调 + boolean clip; //是否开启裁切 + boolean compressPhoto; //是否压缩 + int compressQuality = 90; //压缩质量,compressPhoto=true 时生效 + int maxWidth, maxHeight; //最大宽高 + + public static PhotoAlbumDialog build() { + return new PhotoAlbumDialog(); + } + + List allAlbums; + List defaultAlbumPhotos; + GridSpacingItemDecoration photoGridSpacingItemDecoration; + + LinearLayout boxLayout; + TextView tipView; + FrameLayout contentLayout; + ScrollableRecycleView recyclerView; + TextView albumSelectView; + TextView otherAlbumSelectView; + LinearLayout clipBox; + ImageView closeButton; + ImageView okButton; + FullScreenDialog fullScreenDialog; + Context activityContext; + + public PhotoAlbumDialog() { + fullScreenDialog = FullScreenDialog.build(); + } + + public void show(Activity activityContext) { + this.activityContext = activityContext; + if (checkPermission(activityContext)) { + previewPhotoHeight = getScreenWidth(activityContext) / previewPhotoMaxColum; + + allAlbums = getAllAlbums(activityContext); + defaultAlbumPhotos = getPhotosByAlbum(activityContext, defaultSelectAlbumName, sortBy, sortMode); + + Log.i(">>>", "allAlbums: " + allAlbums.size()); + Log.i(">>>", "defaultAlbumPhotos: " + defaultAlbumPhotos.size()); + + allAlbums.add(0, activityContext.getString(R.string.album_dialog_default_album_name)); + + boxLayout = new LinearLayout(activityContext); //照片选择总布局 + boxLayout.setGravity(Gravity.CENTER_HORIZONTAL); + boxLayout.setOrientation(LinearLayout.VERTICAL); + + ImageView scrollBar = new ImageView(activityContext); //滑动提示条 + scrollBar.setBackgroundResource(R.drawable.album_dialog_bkg_album_gray); + LinearLayout.LayoutParams scrollBarLp = new LinearLayout.LayoutParams(dip2px(30), dip2px(5)); + scrollBarLp.topMargin = dip2px(10); + boxLayout.addView(scrollBar, scrollBarLp); + + tipView = new TextView(activityContext); //提示文本:选择需要使用的照片 + tipView.setText(getDialogTipText()); + tipView.setGravity(Gravity.CENTER); + tipView.setTextColor(activityContext.getResources().getColor(R.color.albumDefaultLabelColor)); + tipView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + tipView.setPadding(dip2px(15), dip2px(10), dip2px(15), dip2px(10)); + boxLayout.addView(tipView, + new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + if (!isNull(dialogTipText)) { + tipView.setText(dialogTipText); + } + + boxLayout.setGravity(Gravity.CENTER_HORIZONTAL); + boxLayout.setOrientation(LinearLayout.VERTICAL); + + LinearLayout albumSelectLayout = new LinearLayout(activityContext); //相册选择条(关闭按钮、已选择的相册、其他相册、确定按钮) + albumSelectLayout.setGravity(Gravity.CENTER); + albumSelectLayout.setPadding(dip2px(10), 0, dip2px(10), 0); + { + albumSelectView = new TextView(activityContext); + otherAlbumSelectView = new TextView(activityContext); + + albumSelectView.setText(isNull(defaultSelectAlbumName) ? activityContext.getString(R.string.album_dialog_default_album_name) + : defaultSelectAlbumName); + albumSelectView.setTextColor(Color.BLACK); + albumSelectView.setCompoundDrawables(null, null, null, null); + albumSelectView.setBackgroundResource(R.drawable.album_dialog_bkg_album_selector); + albumSelectView.setBackground(getRippleBackgroundDrawable(activityContext, R.drawable.album_dialog_bkg_album_selector)); + albumSelectView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + albumSelectView.setClickable(true); + albumSelectView.setFocusable(true); + albumSelectView.setPadding(dip2px(20), dip2px(10), dip2px(20), dip2px(10)); + albumSelectView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + recyclerView.animate().alpha(0f).withEndAction(new Runnable() { + @Override + public void run() { + loadPhotoList(activityContext); + albumSelectView.setBackground( + getRippleBackgroundDrawable(activityContext, R.drawable.album_dialog_bkg_album_selector)); + otherAlbumSelectView.setBackground( + getRippleBackgroundDrawable(activityContext, R.drawable.album_dialog_bkg_album_gray)); + } + }).setDuration(100); + } + }); + albumSelectLayout.addView(albumSelectView, + new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + + otherAlbumSelectView.setText(R.string.album_dialog_other_album); + otherAlbumSelectView.setTextColor(Color.BLACK); + otherAlbumSelectView.setCompoundDrawables(null, null, null, null); + otherAlbumSelectView.setBackground(getRippleBackgroundDrawable(activityContext, R.drawable.album_dialog_bkg_album_gray)); + otherAlbumSelectView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + otherAlbumSelectView.setClickable(true); + otherAlbumSelectView.setFocusable(true); + otherAlbumSelectView.setPadding(dip2px(20), dip2px(10), dip2px(20), dip2px(10)); + LinearLayout.LayoutParams albumSelectViewLp = + new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + albumSelectViewLp.leftMargin = dip2px(5); + albumSelectLayout.addView(otherAlbumSelectView, albumSelectViewLp); + otherAlbumSelectView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + loadAlbumList(activityContext); + albumSelectView.setBackground(getRippleBackgroundDrawable(activityContext, R.drawable.album_dialog_bkg_album_gray)); + otherAlbumSelectView.setBackground( + getRippleBackgroundDrawable(activityContext, R.drawable.album_dialog_bkg_album_selector)); + } + }); + } + { + LinearLayout.LayoutParams spaceLp = + new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + spaceLp.weight = 1; + albumSelectLayout.addView(new Space(activityContext), 0, spaceLp); + + int dp2 = dip2px(2); + closeButton = new ImageView(activityContext); + closeButton.setPadding(dp2, dp2, dp2, dp2); + closeButton.setImageTintList( + ColorStateList.valueOf(activityContext.getResources().getColor(R.color.albumDefaultThemeDeep))); + closeButton.setImageResource(R.mipmap.img_album_dialog_button_close); + closeButton.setBackground(ContextCompat.getDrawable(activityContext, R.drawable.album_dialog_ripple_effect_oval)); + closeButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (step == STEP.SELECT_PHOTO) { + if (getFullScreenDialog() != null) { + getFullScreenDialog().dismiss(); + } + } else { + step = STEP.SELECT_PHOTO; + tipView.setText(getDialogTipText()); + albumSelectView.setVisibility(View.VISIBLE); + otherAlbumSelectView.setVisibility(View.VISIBLE); + fullScreenDialog.setAllowInterceptTouch(true); + recyclerView.animate().x(0).setDuration(300).setInterpolator(new DecelerateInterpolator(2f)); + clipBox.animate().x(recyclerView.getWidth()).setDuration(300).setInterpolator(new DecelerateInterpolator(2f)); + okButton.setVisibility(maxSelectPhotoCount > 1 ? View.VISIBLE : View.INVISIBLE); + closeButton.setImageResource(R.mipmap.img_album_dialog_button_close); + + new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { + @Override + public void run() { + clipBox.setVisibility(View.GONE); + } + }, 300); + } + } + }); + albumSelectLayout.addView(closeButton, 0, new LinearLayout.LayoutParams(dip2px(35), dip2px(35))); + + albumSelectLayout.addView(new Space(activityContext), spaceLp); + + okButton = new ImageView(activityContext); + okButton.setPadding(dp2, dp2, dp2, dp2); + okButton.setImageTintList(ColorStateList.valueOf(activityContext.getResources().getColor(R.color.albumDefaultThemeDeep))); + okButton.setImageResource(R.mipmap.img_album_dialog_button_ok); + okButton.setBackground(ContextCompat.getDrawable(activityContext, R.drawable.album_dialog_ripple_effect_oval)); + okButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + onFinishSelectPhoto(selectedPhotos); + } + }); + albumSelectLayout.addView(okButton, new LinearLayout.LayoutParams(dip2px(35), dip2px(35))); + okButton.setVisibility(maxSelectPhotoCount > 1 ? View.VISIBLE : View.INVISIBLE); + } + LinearLayout.LayoutParams albumBoxSelectViewLp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dip2px(50)); + albumBoxSelectViewLp.bottomMargin = dip2px(10); + boxLayout.addView(albumSelectLayout, albumBoxSelectViewLp); + + contentLayout = new FrameLayout(activityContext); //内容布局 + + recyclerView = new ScrollableRecycleView(activityContext); //照片选择列表 + recyclerView.setLayoutManager(new GridLayoutManager(activityContext, previewPhotoMaxColum)); + photoGridSpacingItemDecoration = + new GridSpacingItemDecoration(previewPhotoMaxColum, previewPhotoMargin == null ? dip2px(1) : previewPhotoMargin, true); + recyclerView.addItemDecoration(photoGridSpacingItemDecoration); + recyclerView.setClipToPadding(false); + recyclerView.setTag("ScrollController"); + recyclerView.setAlpha(0f); + + // recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + // @Override + // public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { + // super.onScrollStateChanged(recyclerView, newState); + // switch (newState){ + // case SCROLL_STATE_SETTLING: + // Glide.with(recyclerView.getContext()).pauseRequests(); + // break; + // case SCROLL_STATE_IDLE: + // Glide.with(recyclerView.getContext()).resumeRequests(); + // break; + // } + // } + // }); + + contentLayout.addView(recyclerView); + boxLayout.addView(contentLayout); + + fullScreenDialog.setCustomView(new OnBindView(boxLayout) { + @Override + public void onBind(FullScreenDialog dialog, View v) { + dialog.getDialogImpl().setScrollView(recyclerView); + dialog.getDialogImpl().boxRoot.setOnSafeInsetsChangeListener(new OnSafeInsetsChangeListener() { + @Override + public void onChange(Rect unsafeRect) { + recyclerView.setPaddingRelative(0, 0, 0, unsafeRect.bottom); + } + }); + + loadPhotoList(activityContext); + } + }) + .setDialogLifecycleCallback(new DialogLifecycleCallback() { + @Override + public void onDismiss(FullScreenDialog dialog) { + super.onDismiss(dialog); + boxLayout = null; + tipView = null; + contentLayout = null; + recyclerView = null; + albumSelectView = null; + otherAlbumSelectView = null; + clipBox = null; + closeButton = null; + okButton = null; + fullScreenDialog = null; + PhotoAlbumDialog.this.activityContext = null; + } + }) + .setRadius(dip2px(15)) + .hideActivityContentView(true) + .setBottomNonSafetyAreaBySelf(true); + + getDialogDialogImplCallback().onDialogCreated(getFullScreenDialog()); + fullScreenDialog.setCancelable(true); + fullScreenDialog.show(activityContext); + } + } + + private Drawable getRippleBackgroundDrawable(Context context, int albumDialogBkgAlbumSelector) { + return new LayerDrawable(new Drawable[] {context.getResources().getDrawable(albumDialogBkgAlbumSelector), + ContextCompat.getDrawable(context, R.drawable.album_dialog_ripple_effect)}); + } + + private void loadAlbumList(Activity activityContext) { + recyclerView.animate().alpha(0f).withEndAction(new Runnable() { + @Override + public void run() { + photoGridSpacingItemDecoration.setSpanCount(2).setSpacing(-dip2px(10)); + recyclerView.setLayoutManager(new GridLayoutManager(activityContext, 2)); + AlbumAdapter albumAdapter = + new AlbumAdapter(activityContext, allAlbums, dip2px(230), errorPhotoDrawableRes, defaultSelectAlbumName) { + @Override + public void onChangeAlbum(String albumName) { + defaultSelectAlbumName = albumName; + albumSelectView.setText( + isNull(albumName) ? activityContext.getString(R.string.album_dialog_default_album_name) + : albumName); + albumSelectView.callOnClick(); + } + }; + recyclerView.setAdapter(albumAdapter); + + recyclerView.animate().alpha(1f).setDuration(100); + } + }).setDuration(100); + } + + private void loadPhotoList(Activity activityContext) { + if (!isNull(defaultSelectAlbumName)) { + defaultAlbumPhotos = getPhotosByAlbum(activityContext, defaultSelectAlbumName, sortBy, sortMode); + } + photoGridSpacingItemDecoration.setSpanCount(4).setSpacing(previewPhotoMargin == null ? dip2px(1) : previewPhotoMargin); + recyclerView.setLayoutManager(new GridLayoutManager(activityContext, previewPhotoMaxColum)); + PhotoAdapter adapter = + new PhotoAdapter(activityContext, defaultAlbumPhotos, previewPhotoHeight, errorPhotoDrawableRes, selectedPhotos) { + @Override + public boolean onSelectPhoto(String uri, List selectedPhotos, boolean add) { + if (add && selectedPhotos.size() == getMaxSelectPhotoCount() && (maxSelectPhotoCount <= 1)) { + onFinishSelectPhoto(selectedPhotos); + return false; + } + boolean flag = !(add && selectedPhotos.size() > getMaxSelectPhotoCount()); + if (!flag) { + tip(getErrorMaxSelectTipTextReal()); + } + return flag; + } + }; + recyclerView.setAdapter(adapter); + + recyclerView.animate().alpha(1f).setDuration(100); + } + + List clipViewList; + int clipIndex; + int selectedPhotosSize; + + private void onFinishSelectPhoto(List selectedPhotos) { + if (!clip) { + if (needResizePhotos()) { + WaitDialog.show(R.string.please_wait); + List resultPhotos = new ArrayList<>(); + + selectedPhotosSize = selectedPhotos.size(); + for (String uri : selectedPhotos) { + Glide.with(getContext()) + .asBitmap() + .load(uri) + .into(new SimpleTarget() { + @Override + public void onResourceReady(Bitmap bitmap, Transition transition) { + Bitmap result = resizeBitmap(bitmap); + + String filename = getRandomImageFileName(); + try (FileOutputStream out = new FileOutputStream(filename)) { + result.compress(compressPhoto ? Bitmap.CompressFormat.JPEG : Bitmap.CompressFormat.PNG, + compressQuality, out); + } catch (IOException e) { + e.printStackTrace(); + } + if (!isNull(fileProvider)) { + resultPhotos.add( + FileProvider.getUriForFile(getContext(), fileProvider, new File(filename)).toString()); + } else { + resultPhotos.add(new File(filename).getAbsolutePath()); + } + + if (resultPhotos.size() == selectedPhotosSize) { + WaitDialog.dismiss(); + callback(resultPhotos); + } + } + }); + } + } else { + callback(selectedPhotos); + } + } else { + if (getContext() == null) { + return; + } + if (step == STEP.SELECT_PHOTO) { + step = STEP.CLIP_PHOTO; + + clipBox = new LinearLayout(getContext()); //裁剪功能总布局 + clipBox.setOrientation(LinearLayout.VERTICAL); + clipBox.setVisibility(View.GONE); + + clipViewList = new ArrayList<>(); + LinearLayout preCutPhotoBox = new LinearLayout(getContext()); //待裁剪图片选择器 + preCutPhotoBox.setOrientation(LinearLayout.HORIZONTAL); + preCutPhotoBox.setGravity(Gravity.CENTER_VERTICAL); + FrameLayout clipPhotoBox = new FrameLayout(getContext()); + + LinearLayout.LayoutParams cLp = + new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + cLp.weight = 1; + clipBox.addView(clipPhotoBox, cLp); + + for (int index = 0; index < selectedPhotos.size(); index++) { + String uri = selectedPhotos.get(index); + ClipView clipView = new ClipView(getContext()); + clipView.setVisibility(index == clipIndex ? View.VISIBLE : View.GONE); + if (index == clipIndex) { + clipView.loadImage(uri); + } + + clipPhotoBox.addView(clipView, + new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + clipViewList.add(clipView); + + PhotoSelectImageView photoView = new PhotoSelectImageView(getContext()); //照片选择缩略图按钮 + int thumbnailSize = dip2px(60); + photoView.setTag(uri); + Glide.with(getContext()) + .load(uri) + .override(thumbnailSize) + .error(errorPhotoDrawableRes) + .into(photoView); + photoView.setRadius(dip2px(2)); + photoView.setBorderWidth((float) dip2px(2)); + photoView.setScaleType(ImageView.ScaleType.CENTER_CROP); + photoView.setSelectState(index == clipIndex); + photoView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + ((PhotoSelectImageView) preCutPhotoBox.getChildAt(clipIndex)).setSelectState(false); + if (clipIndex == preCutPhotoBox.indexOfChild(view)) { + return; + } + clipViewList.get(clipIndex).setVisibility(View.GONE); + clipIndex = preCutPhotoBox.indexOfChild(view); + clipViewList.get(clipIndex).setVisibility(View.VISIBLE); + clipViewList.get(clipIndex).loadImage(uri); + ((PhotoSelectImageView) preCutPhotoBox.getChildAt(clipIndex)).setSelectState(true); + } + }); + LinearLayout.LayoutParams pLp = new LinearLayout.LayoutParams(thumbnailSize, thumbnailSize); + pLp.rightMargin = dip2px(5); + preCutPhotoBox.addView(photoView, pLp); + } + + if (selectedPhotos.size() > 1) { + HorizontalScrollView selectorScrollView = new HorizontalScrollView(getContext()); //待裁剪图片选择器滚动布局 + selectorScrollView.setOverScrollMode(HorizontalScrollView.OVER_SCROLL_NEVER); + selectorScrollView.addView(preCutPhotoBox, + new HorizontalScrollView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, dip2px(70))); + selectorScrollView.setHorizontalFadingEdgeEnabled(true); + selectorScrollView.setHorizontalScrollBarEnabled(false); + LinearLayout.LayoutParams sLp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, dip2px(70)); + sLp.leftMargin = dip2px(10); + sLp.rightMargin = dip2px(10); + sLp.bottomMargin = getFullScreenDialog().getDialogImpl().boxRoot.getUnsafePlace().bottom + dip2px(5); + clipBox.addView(selectorScrollView, sLp); + } + contentLayout.addView(clipBox, + new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + clipBox.setX(recyclerView.getWidth()); + clipBox.setVisibility(View.VISIBLE); + recyclerView.animate().x(-recyclerView.getWidth()).setDuration(300).setInterpolator(new DecelerateInterpolator(2f)); + clipBox.animate().x(0).setDuration(300).setInterpolator(new DecelerateInterpolator(2f)); + okButton.setVisibility(View.VISIBLE); + + tipView.setText(getClipTipText()); + albumSelectView.setVisibility(View.GONE); + otherAlbumSelectView.setVisibility(View.GONE); + fullScreenDialog.setAllowInterceptTouch(false); + closeButton.setImageResource(R.mipmap.img_album_dialog_button_back); + } else { + if (selectedPhotos.size() > 1) { + WaitDialog.show(R.string.please_wait); + new Thread() { + @Override + public void run() { + super.run(); + List resultPhotos = new ArrayList<>(); + for (int i = 0; i < clipViewList.size(); i++) { + ClipView clipView = clipViewList.get(i); + if (clipView.getBitmap() == null) { + WaitDialog.dismiss(); + tip(String.format(getString(R.string.album_dialog_error_not_clip_photo), String.valueOf(i + 1))); + return; + } + Bitmap result = clipView.clip(); + result = resizeBitmap(result); + String filename = getRandomImageFileName(); + try (FileOutputStream out = new FileOutputStream(filename)) { + result.compress(compressPhoto ? Bitmap.CompressFormat.JPEG : Bitmap.CompressFormat.PNG, compressQuality, + out); + } catch (IOException e) { + e.printStackTrace(); + } + if (!isNull(fileProvider)) { + resultPhotos.add(FileProvider.getUriForFile(getContext(), fileProvider, new File(filename)).toString()); + } else { + resultPhotos.add(new File(filename).getAbsolutePath()); + } + } + WaitDialog.dismiss(); + callback(resultPhotos); + } + }.start(); + } else { + List resultPhotos = new ArrayList<>(); + ClipView clipView = clipViewList.get(0); + Bitmap result = clipView.clip(); + result = resizeBitmap(result); + String filename = getRandomImageFileName(); + try (FileOutputStream out = new FileOutputStream(filename)) { + result.compress(compressPhoto ? Bitmap.CompressFormat.JPEG : Bitmap.CompressFormat.PNG, compressQuality, out); + } catch (IOException e) { + e.printStackTrace(); + } + if (!isNull(fileProvider)) { + resultPhotos.add(FileProvider.getUriForFile(getContext(), fileProvider, new File(filename)).toString()); + } else { + resultPhotos.add(new File(filename).getAbsolutePath()); + } + callback(resultPhotos); + } + } + } + } + + private boolean needResizePhotos() { + return getMaxHeight() != 0 || getMaxWidth() != 0; + } + + private Bitmap resizeBitmap(Bitmap originBitmap) { + if (!needResizePhotos()) { + return originBitmap; + } + int width = originBitmap.getWidth(); + int height = originBitmap.getHeight(); + + float scaleWidth = ((float) maxWidth) / width; + float scaleHeight = ((float) maxHeight) / height; + float scaleFactor = min(scaleWidth, scaleHeight); + + Matrix matrix = new Matrix(); + matrix.postScale(scaleFactor, scaleFactor); + Bitmap resizedBitmap = Bitmap.createBitmap(originBitmap, 0, 0, width, height, matrix, true); + // if (resizedBitmap != originBitmap) { + // originBitmap.recycle(); + // } + return resizedBitmap; + } + + private float min(float scaleWidth, float scaleHeight) { + return (scaleWidth == 0 || scaleHeight == 0) ? Math.max(scaleWidth, scaleHeight) : Math.min(scaleWidth, scaleHeight); + } + + private void callback(List selectedPhotos) { + if (getCallback() != null) { + if (selectedPhotos.size() == 1) { + getCallback().selectedPhoto(selectedPhotos.get(0)); + } + getCallback().selectedPhotos(selectedPhotos); + } + if (getFullScreenDialog() != null) { + getFullScreenDialog().dismiss(); + } + } + + private String getRandomImageFileName() { + String folderName = getContext().getCacheDir().getAbsolutePath() + File.separator + "KongzuePhotoAlbumDialog" + File.separator; + File folder = new File(folderName); + if (!folder.exists()) { + folder.mkdirs(); + } + return folderName + ((int) (Math.random() * 1000000)) + (compressPhoto ? ".jpg" : ".png"); + } + + private boolean checkPermission(Activity activityContext) { + XXPermissions permissions = XXPermissions.with(activityContext); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + if (XXPermissions.isGranted(activityContext, Permission.READ_MEDIA_IMAGES)) { + return true; + } else { + permissions.permission(Permission.READ_MEDIA_IMAGES); + permissions.request(new OnPermissionCallback() { + + @Override + public void onGranted(@NonNull List permissions, boolean allGranted) { + if (!allGranted) { + showToast("获取部分权限成功,但部分权限未正常授予"); + } + } + + @Override + public void onDenied(@NonNull List permissions, boolean doNotAskAgain) { + if (doNotAskAgain) { + showToast("被永久拒绝授权,请手动授予权限"); + XXPermissions.startPermissionActivity(activityContext, permissions); + } else { + showToast("获取权限失败"); + } + } + }); + return false; + } + } else { + if (XXPermissions.isGranted(activityContext, Permission.MANAGE_EXTERNAL_STORAGE)) { + return true; + } else { + permissions.permission(Permission.MANAGE_EXTERNAL_STORAGE); + permissions.request(new OnPermissionCallback() { + + @Override + public void onGranted(@NonNull List permissions, boolean allGranted) { + if (!allGranted) { + showToast("获取部分权限成功,但部分权限未正常授予"); + } + } + + @Override + public void onDenied(@NonNull List permissions, boolean doNotAskAgain) { + if (doNotAskAgain) { + showToast("被永久拒绝授权,请手动授予权限"); + XXPermissions.startPermissionActivity(activityContext, permissions); + } else { + showToast("获取权限失败"); + } + } + }); + return false; + } + } + } + + public PhotoAlbumDialog setDialogDialogImplCallback(DialogImplCallback dialogDialogImplCallback) { + this.dialogDialogImplCallback = dialogDialogImplCallback; + return this; + } + + public DialogImplCallback getDialogDialogImplCallback() { + return dialogDialogImplCallback == null ? new DialogImplCallback() { + @Override + public void onDialogCreated(FullScreenDialog dialog) { + + } + } : dialogDialogImplCallback; + } + + public SORT_MODE getSortMode() { + return sortMode; + } + + public PhotoAlbumDialog setSortMode(SORT_MODE sortMode) { + this.sortMode = sortMode; + return this; + } + + public String getSortBy() { + return sortBy; + } + + public PhotoAlbumDialog setSortBy(String sortBy) { + this.sortBy = sortBy; + return this; + } + + public String getDefaultSelectAlbumName() { + return defaultSelectAlbumName; + } + + public PhotoAlbumDialog setDefaultSelectAlbumName(String defaultSelectAlbumName) { + this.defaultSelectAlbumName = defaultSelectAlbumName; + return this; + } + + public int getPreviewPhotoMaxColum() { + return previewPhotoMaxColum; + } + + public PhotoAlbumDialog setPreviewPhotoMaxColum(int previewPhotoMaxColum) { + this.previewPhotoMaxColum = previewPhotoMaxColum; + return this; + } + + public Integer getPreviewPhotoMargin() { + return previewPhotoMargin; + } + + public PhotoAlbumDialog setPreviewPhotoMargin(Integer previewPhotoMargin) { + this.previewPhotoMargin = previewPhotoMargin; + return this; + } + + public Integer getPreviewPhotoHeight() { + return previewPhotoHeight; + } + + public PhotoAlbumDialog setPreviewPhotoHeight(Integer previewPhotoHeight) { + this.previewPhotoHeight = previewPhotoHeight; + return this; + } + + public int getErrorPhotoDrawableRes() { + return errorPhotoDrawableRes; + } + + public PhotoAlbumDialog setErrorPhotoDrawableRes(int errorPhotoDrawableRes) { + this.errorPhotoDrawableRes = errorPhotoDrawableRes; + return this; + } + + public String getDialogTipText() { + String temp; + if (dialogTipText == null) { + temp = getString(R.string.album_dialog_default_select_tip); + } else { + temp = dialogTipText; + } + return temp; + } + + public PhotoAlbumDialog setDialogTipText(String dialogTipText) { + this.dialogTipText = dialogTipText; + return this; + } + + public List getSelectedPhotos() { + return selectedPhotos; + } + + public PhotoAlbumDialog setSelectedPhotos(List selectedPhotos) { + this.selectedPhotos = selectedPhotos; + return this; + } + + public FullScreenDialog getFullScreenDialog() { + return fullScreenDialog; + } + + public PhotoAlbumDialog setFullScreenDialog(FullScreenDialog fullScreenDialog) { + this.fullScreenDialog = fullScreenDialog; + return this; + } + + public SelectPhotoCallback getCallback() { + return callback; + } + + public PhotoAlbumDialog setCallback(SelectPhotoCallback callback) { + this.callback = callback; + return this; + } + + private int getScreenWidth(Context context) { + WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + DisplayMetrics metrics = new DisplayMetrics(); + windowManager.getDefaultDisplay().getMetrics(metrics); + return metrics.widthPixels; + } + + private int dip2px(float dpValue) { + return (int) (0.5f + dpValue * Resources.getSystem().getDisplayMetrics().density); + } + + public int getMaxSelectPhotoCount() { + return Math.max(maxSelectPhotoCount, 1); + } + + private String getErrorMaxSelectTipTextReal() { + String temp; + if (errorMaxSelectTipText == null) { + temp = getString(R.string.album_dialog_error_select_photo_max_tip); + } else { + temp = errorMaxSelectTipText; + } + if (temp.contains("%s")) { + return String.format(temp, String.valueOf(getMaxSelectPhotoCount())); + } + return temp; + } + + private String getString(int resId) { + if (getFullScreenDialog() == null || getFullScreenDialog().getOwnActivity() == null) { + return ""; + } + return getFullScreenDialog().getOwnActivity().getString(resId); + } + + public String getErrorMaxSelectTipText() { + return errorMaxSelectTipText; + } + + public PhotoAlbumDialog setErrorMaxSelectTipText(String errorMaxSelectTipText) { + this.errorMaxSelectTipText = errorMaxSelectTipText; + return this; + } + + public PhotoAlbumDialog setMaxSelectPhotoCount(int maxSelectPhotoCount) { + this.maxSelectPhotoCount = maxSelectPhotoCount; + return this; + } + + public boolean isClip() { + return clip; + } + + public PhotoAlbumDialog setClip(boolean clip) { + this.clip = clip; + return this; + } + + public String getClipTipText() { + String temp; + if (clipTipText == null) { + temp = getString(R.string.album_dialog_default_clip_tip); + } else { + temp = clipTipText; + } + return temp; + } + + public PhotoAlbumDialog setClipTipText(String clipTipText) { + this.clipTipText = clipTipText; + return this; + } + + private Context getContext() { + return activityContext == null ? BaseDialog.getApplicationContext() : activityContext; + } + + public boolean isCompressPhoto() { + return compressPhoto; + } + + public PhotoAlbumDialog setCompressPhoto(boolean compressPhoto) { + this.compressPhoto = compressPhoto; + return this; + } + + public int getCompressQuality() { + return compressQuality; + } + + public PhotoAlbumDialog setCompressQuality(int compressQuality) { + setCompressPhoto(true); + this.compressQuality = compressQuality; + return this; + } + + public int getMaxWidth() { + return maxWidth; + } + + public PhotoAlbumDialog setMaxWidth(int maxWidth) { + this.maxWidth = maxWidth; + return this; + } + + public int getMaxHeight() { + return maxHeight; + } + + public PhotoAlbumDialog setMaxHeight(int maxHeight) { + this.maxHeight = maxHeight; + return this; + } + + public PhotoAlbumDialog setMaxSize(int maxSize) { + this.maxHeight = maxSize; + this.maxWidth = maxSize; + return this; + } + + private void showToast(String str) { + Toast.makeText(activityContext, str, Toast.LENGTH_LONG).show(); + } +} diff --git a/AlbumDialog/src/main/java/com/kongzue/albumdialog/util/AlbumAdapter.java b/AlbumDialog/src/main/java/com/kongzue/albumdialog/util/AlbumAdapter.java new file mode 100644 index 0000000..011e6fd --- /dev/null +++ b/AlbumDialog/src/main/java/com/kongzue/albumdialog/util/AlbumAdapter.java @@ -0,0 +1,127 @@ +package com.kongzue.albumdialog.util; + +import static com.kongzue.albumdialog.util.AlbumUtil.getLatestPhotoFromAlbum; +import static com.kongzue.dialogx.interfaces.BaseDialog.isNull; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +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.engine.GlideException; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; +import com.kongzue.albumdialog.R; +import com.kongzue.albumdialog.views.PhotoSelectImageView; + +import java.util.List; + +public class AlbumAdapter extends RecyclerView.Adapter { + + private Context context; + private List albumNames; + private int layoutHeight; + private int errorPhotoDrawableRes; + private String selectedAlbum; + + public AlbumAdapter(Context context, List albumNames, int layoutHeight, int errorPhotoDrawableRes, String selectedAlbum) { + this.context = context; + this.albumNames = albumNames; + this.layoutHeight = layoutHeight; + this.errorPhotoDrawableRes = errorPhotoDrawableRes; + this.selectedAlbum = selectedAlbum; + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + LinearLayout albumView = new LinearLayout(context); + albumView.setOrientation(LinearLayout.VERTICAL); + albumView.setPadding(dip2px(10), 0, dip2px(10), dip2px(10)); + albumView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, layoutHeight)); + + PhotoSelectImageView albumImageView = new PhotoSelectImageView(context); + albumImageView.setRadius(dip2px(5)); + albumImageView.setScaleType(ImageView.ScaleType.CENTER_CROP); + LinearLayout.LayoutParams albumImageViewLp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + albumImageViewLp.weight = 1; + albumView.addView(albumImageView, albumImageViewLp); + + TextView labelView = new TextView(context); + labelView.setTextColor(context.getResources().getColor(R.color.albumDefaultLabelColor)); + labelView.setGravity(Gravity.CENTER); + labelView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + labelView.setPadding(dip2px(15), dip2px(5), dip2px(15), dip2px(15)); + albumView.addView(labelView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + + return new ViewHolder(albumView); + } + + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + Glide.with(context) + .load(getLatestPhotoFromAlbum(context, albumNames.get(position))) + .override(layoutHeight) + .error(errorPhotoDrawableRes) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + holder.itemView.setTag(null); + return false; + } + + @Override + public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + return false; + } + }) + .into(holder.albumImageView); + holder.albumImageView.setSelectState(albumNames.get(position).equals(selectedAlbum) || (isNull(selectedAlbum) && position == 0)); + holder.itemView.setTag(albumNames.get(position)); + holder.albumLabelView.setText(albumNames.get(position)); + + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + onChangeAlbum((String) v.getTag()); + } + }); + } + + public void onChangeAlbum(String albumName) { + + } + + @Override + public int getItemCount() { + return albumNames.size(); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + + LinearLayout itemView; + PhotoSelectImageView albumImageView; + TextView albumLabelView; + + public ViewHolder(LinearLayout itemView) { + super(itemView); + this.itemView = itemView; + albumImageView = (PhotoSelectImageView) itemView.getChildAt(0); + albumLabelView = (TextView) itemView.getChildAt(1); + } + } + + private int dip2px(float dpValue) { + return (int) (0.5f + dpValue * Resources.getSystem().getDisplayMetrics().density); + } +} diff --git a/AlbumDialog/src/main/java/com/kongzue/albumdialog/util/AlbumUtil.java b/AlbumDialog/src/main/java/com/kongzue/albumdialog/util/AlbumUtil.java new file mode 100644 index 0000000..75b6a88 --- /dev/null +++ b/AlbumDialog/src/main/java/com/kongzue/albumdialog/util/AlbumUtil.java @@ -0,0 +1,119 @@ +package com.kongzue.albumdialog.util; + +import static com.kongzue.dialogx.interfaces.BaseDialog.isNull; + +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.provider.MediaStore; + +import com.kongzue.albumdialog.PhotoAlbumDialog; +import com.kongzue.albumdialog.R; + +import java.util.ArrayList; +import java.util.List; + +public class AlbumUtil { + public static List getAllAlbums(Context context) { + List albums = new ArrayList<>(); + String[] projection = new String[]{ + MediaStore.Images.Media.BUCKET_DISPLAY_NAME, + MediaStore.Images.Media.BUCKET_ID + }; + + Uri images = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + Cursor cur = context.getContentResolver().query(images, + projection, // Which columns to return + null, // Which rows to return (all rows) + null, // Selection arguments (none) + null // Ordering + ); + + if (cur != null && cur.moveToFirst()) { + int bucketColumn = cur.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME); + + do { + String albumName = cur.getString(bucketColumn); + if (!albums.contains(albumName) && !isNull(albumName)) albums.add(albumName); + } while (cur.moveToNext()); + } + + if (cur != null) { + cur.close(); + } + + return albums; + } + + public static List getPhotosByAlbum(Context context, String albumName, String sortBy, PhotoAlbumDialog.SORT_MODE sortMode) { + List photos = new ArrayList<>(); + Uri images = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + String[] projection = new String[]{ + MediaStore.Images.Media.DATA, // 图片的文件路径 + MediaStore.Images.Media.DATE_ADDED // 图片的拍摄日期 + }; + String selection; + String[] selectionArgs; + if (isNull(albumName) || context.getString(R.string.album_dialog_default_album_name).equals(albumName)) { + selection = null; + selectionArgs = null; + } else { + selection = MediaStore.Images.Media.BUCKET_DISPLAY_NAME + " = ?"; + selectionArgs = new String[]{albumName}; + } + String sortOrder = sortBy + " " + sortMode.name(); + Cursor cur = context.getContentResolver().query(images, + projection, + selection, + selectionArgs, + sortOrder); + + if (cur != null && cur.moveToFirst()) { + int dataColumn = cur.getColumnIndex(MediaStore.Images.Media.DATA); + do { + String photoPath = cur.getString(dataColumn); + photos.add(photoPath); + } while (cur.moveToNext()); + } + + if (cur != null) { + cur.close(); + } + + return photos; + } + + public static String getLatestPhotoFromAlbum(Context context, String albumName) { + Uri imagesUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + String[] projection = new String[]{ + MediaStore.Images.Media.DATA, // 图片的文件路径 + MediaStore.Images.Media.DATE_ADDED // 图片的拍摄日期 + }; + String selection; + String[] selectionArgs; + if (isNull(albumName) || context.getString(R.string.album_dialog_default_album_name).equals(albumName)) { + selection = null; + selectionArgs = null; + } else { + selection = MediaStore.Images.Media.BUCKET_DISPLAY_NAME + " = ?"; + selectionArgs = new String[]{albumName}; + } + + String sortOrder = MediaStore.Images.Media.DATE_ADDED + " DESC"; // 按日期降序排序 + + try (Cursor cursor = context.getContentResolver().query( + imagesUri, + projection, + selection, + selectionArgs, + sortOrder)) { + if (cursor != null && cursor.moveToFirst()) { + // 获取最新一张照片的文件路径 + return cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; // 没有找到照片或出现异常 + } +} diff --git a/AlbumDialog/src/main/java/com/kongzue/albumdialog/util/DialogImplCallback.java b/AlbumDialog/src/main/java/com/kongzue/albumdialog/util/DialogImplCallback.java new file mode 100644 index 0000000..80cb5bf --- /dev/null +++ b/AlbumDialog/src/main/java/com/kongzue/albumdialog/util/DialogImplCallback.java @@ -0,0 +1,7 @@ +package com.kongzue.albumdialog.util; + +import com.kongzue.dialogx.interfaces.BaseDialog; + +public interface DialogImplCallback { + void onDialogCreated(D dialog); +} diff --git a/AlbumDialog/src/main/java/com/kongzue/albumdialog/util/GridSpacingItemDecoration.java b/AlbumDialog/src/main/java/com/kongzue/albumdialog/util/GridSpacingItemDecoration.java new file mode 100644 index 0000000..e8bb3b2 --- /dev/null +++ b/AlbumDialog/src/main/java/com/kongzue/albumdialog/util/GridSpacingItemDecoration.java @@ -0,0 +1,49 @@ +package com.kongzue.albumdialog.util; + +import android.graphics.Rect; +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; + +public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration { + + private int spanCount; + private int spacing; + + public int getSpanCount() { + return spanCount; + } + + public GridSpacingItemDecoration setSpanCount(int spanCount) { + this.spanCount = spanCount; + return this; + } + + public int getSpacing() { + return spacing; + } + + public GridSpacingItemDecoration setSpacing(int spacing) { + this.spacing = spacing; + return this; + } + + public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) { + this.spanCount = spanCount; + this.spacing = spacing; + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + int position = parent.getChildAdapterPosition(view); + int column = position % spanCount; + + if (column >= 1) { + outRect.left = spacing; + } + + if (position >= spanCount) { + outRect.top = spacing; + } + } +} diff --git a/AlbumDialog/src/main/java/com/kongzue/albumdialog/util/PhotoAdapter.java b/AlbumDialog/src/main/java/com/kongzue/albumdialog/util/PhotoAdapter.java new file mode 100644 index 0000000..b04920f --- /dev/null +++ b/AlbumDialog/src/main/java/com/kongzue/albumdialog/util/PhotoAdapter.java @@ -0,0 +1,111 @@ +package com.kongzue.albumdialog.util; + +import static com.kongzue.dialogx.interfaces.BaseDialog.isNull; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +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.engine.GlideException; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.target.Target; +import com.kongzue.albumdialog.views.PhotoSelectImageView; + +import java.util.List; + +public class PhotoAdapter extends RecyclerView.Adapter { + + private Context context; + private List imageUrls; // 图片的 URL 列表 + private int imageSize; + private int errorPhotoDrawableRes; + private List selectedPhotos; + + public PhotoAdapter(Context context, List imageUrls, int imageSize, int errorPhotoDrawableRes, List selectedPhotos) { + this.context = context; + this.imageUrls = imageUrls; + this.imageSize = imageSize; + this.selectedPhotos = selectedPhotos; + this.errorPhotoDrawableRes = errorPhotoDrawableRes; + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + PhotoSelectImageView imageView = new PhotoSelectImageView(context); + imageView.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + imageSize + )); + imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); + return new ViewHolder(imageView); + } + + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + Glide.with(context) + .load(imageUrls.get(position)) + .override(imageSize) + .error(errorPhotoDrawableRes) + .listener(new RequestListener() { + @Override + public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { + holder.itemView.setTag(null); + return false; + } + + @Override + public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { + return false; + } + }) + .into((PhotoSelectImageView) holder.itemView); + holder.itemView.setTag(imageUrls.get(position)); + ((PhotoSelectImageView) holder.itemView).setSelectState(selectedPhotos.contains(imageUrls.get(position))); + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + String uri = (String) v.getTag(); + + if (isNull(uri)) return; + if (selectedPhotos.contains(uri)) { + selectedPhotos.remove(uri); + ((PhotoSelectImageView) holder.itemView).setSelectState(false); + if (!onSelectPhoto(uri, selectedPhotos, false)){ + selectedPhotos.add(uri); + ((PhotoSelectImageView) holder.itemView).setSelectState(true); + } + } else { + selectedPhotos.add(uri); + ((PhotoSelectImageView) holder.itemView).setSelectState(true); + if (!onSelectPhoto(uri, selectedPhotos, true)){ + selectedPhotos.remove(uri); + ((PhotoSelectImageView) holder.itemView).setSelectState(false); + } + } + } + }); + } + + public boolean onSelectPhoto(String uri, List selectedPhotos, boolean add) { + return true; + } + + @Override + public int getItemCount() { + return imageUrls.size(); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + public ViewHolder(ImageView itemView) { + super(itemView); + } + } +} diff --git a/AlbumDialog/src/main/java/com/kongzue/albumdialog/util/SelectPhotoCallback.java b/AlbumDialog/src/main/java/com/kongzue/albumdialog/util/SelectPhotoCallback.java new file mode 100644 index 0000000..a4b2e3a --- /dev/null +++ b/AlbumDialog/src/main/java/com/kongzue/albumdialog/util/SelectPhotoCallback.java @@ -0,0 +1,10 @@ +package com.kongzue.albumdialog.util; + +import java.util.List; + +public abstract class SelectPhotoCallback { + + public void selectedPhoto(String selectedPhotos){} + + public void selectedPhotos(List selectedPhotos){} +} diff --git a/AlbumDialog/src/main/java/com/kongzue/albumdialog/views/PhotoSelectImageView.java b/AlbumDialog/src/main/java/com/kongzue/albumdialog/views/PhotoSelectImageView.java new file mode 100644 index 0000000..fbb0f9d --- /dev/null +++ b/AlbumDialog/src/main/java/com/kongzue/albumdialog/views/PhotoSelectImageView.java @@ -0,0 +1,136 @@ +package com.kongzue.albumdialog.views; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Outline; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.Rect; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewOutlineProvider; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.kongzue.albumdialog.R; + +public class PhotoSelectImageView extends androidx.appcompat.widget.AppCompatImageView { + + private Bitmap selectFlagBitmap; + private Rect selectFlagRect; + private int borderColor; + private Float borderWidth; + private Paint paint; + + boolean selected; + + public PhotoSelectImageView(@NonNull Context context) { + super(context); + init(); + } + + public PhotoSelectImageView(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(); + } + + public PhotoSelectImageView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + private void init() { + if (paint == null) { + borderColor = getResources().getColor(R.color.albumDefaultThemeDeep); + paint = new Paint(); + paint.setAntiAlias(true); + paint.setColor(borderColor); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeWidth(getBorderWidth()); + + selectFlagRect = new Rect((int) (getBorderWidth()), (int) (getBorderWidth()), dip2px(30), dip2px(30)); + selectFlagBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.album_dialog_img_selected); + + Bitmap tintedBitmap = Bitmap.createBitmap(selectFlagBitmap.getWidth(), selectFlagBitmap.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(tintedBitmap); + Paint paint = new Paint(); + paint.setColorFilter(new PorterDuffColorFilter(getResources().getColor(R.color.albumDefaultThemeDeep), PorterDuff.Mode.SRC_IN)); + + Paint backgroundPaint = new Paint(); + backgroundPaint.setColor(Color.WHITE); + backgroundPaint.setStyle(Paint.Style.FILL); + canvas.drawCircle(selectFlagBitmap.getWidth() / 2, selectFlagBitmap.getHeight() / 2, selectFlagBitmap.getWidth() / 3, backgroundPaint); + canvas.drawBitmap(selectFlagBitmap, 0, 0, paint); + selectFlagBitmap = tintedBitmap; + } + } + + private float getBorderWidth() { + return borderWidth == null ? dip2px(4) : borderWidth; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (selected) { + if (radius == 0) { + canvas.drawRect(0 + getBorderWidth() / 2, 0 + getBorderWidth() / 2, getWidth() - getBorderWidth() / 2, getHeight() - getBorderWidth() / 2, paint); + } else { + RectF rect = new RectF(0 + getBorderWidth() / 2, 0 + getBorderWidth() / 2, getWidth() - getBorderWidth() / 2, getHeight() - getBorderWidth() / 2); + canvas.drawRoundRect(rect, radius, radius, paint); + } + canvas.drawBitmap(selectFlagBitmap, null, selectFlagRect, paint); + } + } + + @Override + public boolean isSelected() { + return selected; + } + + public PhotoSelectImageView setSelectState(boolean selected) { + this.selected = selected; + if (selected) { + setPadding((int) getBorderWidth(), (int) getBorderWidth(), (int) getBorderWidth(), (int) getBorderWidth()); + } else { + setPadding(0, 0, 0, 0); + } + invalidate(); + return this; + } + + private int dip2px(float dpValue) { + return (int) (0.5f + dpValue * Resources.getSystem().getDisplayMetrics().density); + } + + int radius; + + public void setRadius(int r) { + setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), r); + } + }); + setClipToOutline(true); + radius = r; + invalidate(); + } + + public PhotoSelectImageView setBorderColor(int borderColor) { + this.borderColor = borderColor; + return this; + } + + public PhotoSelectImageView setBorderWidth(Float borderWidth) { + this.borderWidth = borderWidth; + return this; + } +} diff --git a/AlbumDialog/src/main/java/com/kongzue/albumdialog/views/ScrollableRecycleView.java b/AlbumDialog/src/main/java/com/kongzue/albumdialog/views/ScrollableRecycleView.java new file mode 100644 index 0000000..603bfec --- /dev/null +++ b/AlbumDialog/src/main/java/com/kongzue/albumdialog/views/ScrollableRecycleView.java @@ -0,0 +1,80 @@ +package com.kongzue.albumdialog.views; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.kongzue.dialogx.interfaces.ScrollController; + +public class ScrollableRecycleView extends RecyclerView implements ScrollController { + public ScrollableRecycleView(@NonNull Context context) { + super(context); + } + + public ScrollableRecycleView(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + public ScrollableRecycleView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + /** + * 滑动锁定判断依据,若此标记被置为 true,则意味着滑动由父布局处理,请勿进行任何滚动操作。 + * 具体请参考 {@link #onTouchEvent(MotionEvent)} 的处理方案,其他诸如 ScrollView 处理方式相同。 + */ + boolean lockScroll; + + @Override + public boolean isLockScroll() { + return lockScroll; + } + + @Override + public void lockScroll(boolean lockScroll) { + this.lockScroll = lockScroll; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + if (lockScroll) { + return false; + } + return super.onTouchEvent(ev); + } + + /** + * 是否可以滑动判断依据,若当前滑动布局内容高度小于布局高度则为不可滑动。 + * 此处列举的是 RecycleView 的判断依据编写方法, + * ScrollView 的范例请参考 {@link com.kongzue.dialogx.util.views.BottomDialogScrollView#isCanScroll()} + * + * @return 是否可滑动 + */ + @Override + public boolean isCanScroll() { + return canScrollVertically(1) || canScrollVertically(-1); + } + + /** + * 此处请给出已滑动距离值,BottomDialog 需要根据此值判断当子布局滑动过程中,父布局是否需要介入滑动流程。 + * 此处列举的是 RecycleView 的判断依据编写方法, + * ScrollView 的范例请参考 {@link com.kongzue.dialogx.util.views.BottomDialogScrollView#getScrollDistance()} + * + * @return 已滑动距离 + */ + public int getScrollDistance() { + GridLayoutManager layoutManager = (GridLayoutManager) getLayoutManager(); + View firstVisibleItem = this.getChildAt(0); + int firstItemPosition = layoutManager.findFirstVisibleItemPosition(); + int itemHeight = firstVisibleItem.getHeight(); + int firstItemBottom = layoutManager.getDecoratedBottom(firstVisibleItem); + return (firstItemPosition + 1) * itemHeight - firstItemBottom; + } +} diff --git a/AlbumDialog/src/main/java/com/kongzue/albumdialog/views/crop/ClipImageBorderView.java b/AlbumDialog/src/main/java/com/kongzue/albumdialog/views/crop/ClipImageBorderView.java new file mode 100644 index 0000000..08201c5 --- /dev/null +++ b/AlbumDialog/src/main/java/com/kongzue/albumdialog/views/crop/ClipImageBorderView.java @@ -0,0 +1,134 @@ +package com.kongzue.albumdialog.views.crop; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.View; + +/** + * 中间显示的正方形框 + */ +public class ClipImageBorderView extends View { + public static int xxx; + public static int yyy; + + public static boolean isshowline = false; + + /** + * 水平方向与View的边距 + */ + public static int mHorizontalPadding = 0; + /** + * 垂直方向与View的边距 + */ + public static int mVerticalPadding = 0; + /** + * 绘制的矩形的宽度 + */ + public static int mWidth = 0; + public static int mHeight = 0; + /** + * 边框的颜色,默认为白色 + */ + private int mBorderColor = Color.parseColor("#FFFFFF"); + /** + * 边框的宽度 单位dp + */ + private int mBorderWidth = 1; + + private Paint mPaint; + + public ClipImageBorderView(Context context) { + this(context, null); + } + + public ClipImageBorderView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ClipImageBorderView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + mBorderWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mBorderWidth, getResources().getDisplayMetrics()); + mPaint = new Paint(); + mPaint.setAntiAlias(true); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + // 计算距离屏幕垂直边界 的边距 + mWidth = getWidth() - 2 * mHorizontalPadding; + mVerticalPadding = (int) ((getHeight() - mWidth * getAspectRatio()) / 2.0); //白描模式矩形高宽比例1.22 + mHeight = getHeight() - mVerticalPadding * 2; + + mPaint.setColor(0xE6ffffff); + mPaint.setStyle(Paint.Style.FILL); + // 绘制左边1,阴影效果 + canvas.drawRect(0, 0, mHorizontalPadding, getHeight(), mPaint); + // 绘制右边2 + canvas.drawRect(getWidth() - mHorizontalPadding, 0, getWidth(), + getHeight(), mPaint); + // 绘制上边3 + canvas.drawRect(mHorizontalPadding, 0, getWidth() - mHorizontalPadding, mVerticalPadding, mPaint); + // 绘制下边4 + canvas.drawRect(mHorizontalPadding, getHeight() - mVerticalPadding, getWidth() - mHorizontalPadding, getHeight(), mPaint); + // 绘制外边框 + mPaint.setColor(mBorderColor); + mPaint.setStrokeWidth(mBorderWidth + 5); + mPaint.setStyle(Paint.Style.STROKE); + canvas.drawRect(mHorizontalPadding, mVerticalPadding, getWidth() - mHorizontalPadding, getHeight() - mVerticalPadding, mPaint); + xxx = getWidth() / 2; + yyy = mVerticalPadding + mWidth / 2; + } + + public void showline(Canvas canvas) { + // 得到网格坐标参数 + float upStart_x1, upStart_y1, upStart_x2, upStart_y2; + float downStart_x1, downStart_y1, downStart_x2, downStart_y2; + float leftStart_x1, leftStart_y1, leftStart_x2, leftStart_y2; + float rightStart_x1, rightStart_y1, rightStart_x2, rightStart_y2; + + //上沿两个点的坐标 + upStart_x1 = mWidth / 3 + mHorizontalPadding; + upStart_y1 = mVerticalPadding; + upStart_x2 = mWidth / 3 * 2 + mHorizontalPadding; + upStart_y2 = mVerticalPadding; + + //下沿两个点的坐标 + downStart_x1 = mWidth / 3 + mHorizontalPadding; + downStart_y1 = getHeight() - mVerticalPadding; + downStart_x2 = mWidth / 3 * 2 + mHorizontalPadding; + downStart_y2 = getHeight() - mVerticalPadding; + + // 左边两个点的坐标 + leftStart_x1 = mHorizontalPadding; + leftStart_y1 = mVerticalPadding + mHeight / 3; + leftStart_x2 = mHorizontalPadding; + leftStart_y2 = mVerticalPadding + mHeight / 3 * 2; + + // 右边两个点的坐标 + rightStart_x1 = mHorizontalPadding + mWidth; + rightStart_y1 = mVerticalPadding + mHeight / 3; + rightStart_x2 = mHorizontalPadding + mWidth; + rightStart_y2 = mVerticalPadding + mHeight / 3 * 2; + + // 绘制网格 + mPaint.setStrokeWidth(mBorderWidth); + canvas.drawLine(upStart_x1, upStart_y1, downStart_x1, downStart_y1, mPaint); + canvas.drawLine(upStart_x2, upStart_y2, downStart_x2, downStart_y2, mPaint); + canvas.drawLine(leftStart_x1, leftStart_y1, rightStart_x1, rightStart_y1, mPaint); + canvas.drawLine(leftStart_x2, leftStart_y2, rightStart_x2, rightStart_y2, mPaint); + } + + public void setHorizontalPadding(int mHorizontalPadding) { + this.mHorizontalPadding = mHorizontalPadding; + } + + public float getAspectRatio() { + return ((ClipView) getParent()).getAspectRatio(); + } +} + diff --git a/AlbumDialog/src/main/java/com/kongzue/albumdialog/views/crop/ClipView.java b/AlbumDialog/src/main/java/com/kongzue/albumdialog/views/crop/ClipView.java new file mode 100644 index 0000000..0aeb70d --- /dev/null +++ b/AlbumDialog/src/main/java/com/kongzue/albumdialog/views/crop/ClipView.java @@ -0,0 +1,184 @@ +package com.kongzue.albumdialog.views.crop; + + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Matrix; +import android.graphics.RectF; +import android.util.TypedValue; +import android.widget.RelativeLayout; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.target.SimpleTarget; +import com.bumptech.glide.request.transition.Transition; + +import java.util.Objects; + +public class ClipView extends RelativeLayout { + + private float aspectRatio = 1f;//宽高比 + private ClipZoomImageView mZoomImageView; + private ClipImageBorderView mClipImageView; + public Bitmap bm = null; + + /** + * 裁剪框大小固定,可以提取为自定义属性 + */ + private int mHorizontalPadding = 20;//边距 + + public ClipView(Context context) { + super(context); + mZoomImageView = new ClipZoomImageView(context); + mClipImageView = new ClipImageBorderView(context); + addView(mZoomImageView, new LayoutParams(android.view.ViewGroup.LayoutParams.MATCH_PARENT, android.view.ViewGroup.LayoutParams.MATCH_PARENT)); + addView(mClipImageView, new LayoutParams(android.view.ViewGroup.LayoutParams.MATCH_PARENT, android.view.ViewGroup.LayoutParams.MATCH_PARENT)); + + mHorizontalPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mHorizontalPadding, getResources().getDisplayMetrics()); + mZoomImageView.setHorizontalPadding(mHorizontalPadding); + mClipImageView.setHorizontalPadding(mHorizontalPadding); + } + + public void setImage(Bitmap bitmap) { + bm = bitmap; + try { + float scare = getScare(bm); + if (scare < 1) scare = 1; + bm = zoomBitmap(bm, (int) (bm.getWidth() / scare), (int) (bm.getHeight() / scare)); + } catch (Exception e) { + + } + mZoomImageView.setImageBitmap(bm); + invalidate(); + } + + private float getScare(Bitmap bm) { + if (getHeight() <= 0) return 1f; + return bm.getHeight() / getHeight(); + } + + /** + * 图片反转 + */ + public void reverseBitmap() { + float[] floats = null; + switch (0) { + case 0: // 水平反转 + floats = new float[]{-1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f}; + break; + case 1: // 垂直反转 + floats = new float[]{1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, 1f}; + break; + } + + if (floats != null) { + Matrix matrix = new Matrix(); + matrix.setValues(floats); + float dx = getXpoint(); + float dxx = getXRightpoint(); + float dx_should = getWidth() / 2 - (dxx - ClipImageBorderView.mHorizontalPadding - mClipImageView.mWidth / 2); + + bm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true); + mZoomImageView.setImageBitmap(bm); + mZoomImageView.check_bitmap(); + mZoomImageView.moveimage(dx_should - dx, 0); + + + } + } + + /** + * 图片旋转 + */ + public void rotateBitmap() { + float alpha = 90; + int width = bm.getWidth(); + int height = bm.getHeight(); + Matrix matrix = new Matrix(); + matrix.setRotate(alpha); + // 围绕原地进行旋转 + bm = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true); + + float dx = getXpoint(); + float dy = getYpoint(); + float dyy = getYBottompoint(); + + mZoomImageView.setImageBitmap(bm); + float yy = ClipImageBorderView.mVerticalPadding + mClipImageView.mWidth / 2 - (getWidth() / 2 - dx) - dy; + float xx = getWidth() / 2 - (dyy - ClipImageBorderView.mVerticalPadding - mClipImageView.mWidth / 2) - dx; + mZoomImageView.moveimage(xx, yy); + + } + + + public float getXpoint() { + RectF rect = mZoomImageView.getMatrixRectF(); + return rect.left; + } + + public float getXRightpoint() { + RectF rect = mZoomImageView.getMatrixRectF(); + return rect.right; + } + + public float getYpoint() { + RectF rect = mZoomImageView.getMatrixRectF(); + return rect.top; + } + + public float getYBottompoint() { + RectF rect = mZoomImageView.getMatrixRectF(); + return rect.bottom; + } + + /** + * 对外公布设置边距的方法,单位为dp + */ + public void setHorizontalPadding(int mHorizontalPadding) { + this.mHorizontalPadding = mHorizontalPadding; + } + + /** + * 裁切图片 + * + * @return + */ + public Bitmap clip() { + return mZoomImageView.clip(); + } + + public Bitmap getBitmap() { + return bm; + } + + private Bitmap zoomBitmap(Bitmap bitmap, int width, int height) { + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + Matrix matrix = new Matrix(); + float scaleWidth = ((float) width / w); + float scaleHeight = ((float) height / h); + matrix.postScale(scaleWidth, scaleHeight); + Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true); + return newbmp; + } + + public float getAspectRatio() { + return aspectRatio; + } + + public ClipView setAspectRatio(float aspectRatio) { + this.aspectRatio = aspectRatio; + return this; + } + + public void loadImage(String uri) { + Glide.with(getContext()) + .asBitmap() + .load(uri) + .into(new SimpleTarget() { + @Override + public void onResourceReady(Bitmap bitmap, Transition transition) { + setImage(bitmap); + } + }); + } +} diff --git a/AlbumDialog/src/main/java/com/kongzue/albumdialog/views/crop/ClipZoomImageView.java b/AlbumDialog/src/main/java/com/kongzue/albumdialog/views/crop/ClipZoomImageView.java new file mode 100644 index 0000000..189579f --- /dev/null +++ b/AlbumDialog/src/main/java/com/kongzue/albumdialog/views/crop/ClipZoomImageView.java @@ -0,0 +1,480 @@ +package com.kongzue.albumdialog.views.crop; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Matrix; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.view.GestureDetector; +import android.view.GestureDetector.SimpleOnGestureListener; +import android.view.MotionEvent; +import android.view.ScaleGestureDetector; +import android.view.ScaleGestureDetector.OnScaleGestureListener; +import android.view.View; +import android.view.View.OnTouchListener; +import android.view.ViewTreeObserver; + +/** + * Author: @Kongzue + * Github: https://github.com/kongzue/ + * Homepage: http://kongzue.com/ + * Mail: myzcxhh@live.cn + * CreateTime: 2018/8/12 16:26 + */ +public class ClipZoomImageView extends androidx.appcompat.widget.AppCompatImageView implements OnScaleGestureListener, OnTouchListener, ViewTreeObserver.OnGlobalLayoutListener { + + public Bitmap bm = null; + + private Handler handler = new Handler() { + public void handleMessage(Message msg) { + switch (msg.what) { + case 1: + ClipImageBorderView.isshowline = false; + ((ClipView) getParent()).invalidate(); + break; + default: + break; + } + } + + ; + }; + + public static float SCALE_MAX = 4.0f; + private static float SCALE_MID = 2.0f; + + public static float initScale = 1.0f; + public static float now_scale; + private boolean once = true; + + /** + * 用于存放矩阵的9个值 + */ + private final float[] matrixValues = new float[9]; + + /** + * 缩放的手势检测 + */ + private ScaleGestureDetector mScaleGestureDetector = null; + private final Matrix mScaleMatrix = new Matrix(); + + /** + * 用于双击检测 + */ + private GestureDetector mGestureDetector; + private boolean isAutoScale; + + private int mTouchSlop; + + private float mLastX; + private float mLastY; + + private boolean isCanDrag; + private int lastPointerCount; + + public ClipZoomImageView(Context context) { + this(context, null); + } + + public void setImageBitmap(Bitmap bm) { + super.setImageBitmap(bm); + this.bm = bm; + } + + public ClipZoomImageView(Context context, AttributeSet attrs) { + super(context, attrs); + + setScaleType(ScaleType.MATRIX); + mGestureDetector = new GestureDetector( + context, + new SimpleOnGestureListener() { + @Override + public boolean onDoubleTap(MotionEvent e) { + if (isAutoScale == true) + return true; + + float x = e.getX(); + float y = e.getY(); + if (getScale() < SCALE_MID) { + ClipZoomImageView.this.postDelayed( + new AutoScaleRunnable(SCALE_MID, x, y), 16); + isAutoScale = true; + } else { + ClipZoomImageView.this.postDelayed( + new AutoScaleRunnable(initScale, x, y), 16); + isAutoScale = true; + } + + return true; + } + } + ); + mScaleGestureDetector = new ScaleGestureDetector(context, this); + this.setOnTouchListener(this); + } + + /** + * 自动缩放的任务、已经进行注释 + */ + private class AutoScaleRunnable implements Runnable { + + static final float BIGGER = 1.07f; + static final float SMALLER = 0.93f; + private float mTargetScale; + private float tmpScale; + + /** + * 缩放的中心 + */ + private float x; + private float y; + + /** + * 传入目标缩放值,根据目标值与当前值,判断应该放大还是缩小 + * + * @param targetScale + */ + public AutoScaleRunnable(float targetScale, float x, float y) { + this.mTargetScale = targetScale; + this.x = x; + this.y = y; + if (getScale() < mTargetScale) { + tmpScale = BIGGER; + } else { + tmpScale = SMALLER; + } + + } + + @Override + public void run() { + // 进行缩放 + mScaleMatrix.postScale(tmpScale, tmpScale, x, y); + checkBorder(); + setImageMatrix(mScaleMatrix); + final float currentScale = getScale(); + // 如果值在合法范围内,继续缩放 + if (((tmpScale > 1f) && (currentScale < mTargetScale)) + || ((tmpScale < 1f) && (mTargetScale < currentScale))) { + ClipZoomImageView.this.postDelayed(this, 16); + } else + // 设置为目标的缩放比例 + { + final float deltaScale = mTargetScale / currentScale; + mScaleMatrix.postScale(deltaScale, deltaScale, x, y); + checkBorder(); + setImageMatrix(mScaleMatrix); + isAutoScale = false; + } + + } + } + + @Override + public boolean onScale(ScaleGestureDetector detector) { + float scale = getScale(); + float scaleFactor = detector.getScaleFactor(); + + if (getDrawable() == null) + return true; + + /** + * 缩放的范围控制 + */ + if ((scale < SCALE_MAX && scaleFactor > 1.0f) || (scale > initScale && scaleFactor < 1.0f)) { + /* + * 最大值最小值判断 + */ + if (scaleFactor * scale < initScale) { + scaleFactor = (initScale / scale); + } + if (scaleFactor * scale > SCALE_MAX) { + scaleFactor = SCALE_MAX / scale; + } + /** + * 设置缩放比例 + */ + mScaleMatrix.postScale(scaleFactor, scaleFactor, + detector.getFocusX(), detector.getFocusY() + ); + + now_scale = scaleFactor * scale; + setImageMatrix(mScaleMatrix); + } + return true; + + } + + /** + * 用于旋转图片时控制图片的位置范围 + */ + public void check_bitmap() { + checkBorder(); + setImageMatrix(mScaleMatrix); + + } + + /** + * 根据当前图片的Matrix获得图片的范围 + * + * @return + */ + public RectF getMatrixRectF() { + Matrix matrix = mScaleMatrix; + RectF rect = new RectF(); + Drawable d = getDrawable(); + + if (null != d) { + rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight()); + matrix.mapRect(rect); + } + return rect; + } + + @Override + public boolean onScaleBegin(ScaleGestureDetector detector) { + return true; + } + + @Override + public void onScaleEnd(ScaleGestureDetector detector) { + } + + + /** + * 移动view + */ + @Override + public boolean onTouch(View v, MotionEvent event) { + + mScaleGestureDetector.onTouchEvent(event); + + float x = 0, y = 0; + // 拿到触摸点的个数 + final int pointerCount = event.getPointerCount(); + // 得到多个触摸点的x与y均值 + for (int i = 0; i < pointerCount; i++) { + x += event.getX(i); + y += event.getY(i); + } + x = x / pointerCount; + y = y / pointerCount; + + /** + * 每当触摸点发生变化时,重置mLasX , mLastY + */ + if (pointerCount != lastPointerCount) { + isCanDrag = false; + mLastX = x; + mLastY = y; + } + + lastPointerCount = pointerCount; + switch (event.getAction()) { + case MotionEvent.ACTION_MOVE: + if (ClipImageBorderView.isshowline == false) { + ClipImageBorderView.isshowline = true; + ((ClipView) getParent()).invalidate(); + } + float dx = x - mLastX; + float dy = y - mLastY; + if (!isCanDrag) { + isCanDrag = isCanDrag(dx, dy); + } + if (isCanDrag) { + if (getDrawable() != null) { + + RectF rectF = getMatrixRectF(); //根据当前图片的Matrix获得图片的范围 + // 如果宽度小于屏幕宽度,则禁止左右移动 + if (rectF.width() <= getWidth() - mHorizontalPadding * 2) { + dx = 0; + } + // 如果高度小于屏幕高度,则禁止上下移动 + if (rectF.height() <= getHeight() - mVerticalPadding * 2) { + dy = 0; + } + mScaleMatrix.postTranslate(dx, dy); + checkBorder(); + setImageMatrix(mScaleMatrix); + } + } + mLastX = x; + mLastY = y; + break; + + case MotionEvent.ACTION_UP: + Message msg = new Message(); + msg.what = 1; + handler.sendMessageDelayed(msg, 1000); + case MotionEvent.ACTION_DOWN: + ClipImageBorderView.isshowline = true; + ((ClipView) getParent()).invalidate(); + case MotionEvent.ACTION_CANCEL: + lastPointerCount = 0; + break; + } + return true; + } + + public void moveimage(float dx, float dy) { + mScaleMatrix.postTranslate(dx, dy); + setImageMatrix(mScaleMatrix); + } + + /** + * 获得当前的缩放比例 + * + * @return + */ + public final float getScale() { + mScaleMatrix.getValues(matrixValues); + return matrixValues[Matrix.MSCALE_X]; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + getViewTreeObserver().addOnGlobalLayoutListener(this); + } + + @SuppressWarnings("deprecation") + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + getViewTreeObserver().removeGlobalOnLayoutListener(this); + } + + /** + * 水平方向与View的边距 + */ + private int mHorizontalPadding; + /** + * 垂直方向与View的边距 + */ + public static int mVerticalPadding; + + @Override + public void onGlobalLayout() { + if (once) { + Drawable d = getDrawable(); + if (d == null) + return; + + mVerticalPadding = (int) ((getHeight() - (getWidth() - 2 * mHorizontalPadding) * getAspectRatio()) / 2.0); + + float scale = 1.0f; + int width = getWidth(); + int height = getHeight(); + // 拿到图片的宽和高 + int dw = d.getIntrinsicWidth(); + int dh = d.getIntrinsicHeight(); + + float scaleW = (getWidth() * 1.0f - mHorizontalPadding * 2) / dw; + float scaleH = (getHeight() * 1.0f - mVerticalPadding * 2) / dh; + scale = Math.max(scaleW, scaleH); + + now_scale = initScale = scale; + SCALE_MID = initScale * 2; + SCALE_MAX = initScale * 4; + mScaleMatrix.postTranslate((int) ((width - dw) / 2.0), (int) (height - dh) / 2); + mScaleMatrix.postScale(scale, scale, (int) (getWidth() / 2.0), + (int) (getHeight() / 2.0) + ); + // 图片移动至屏幕中心 + setImageMatrix(mScaleMatrix); + once = false; + } + + } + + /** + * 剪切图片,返回剪切后的bitmap对象 + * + * @return + */ + public Bitmap clip() { + if (bm==null) return null; + RectF rectF = getMatrixRectF(); + + float scare = getScale(); + + int image_left = (int) ((mHorizontalPadding - rectF.left) / scare); + int image_right = (int) ((getWidth() - mHorizontalPadding - rectF.left) / scare); + + int width = image_right - image_left; + int image_top = (int) ((mVerticalPadding - rectF.top) / scare); + if (bm.getHeight() < (width + image_top)) { + width = bm.getHeight() - image_top; + } + + int height = (int) (width * getAspectRatio()); + + if ((image_top + height) > bm.getHeight()) image_top = bm.getHeight() - height; + + if (image_left < 0) image_left = 0; + if (image_top < 0) image_top = 0; + if (image_left > bm.getWidth()) image_left = 0; + if (image_top > bm.getHeight()) image_top = 0; + if (width <= 0) width = bm.getWidth(); + if (height <= 0) height = bm.getHeight(); + + Bitmap bitmap = Bitmap.createBitmap(bm, image_left, image_top, width, height); + return bitmap; + } + + + /** + * 边界检测 + */ + public void checkBorder() { + + RectF rect = getMatrixRectF(); + float deltaX = 0; + float deltaY = 0; + int width = getWidth(); + int height = getHeight(); + + // 如果宽或高大于屏幕,则控制范围 ; 这里的0.001是因为精度丢失会产生问题,但是误差一般很小,所以我们直接加了一个0.01 + if (rect.width() + 0.001 >= width - 2 * mHorizontalPadding) { + if (rect.left > mHorizontalPadding) { + deltaX = -rect.left + mHorizontalPadding; + } + if (rect.right < width - mHorizontalPadding) { + deltaX = width - mHorizontalPadding - rect.right; + } + } + if (rect.height() + 2.01 >= height - 2 * mVerticalPadding) { + if (rect.top > mVerticalPadding) { + deltaY = -rect.top + mVerticalPadding; + } + + if (rect.bottom < height - mVerticalPadding) { + deltaY = height - mVerticalPadding - rect.bottom; + } + } + mScaleMatrix.postTranslate(deltaX, deltaY); + + } + + /** + * 是否是拖动行为 + * + * @param dx + * @param dy + * @return + */ + private boolean isCanDrag(float dx, float dy) { + return Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop; + } + + public void setHorizontalPadding(int mHorizontalPadding) { + this.mHorizontalPadding = mHorizontalPadding; + } + + public float getAspectRatio() { + return ((ClipView) getParent()).getAspectRatio(); + } +} diff --git a/AlbumDialog/src/main/res/drawable/album_dialog_bkg_album_gray.xml b/AlbumDialog/src/main/res/drawable/album_dialog_bkg_album_gray.xml new file mode 100644 index 0000000..ed26eea --- /dev/null +++ b/AlbumDialog/src/main/res/drawable/album_dialog_bkg_album_gray.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/AlbumDialog/src/main/res/drawable/album_dialog_bkg_album_selector.xml b/AlbumDialog/src/main/res/drawable/album_dialog_bkg_album_selector.xml new file mode 100644 index 0000000..6a80b5d --- /dev/null +++ b/AlbumDialog/src/main/res/drawable/album_dialog_bkg_album_selector.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/AlbumDialog/src/main/res/drawable/album_dialog_error_photo.xml b/AlbumDialog/src/main/res/drawable/album_dialog_error_photo.xml new file mode 100644 index 0000000..5b1594e --- /dev/null +++ b/AlbumDialog/src/main/res/drawable/album_dialog_error_photo.xml @@ -0,0 +1,4 @@ + + + + diff --git a/AlbumDialog/src/main/res/drawable/album_dialog_ripple_effect.xml b/AlbumDialog/src/main/res/drawable/album_dialog_ripple_effect.xml new file mode 100644 index 0000000..8f62b5d --- /dev/null +++ b/AlbumDialog/src/main/res/drawable/album_dialog_ripple_effect.xml @@ -0,0 +1,6 @@ + + + + diff --git a/AlbumDialog/src/main/res/drawable/album_dialog_ripple_effect_oval.xml b/AlbumDialog/src/main/res/drawable/album_dialog_ripple_effect_oval.xml new file mode 100644 index 0000000..e85a501 --- /dev/null +++ b/AlbumDialog/src/main/res/drawable/album_dialog_ripple_effect_oval.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/AlbumDialog/src/main/res/mipmap-xxhdpi/album_dialog_img_selected.png b/AlbumDialog/src/main/res/mipmap-xxhdpi/album_dialog_img_selected.png new file mode 100644 index 0000000..9a6631e Binary files /dev/null and b/AlbumDialog/src/main/res/mipmap-xxhdpi/album_dialog_img_selected.png differ diff --git a/AlbumDialog/src/main/res/mipmap-xxhdpi/img_album_dialog_button_back.png b/AlbumDialog/src/main/res/mipmap-xxhdpi/img_album_dialog_button_back.png new file mode 100644 index 0000000..b4de2f4 Binary files /dev/null and b/AlbumDialog/src/main/res/mipmap-xxhdpi/img_album_dialog_button_back.png differ diff --git a/AlbumDialog/src/main/res/mipmap-xxhdpi/img_album_dialog_button_close.png b/AlbumDialog/src/main/res/mipmap-xxhdpi/img_album_dialog_button_close.png new file mode 100644 index 0000000..f21725a Binary files /dev/null and b/AlbumDialog/src/main/res/mipmap-xxhdpi/img_album_dialog_button_close.png differ diff --git a/AlbumDialog/src/main/res/mipmap-xxhdpi/img_album_dialog_button_ok.png b/AlbumDialog/src/main/res/mipmap-xxhdpi/img_album_dialog_button_ok.png new file mode 100644 index 0000000..c002689 Binary files /dev/null and b/AlbumDialog/src/main/res/mipmap-xxhdpi/img_album_dialog_button_ok.png differ diff --git a/AlbumDialog/src/main/res/values/colors.xml b/AlbumDialog/src/main/res/values/colors.xml new file mode 100644 index 0000000..6f996d5 --- /dev/null +++ b/AlbumDialog/src/main/res/values/colors.xml @@ -0,0 +1,7 @@ + + + #84A3A1 + #D5E3E2 + #587472 + #8B8B8B + \ No newline at end of file diff --git a/AlbumDialog/src/main/res/values/strings.xml b/AlbumDialog/src/main/res/values/strings.xml new file mode 100644 index 0000000..8b279c6 --- /dev/null +++ b/AlbumDialog/src/main/res/values/strings.xml @@ -0,0 +1,10 @@ + + + 所有照片 + 其他相册 + 请选择需要使用的照片 + 最多可选择 %s 张照片 + 请裁剪照片 + 请稍候... + 第 %s 张照片还未裁剪 + \ No newline at end of file diff --git a/AlbumDialog/src/main/res/values/values.xml b/AlbumDialog/src/main/res/values/values.xml new file mode 100644 index 0000000..9568f57 --- /dev/null +++ b/AlbumDialog/src/main/res/values/values.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..d0b97c6 --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,2 @@ +/build +*.iml \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..48ca6d2 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,129 @@ +plugins { + id 'com.android.application' +} + +def releaseTime() { + return new Date().format("yyyyMMddHHmmss") +} + +android { + compileSdkVersion 33 + defaultConfig { + applicationId "com.tairui.gov_affairs_cloud" + minSdkVersion 21 + targetSdkVersion 33 + versionCode 1 + versionName "1.0" + multiDexEnabled true + javaCompileOptions { + annotationProcessorOptions { + arguments = [ + //必须,告知RxHttp你依赖的okhttp版本,目前已适配 v3.12.0 - v4.8.1版本 + rxhttp_okhttp : '4.8.1', + //使用asXxx方法时必须,告知RxHttp你依赖的rxjava版本,可传入rxjava2、rxjava3 + rxhttp_rxjava : 'rxjava2', + rxhttp_package: 'rxhttp' //非必须,指定RxHttp相关类的生成路径,即包名 + ] + } + } + renderscriptTargetApi 21 + renderscriptSupportModeEnabled true + } + + buildFeatures { + viewBinding true + } + + sourceSets { + main { + jniLibs.srcDir 'libs' + } + } + dexOptions { + javaMaxHeapSize "4g" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + signingConfigs { + release { + storeFile file('../key/tairui.jks') + storePassword "tairui" + keyAlias "tairui" + keyPassword "tairui" + } + } + buildTypes { + debug { + signingConfig signingConfigs.release + jniDebuggable false + zipAlignEnabled false + } + release { + zipAlignEnabled true + signingConfig signingConfigs.release + minifyEnabled false + jniDebuggable false + + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + + } + + lintOptions { + abortOnError false + } + + android.applicationVariants.all { variant -> + variant.outputs.all { + outputFileName = "GovAffairsCloud_app_v${variant.versionName}_${releaseTime()}.apk" + } + } +} +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation 'androidx.appcompat:appcompat:1.4.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.3' + implementation 'androidx.legacy:legacy-support-v4:1.0.0' + implementation 'androidx.recyclerview:recyclerview:1.2.1' + implementation 'com.google.android.material:material:1.5.0' + + implementation 'com.google.code.gson:gson:2.8.7' + + implementation 'com.scwang.smart:refresh-layout-kernel:2.0.1' //核心必须依赖 + implementation 'com.scwang.smart:refresh-header-classics:2.0.1' //经典刷新头 + implementation 'com.scwang.smart:refresh-header-material:2.0.1' //谷歌刷新头 + implementation 'com.gyf.immersionbar:immersionbar:3.0.0' + + // 事件总线 + implementation 'org.greenrobot:eventbus:3.2.0' + //键值存储 + implementation 'com.orhanobut:hawk:2.0.1' + //高德地图 + implementation 'com.amap.api:3dmap:latest.integration' + + // 底部导航库 + implementation 'com.flyco.tablayout:FlycoTabLayout_Lib:2.1.2@aar' + + implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.50' + + //rxhttp + implementation 'com.ljx.rxhttp:rxhttp:2.5.7' + implementation 'com.squareup.okhttp3:okhttp:4.8.1' //rxhttp v2.2.2版本起,需要手动依赖okhttp + annotationProcessor 'com.ljx.rxhttp:rxhttp-compiler:2.5.7' //生成RxHttp类,纯Java项目,请使用annotationProcessor代替kapt + //rxjava2 (RxJava2/Rxjava3二选一,使用asXxx方法时必须) + implementation 'io.reactivex.rxjava2:rxjava:2.2.8' + implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' + implementation 'com.rxjava.rxlife:rxlife:2.0.0' + // glide加载图片 + implementation 'com.github.bumptech.glide:glide:4.12.0' + annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0' + + implementation 'com.contrarywind:Android-PickerView:4.1.9' + + implementation 'com.github.li-xiaojun:XPopup:v2.2.23' + + implementation project(path: ':AlbumDialog') +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..6e38d17 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,22 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in D:\AndroidStudio\sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# 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 *; +#} +-keep class com.kongzue.dialogx.** { *; } +-dontwarn com.kongzue.dialogx.** + +# 额外的,建议将 android.view 也列入 keep 范围: +-keep class android.view.** { *; } diff --git a/app/release/GovAffairsCloud_app_v1.0_20250523090051.apk b/app/release/GovAffairsCloud_app_v1.0_20250523090051.apk new file mode 100644 index 0000000..9fd7d92 Binary files /dev/null and b/app/release/GovAffairsCloud_app_v1.0_20250523090051.apk differ diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json new file mode 100644 index 0000000..ac87c7f --- /dev/null +++ b/app/release/output-metadata.json @@ -0,0 +1,20 @@ +{ + "version": 3, + "artifactType": { + "type": "APK", + "kind": "Directory" + }, + "applicationId": "com.tairui.gov_affairs_cloud", + "variantName": "release", + "elements": [ + { + "type": "SINGLE", + "filters": [], + "attributes": [], + "versionCode": 1, + "versionName": "1.0", + "outputFile": "GovAffairsCloud_app_v1.0_20250523090051.apk" + } + ], + "elementType": "File" +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..2b19c62 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/GacApplication.java b/app/src/main/java/com/tairui/gov_affairs_cloud/GacApplication.java new file mode 100644 index 0000000..a1259c3 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/GacApplication.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2025 Baidu, Inc. All Rights Reserved. + */ +package com.tairui.gov_affairs_cloud; + +import java.util.concurrent.TimeUnit; + +import com.kongzue.dialogx.DialogX; +import com.kongzue.dialogxmaterialyou.style.MaterialYouStyle; +import com.orhanobut.hawk.Hawk; +import com.tairui.gov_affairs_cloud.config.AppConfig; +import com.tairui.gov_affairs_cloud.entity.Api; +import com.tairui.gov_affairs_cloud.http.ApiDns; +import com.tairui.gov_affairs_cloud.util.CrashHandler; + +import android.app.Application; +import android.content.Context; +import android.text.TextUtils; +import okhttp3.OkHttpClient; +import rxhttp.RxHttp; +import rxhttp.wrapper.ssl.HttpsUtils; + +public class GacApplication extends Application { + + protected static Context context; + + public static GacApplication instance; + + public static GacApplication getInstance() { + if (instance == null) { + instance = new GacApplication(); + } + return instance; + } + + @Override + public void onCreate() { + super.onCreate(); + context = this; + + CrashHandler.instance().init(getApplicationContext()); + intiDialog(); + initHawk(); + initHttp(); + } + + private void initHttp() { + HttpsUtils.SSLParams sslParams = HttpsUtils.getSslSocketFactory(); + OkHttpClient okHttpClient = new OkHttpClient.Builder() + .connectTimeout(10, TimeUnit.SECONDS) + .readTimeout(10, TimeUnit.SECONDS) + .writeTimeout(10, TimeUnit.SECONDS) + .sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager) + .hostnameVerifier((hostname, session) -> true) + .dns(new ApiDns()) + .build(); + RxHttp.init(okHttpClient); + RxHttp.setDebug(BuildConfig.DEBUG); + RxHttp.setOnParamAssembly(param -> { + if (null != GacApplication.getContext()) { + if (!TextUtils.isEmpty(AppConfig.getInstance().getToken())) { + param = param.addHeader(Api.STR_AUTHORIZATION, Api.BEARER.concat(AppConfig.getInstance().getToken())); + } + } + return param; + }); + } + + private void initHawk() { + Hawk.init(context).build(); + } + + private void intiDialog() { + //初始化 + DialogX.init(this); + DialogX.globalStyle = new MaterialYouStyle(); + //设置亮色/暗色(在启动下一个对话框时生效) + DialogX.globalTheme = DialogX.THEME.AUTO; + } + + public static Context getContext() { + return context; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/base/BaseActivity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/base/BaseActivity.java new file mode 100644 index 0000000..c9081b5 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/base/BaseActivity.java @@ -0,0 +1,186 @@ +package com.tairui.gov_affairs_cloud.base; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import com.gyf.immersionbar.ImmersionBar; +import com.kongzue.dialogx.dialogs.PopTip; +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.util.AppUtil; +import com.tairui.gov_affairs_cloud.widget.loading.LoadingDialog; + +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.viewbinding.ViewBinding; + +public abstract class BaseActivity extends AppCompatActivity { + + protected T binding; + + private LoadingDialog loading; + protected Context mContext; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mContext = this; + initStatusBar(); + try { + // 通过反射获取 ViewBinding 类的 inflate 方法 + Method inflateMethod = getBindingClass().getMethod("inflate", android.view.LayoutInflater.class); + // 调用 inflate 方法创建 ViewBinding 实例 + binding = (T) inflateMethod.invoke(null, getLayoutInflater()); + // 设置 Activity 的内容视图为 ViewBinding 的根视图 + setContentView(binding.getRoot()); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + initContentView(savedInstanceState); + } + + protected abstract Class getBindingClass(); + + protected void initStatusBar() { + ImmersionBar.with(this) + .statusBarColor(getStatusBarColor()) + .statusBarDarkFont(isDarkMode()) //状态栏字体是深色,不写默认为亮色 + .fitsSystemWindows(true) + .keyboardEnable(true) //解决软键盘与底部输入框冲突问题 + .init(); + } + + protected boolean isDarkMode() { + return true; + } + + protected int getStatusBarColor() { + return R.color.white; + } + + /** + * 解决系统字体改变而ui不协调问题,设置app字体为默认字体 + * + * @return + */ + @Override + public Resources getResources() { + Resources res = super.getResources(); + if (res != null) { + Configuration config = res.getConfiguration(); + if (config != null && config.fontScale != 1.0f) { + config.fontScale = 1.0f; + res.updateConfiguration(config, res.getDisplayMetrics()); + } + } + return res; + } + + @Override + protected void onDestroy() { + super.onDestroy(); + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + protected void onResume() { + super.onResume(); + } + + private void initContentView(Bundle savedInstanceState) { + onQueryArguments(); + onFindView(savedInstanceState); + onBindListener(); + onApplyData(); + } + + /** + * 取得传递的参数 + */ + protected void onQueryArguments() { + + } + + /** + * 初始化控件、获取内部控件 + */ + protected void onFindView(Bundle savedInstanceState) { + } + + /** + * 设置监听事件 + */ + protected void onBindListener() { + + } + + /** + * 加载数据 + */ + protected void onApplyData() { + + } + + protected String getStr(int resId) { + return mContext.getResources().getString(resId); + } + + protected int getResColor(int resId) { + return mContext.getResources().getColor(resId); + } + + protected void showToast(String str) { + Toast.makeText(mContext, str, Toast.LENGTH_LONG).show(); + } + protected void showError(String str) { + PopTip.show(str).iconError(); + } + + protected void setText(TextView view, String txt, String defaultTxt) { + if (view != null) { + view.setText(TextUtils.isEmpty(txt) ? defaultTxt : txt); + } + } + + protected void setText(TextView view, String txt) { + setText(view, txt, ""); + } + + protected void setGone(View view, boolean visible) { + view.setVisibility(visible ? View.VISIBLE : View.GONE); + } + + protected void showLoading() { + if (loading == null) { + loading = AppUtil.getLoading(mContext); + } + if (!loading.isShow()) { + loading.show(); + } + } + + protected void hideLoading() { + if (loading != null && loading.isShow()) { + loading.close(); + } + } + + protected boolean isLoadingShow() { + if (loading != null && loading.isShow()) { + return true; + } else { + return false; + } + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/base/BaseFragment.java b/app/src/main/java/com/tairui/gov_affairs_cloud/base/BaseFragment.java new file mode 100644 index 0000000..5f64a4b --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/base/BaseFragment.java @@ -0,0 +1,167 @@ +package com.tairui.gov_affairs_cloud.base; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import com.tairui.gov_affairs_cloud.util.AppUtil; +import com.tairui.gov_affairs_cloud.util.ToastUtil; +import com.tairui.gov_affairs_cloud.widget.loading.LoadingDialog; + +import android.content.Context; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.viewbinding.ViewBinding; + +/** + * Created by tongchao on 17/5/20. + */ + +public abstract class BaseFragment extends Fragment { + + protected T binding; + + protected Context mContext; + + private LoadingDialog loading; + + // Fragment当前状态是否可见 + protected boolean isVisible; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + mContext = getActivity(); + try { + // 获取 ViewBinding 类的 inflate 方法 + Method inflateMethod = getBindingClass().getMethod("inflate", LayoutInflater.class, ViewGroup.class, boolean.class); + // 调用 inflate 方法创建 ViewBinding 实例 + binding = (T) inflateMethod.invoke(null, inflater, container, false); + return binding.getRoot(); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + return null; + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + // 避免内存泄漏,在 Fragment 视图销毁时将 binding 置为 null + binding = null; + } + + /** + * 抽象方法,由子类实现以返回具体的 ViewBinding 类 + * @return 具体的 ViewBinding 类 + */ + protected abstract Class getBindingClass(); + + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + initContentView(); + } + + private void initContentView() { + onQueryArguments(); + onFindView(getView()); + onBindListener(); + onApplyData(); + } + + /** + * 取得传递的参数 + */ + protected void onQueryArguments() { + + } + + /** + * 初始化控件、获取内部控件 + */ + protected void onFindView(View rootView) { + + } + + /** + * 设置监听事件 + */ + protected void onBindListener() { + + } + + /** + * 加载数据 + */ + protected void onApplyData() { + + } + + + protected void showToast(String str) { + ToastUtil.showLongToast(str); + } + + public void frResume() { + } + + public void frPause() { + } + + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + if (getUserVisibleHint()) { + isVisible = true; + frResume(); + } else { + isVisible = false; + frPause(); + } + } + + protected void showLoading() { + if (loading == null) { + loading = AppUtil.getLoading(getActivity()); + } + if (!loading.isShow()) { + loading.show(); + } + } + + protected void hideLoading() { + if (loading != null && loading.isShow()) { + loading.close(); + } + } + + protected boolean isLoadingShow() { + if (loading != null && loading.isShow()) { + return true; + } else { + return false; + } + } + + protected void setText(TextView view, String txt, String defaultTxt) { + if (view != null) { + view.setText(TextUtils.isEmpty(txt) ? defaultTxt : txt); + } + } + + protected void setText(TextView view, String txt) { + setText(view, txt, ""); + } + + protected void setGone(View view, boolean visible) { + view.setVisibility(visible ? View.VISIBLE : View.GONE); + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/base/adapter/CommPagerAdapter.kt b/app/src/main/java/com/tairui/gov_affairs_cloud/base/adapter/CommPagerAdapter.kt new file mode 100644 index 0000000..3d6edcc --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/base/adapter/CommPagerAdapter.kt @@ -0,0 +1,37 @@ +package cn.kpinfo.base.adapter + +import android.os.Parcelable +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentStatePagerAdapter + +/** + * create by libo + * create on 2020/5/19 + * description 公共viewPageradapter + */ +class CommPagerAdapter( + fm: FragmentManager?, + private val items: ArrayList, + private val mTitles: Array +) : FragmentStatePagerAdapter(fm!!) { + override fun getCount(): Int { + return if (items.size == 0) 0 else items.size + } + + override fun getItem(position: Int): Fragment { + return items[position] + } + + override fun getPageTitle(position: Int): CharSequence? { + return mTitles[position] + } + + override fun getItemPosition(`object`: Any): Int { + return POSITION_NONE + } + + override fun saveState(): Parcelable? { + return null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/base/adapter/TabFragmentPagerAdapter.java b/app/src/main/java/com/tairui/gov_affairs_cloud/base/adapter/TabFragmentPagerAdapter.java new file mode 100644 index 0000000..ef64f84 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/base/adapter/TabFragmentPagerAdapter.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2020 Baidu, Inc. All Rights Reserved. + */ +package com.tairui.gov_affairs_cloud.base.adapter; + +import java.util.ArrayList; +import java.util.List; + +import com.tairui.gov_affairs_cloud.base.BaseFragment; + +import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; + +public class TabFragmentPagerAdapter extends FragmentPagerAdapter { + + private ArrayList tab_title_list;//存放标签页标题 + private List fragments; + + public TabFragmentPagerAdapter(FragmentManager fm, ArrayList tab_title_list, List fragments) { + super(fm); + this.tab_title_list = tab_title_list; + this.fragments = fragments; + } + + @Override + public BaseFragment getItem(int position) { + if (position >= fragments.size() || position < 0) { + return null; + } + return fragments.get(position); + } + + @Override + public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { + //super.destroyItem(container, position, object); + } + + @Override + public int getCount() { + return fragments.size(); + } + + @Override + public CharSequence getPageTitle(int position) { + return tab_title_list.get(position); + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/base/entity/BaseHolderEntity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/base/entity/BaseHolderEntity.java new file mode 100644 index 0000000..a13c9b5 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/base/entity/BaseHolderEntity.java @@ -0,0 +1,48 @@ +package com.tairui.gov_affairs_cloud.base.entity; + +import com.chad.library.adapter.base.entity.MultiItemEntity; + +public class BaseHolderEntity implements MultiItemEntity { + private int type; + private Object data; + private Object subData; + private boolean select = false; + + public Object getSubData() { + return subData; + } + + public void setSubData(Object subData) { + this.subData = subData; + } + + public boolean isSelect() { + return select; + } + + public void setSelect(boolean select) { + this.select = select; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + @Override + public int getItemType() { + return type; + } + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/config/AppConfig.java b/app/src/main/java/com/tairui/gov_affairs_cloud/config/AppConfig.java new file mode 100644 index 0000000..ec9de55 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/config/AppConfig.java @@ -0,0 +1,31 @@ +package com.tairui.gov_affairs_cloud.config; + +import com.orhanobut.hawk.Hawk; +import com.tairui.gov_affairs_cloud.entity.Constant; + +import android.text.TextUtils; + +public class AppConfig { + + public static AppConfig _instance; + + public static AppConfig getInstance() { + if (_instance == null) { + _instance = new AppConfig(); + } + return _instance; + } + + private String token; + + public String getToken() { + if (TextUtils.isEmpty(token)) { + token = Hawk.get(Constant.TOKEN); + } + return token; + } + + public void setToken(String token) { + this.token = token; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/entity/Api.java b/app/src/main/java/com/tairui/gov_affairs_cloud/entity/Api.java new file mode 100644 index 0000000..b34f0a3 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/entity/Api.java @@ -0,0 +1,46 @@ +package com.tairui.gov_affairs_cloud.entity; + +public class Api { + +// public static String BASE_HOST = "http://192.168.18.14:8080"; + public static String BASE_HOST = "http://47.109.205.240:8080"; + public static String OSS_HOST = "http://gov-cloud.oss-cn-chengdu.aliyuncs.com/"; + + /** + * 请求成功 + */ + public static final int CODE_SUCCESS_REQUEST = 200; + /** + * 登录状态异常 + */ + public static final int CODE_AUTH_ERROR = 401; + /** + * token前面需要加入的字段 + */ + public static final String BEARER = "Bearer "; + /** + * 分页值 + */ + public static final int SIZE_PAGE = 10; + /** + * 请求接口的时候的 授权token + */ + public static final String STR_AUTHORIZATION = "Authorization"; + + public static final String LOGIN = BASE_HOST + "/auth/app/login"; + public static final String FILE_UPLOAD = BASE_HOST + "/uploadApis/upload"; + public static final String CAPTCHA = BASE_HOST + "/auth/app/captcha"; + public static final String HOME = BASE_HOST + "/app/home/data"; + public static final String USER_INFO = BASE_HOST + "/app/my/info"; + public static final String LAND_OVERVIEW = BASE_HOST + "/land-resource/analysis/overview"; + public static final String LAND_SUB_AREA = BASE_HOST + "/land-resource/analysis/subArea"; + public static final String LAND_AREA_REGION = BASE_HOST + "/system/area/region"; + public static final String LAND_GRID = BASE_HOST + "/land-resource/gridManage/app/getGridInfo"; + public static final String ADD_LAND = BASE_HOST + "/land-resource/landManage/save"; + public static final String EDIT_LAND = BASE_HOST + "/land-resource/landManage/edit"; + public static final String LAND_GROUD_TYPE = BASE_HOST + "/land-resource/baseInfo/soilTypePage"; + public static final String LAND_TYPE = BASE_HOST + "/land-resource/baseInfo/landTree"; + public static final String LAND_RESOURCE_TYPE_NO_CHILD = BASE_HOST + "/land-resource/baseInfo/landTypeNoChild"; + public static final String LAND_RESOURCE_LIST = BASE_HOST + "/land-resource/landManage/page"; + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/entity/Constant.java b/app/src/main/java/com/tairui/gov_affairs_cloud/entity/Constant.java new file mode 100644 index 0000000..e00a852 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/entity/Constant.java @@ -0,0 +1,9 @@ +package com.tairui.gov_affairs_cloud.entity; + +public class Constant { + + public static String TOKEN = "token"; + + public static String LOGIN_USER_NAME = "login_user_name"; + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/entity/EventConstant.java b/app/src/main/java/com/tairui/gov_affairs_cloud/entity/EventConstant.java new file mode 100644 index 0000000..2e1423c --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/entity/EventConstant.java @@ -0,0 +1,21 @@ +package com.tairui.gov_affairs_cloud.entity; + +public class EventConstant { + /** + * 刷新列表 + */ + public static final String REFRESH_LIST = "refreshList"; + + /** + * 搜索后刷新列表 + */ + public static final String SEARCH_LIST = "search_list"; + + + public static final String LOCATION_CODE = "location"; + + public static final String SELECT_AREA = "select_area"; + + + public static final String EDIT_SUCCESS = "edit_success"; +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/entity/EventMessage.java b/app/src/main/java/com/tairui/gov_affairs_cloud/entity/EventMessage.java new file mode 100644 index 0000000..fe71774 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/entity/EventMessage.java @@ -0,0 +1,60 @@ +package com.tairui.gov_affairs_cloud.entity; + +/** + * @author kpinfo + *

+ * EventBus 发送消息的 实体类 + */ +public class EventMessage { + private Object data; + private Object subData; + private String label; + private String content; + + public EventMessage(String label) { + this.label = label; + } + + public EventMessage(String label, Object data) { + this.label = label; + this.data = data; + } + + public EventMessage(String label, Object data, Object subData) { + this.label = label; + this.data = data; + this.subData = subData; + } + + public Object getSubData() { + return subData; + } + + public void setSubData(Object subData) { + this.subData = subData; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/entity/PieBean.java b/app/src/main/java/com/tairui/gov_affairs_cloud/entity/PieBean.java new file mode 100644 index 0000000..2af84f6 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/entity/PieBean.java @@ -0,0 +1,38 @@ +package com.tairui.gov_affairs_cloud.entity; + + +/** + * autour : openXu + * date : 2018/6/8 9:40 + * className : PieBean + * version : 1.0 + * description : 请添加类说明 + */ +public class PieBean { + private float Numner; + private String Name; + + public PieBean() { + } + + public PieBean(float Numner, String Name) { + this.Numner = Numner; + this.Name = Name; + } + + public float getNumner() { + return Numner; + } + + public void setNumner(float numner) { + Numner = numner; + } + + public String getName() { + return Name; + } + + public void setName(String name) { + Name = name; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/entity/RoseBean.java b/app/src/main/java/com/tairui/gov_affairs_cloud/entity/RoseBean.java new file mode 100644 index 0000000..24f8783 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/entity/RoseBean.java @@ -0,0 +1,39 @@ +package com.tairui.gov_affairs_cloud.entity; + + +/** + * autour : openXu + * date : 2018/6/8 9:40 + * className : RoseBean + * version : 1.0 + * description : 请添加类说明 + */ +public class RoseBean { + + private float count; + private String ClassName; + + public RoseBean() { + } + + public RoseBean(float count, String className) { + this.count = count; + ClassName = className; + } + + public float getCount() { + return count; + } + + public void setCount(float count) { + this.count = count; + } + + public String getClassName() { + return ClassName; + } + + public void setClassName(String className) { + ClassName = className; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/entity/TabEntity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/entity/TabEntity.java new file mode 100644 index 0000000..9137012 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/entity/TabEntity.java @@ -0,0 +1,30 @@ +package com.tairui.gov_affairs_cloud.entity; + +import com.flyco.tablayout.listener.CustomTabEntity; + +public class TabEntity implements CustomTabEntity { + public String title; + public int selectedIcon; + public int unSelectedIcon; + + public TabEntity(String title, int selectedIcon, int unSelectedIcon) { + this.title = title; + this.selectedIcon = selectedIcon; + this.unSelectedIcon = unSelectedIcon; + } + + @Override + public String getTabTitle() { + return title; + } + + @Override + public int getTabSelectedIcon() { + return selectedIcon; + } + + @Override + public int getTabUnselectedIcon() { + return unSelectedIcon; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/entity/UploadEntity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/entity/UploadEntity.java new file mode 100644 index 0000000..6a98dc6 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/entity/UploadEntity.java @@ -0,0 +1,27 @@ +package com.tairui.gov_affairs_cloud.entity; + +import com.google.gson.annotations.SerializedName; + +public class UploadEntity { + + @SerializedName("name") + private String name; + @SerializedName("url") + private String url; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/http/ApiDns.java b/app/src/main/java/com/tairui/gov_affairs_cloud/http/ApiDns.java new file mode 100644 index 0000000..7adacbf --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/http/ApiDns.java @@ -0,0 +1,35 @@ +package com.tairui.gov_affairs_cloud.http; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; + +import okhttp3.Dns; + +public class ApiDns implements Dns { + @Override + public List lookup(String hostname) throws UnknownHostException { + if (hostname == null) { + throw new UnknownHostException("hostname == null"); + } else { + try { + List mInetAddressesList = new ArrayList<>(); + InetAddress[] mInetAddresses = InetAddress.getAllByName(hostname); + for (InetAddress address : mInetAddresses) { + if (address instanceof Inet4Address) { + mInetAddressesList.add(0, address); + } else { + mInetAddressesList.add(address); + } + } + return mInetAddressesList; + } catch (NullPointerException var4) { + UnknownHostException unknownHostException = new UnknownHostException("Broken system behaviour"); + unknownHostException.initCause(var4); + throw unknownHostException; + } + } + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/http/ErrorInfo.java b/app/src/main/java/com/tairui/gov_affairs_cloud/http/ErrorInfo.java new file mode 100644 index 0000000..b0a7154 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/http/ErrorInfo.java @@ -0,0 +1,72 @@ +package com.tairui.gov_affairs_cloud.http; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.orhanobut.hawk.Hawk; +import com.tairui.gov_affairs_cloud.GacApplication; +import com.tairui.gov_affairs_cloud.config.AppConfig; +import com.tairui.gov_affairs_cloud.http.exception.AuthException; +import com.tairui.gov_affairs_cloud.ui.login.LoginActivity; + +import android.content.Intent; +import android.text.TextUtils; +import rxhttp.wrapper.exception.HttpStatusCodeException; +import rxhttp.wrapper.exception.ParseException; + +/** + * Http请求错误信息 + */ +public class ErrorInfo { + private int errorCode; //仅指服务器返回的错误码 + private String errorMsg; //错误文案,网络错误、请求失败错误、服务器返回的错误等文案 + private Throwable throwable; //异常信息 + + public ErrorInfo(Throwable throwable) { + this.throwable = throwable; + String errorMsg = ExceptionHelper.handleNetworkException(throwable); //网络异常 + if (throwable instanceof AuthException) { //没有身份信息,需要重新登录 + this.errorMsg = throwable.getMessage(); + AppConfig.getInstance().setToken(""); + Hawk.put("token",""); + // 创建跳转到登录页面的 Intent + Intent intent = new Intent(GacApplication.getContext(), LoginActivity.class); + // 设置标志位,清除所有旧的 Activity 并创建新任务 + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + // 启动登录 Activity + GacApplication.getContext().startActivity(intent); + } else if (throwable instanceof ParseException) { // ParseException异常表明请求成功,但是数据不正确 + String errorCode = throwable.getLocalizedMessage(); + this.errorCode = Integer.valueOf(errorCode); + errorMsg = throwable.getMessage(); + if (TextUtils.isEmpty(errorMsg)) { + errorMsg = errorCode;//errorMsg为空,显示errorCode + } + } + if (errorMsg == null) { + if (throwable instanceof HttpStatusCodeException) { + HttpStatusCodeException exception = (HttpStatusCodeException) throwable; + if (exception.getStatusCode().equals("500")) { + this.errorMsg = "服务器接口发生错误"; + } else { + JsonObject result = (JsonObject) new JsonParser().parse(exception.getResult()); + String message = result.get("msg").getAsString(); + this.errorMsg = message; + } + } + } else { + this.errorMsg = errorMsg; + } + } + + public int getErrorCode() { + return errorCode; + } + + public String getErrorMsg() { + return errorMsg; + } + + public Throwable getThrowable() { + return throwable; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/http/ExceptionHelper.java b/app/src/main/java/com/tairui/gov_affairs_cloud/http/ExceptionHelper.java new file mode 100644 index 0000000..ba33fb8 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/http/ExceptionHelper.java @@ -0,0 +1,50 @@ +package com.tairui.gov_affairs_cloud.http; + +import java.net.ConnectException; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; +import java.util.concurrent.TimeoutException; + +import com.tairui.gov_affairs_cloud.GacApplication; +import com.tairui.gov_affairs_cloud.R; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +/** + * 异常处理帮助类 + */ +public class ExceptionHelper { + + //处理网络异常 + public static String handleNetworkException(T throwable) { + int stringId = -1; + if (throwable instanceof UnknownHostException) { + if (!isNetworkConnected(GacApplication.getInstance())) { + stringId = R.string.network_error; + } else { + stringId = R.string.notify_no_network; + } + } else if (throwable instanceof SocketTimeoutException || throwable instanceof TimeoutException) { + //前者是通过OkHttpClient设置的超时引发的异常,后者是对单个请求调用timeout方法引发的超时异常 + stringId = R.string.time_out_please_try_again_later; + } else if (throwable instanceof ConnectException) { + stringId = R.string.esky_service_exception; + } + return stringId == -1 ? null : GacApplication.getInstance().getString(stringId); + } + + public static boolean isNetworkConnected(Context context) { + if (context != null) { + ConnectivityManager mConnectivityManager = + (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo(); + if (mNetworkInfo != null) { + return mNetworkInfo.isAvailable(); + } + } + + return false; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/http/OnError.java b/app/src/main/java/com/tairui/gov_affairs_cloud/http/OnError.java new file mode 100644 index 0000000..0cbc4af --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/http/OnError.java @@ -0,0 +1,17 @@ +package com.tairui.gov_affairs_cloud.http; + + +import io.reactivex.functions.Consumer; + +/** + * RxJava 错误回调 ,加入网络异常处理 + */ +public interface OnError extends Consumer { + + @Override + default void accept(Throwable throwable) throws Exception { + onError(new ErrorInfo(throwable)); + } + + void onError(ErrorInfo error) throws Exception; +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/http/Response.java b/app/src/main/java/com/tairui/gov_affairs_cloud/http/Response.java new file mode 100644 index 0000000..d56fea7 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/http/Response.java @@ -0,0 +1,32 @@ +package com.tairui.gov_affairs_cloud.http; + +public class Response { + + private int code; + private String msg; + private T data; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/http/ResponseParser.java b/app/src/main/java/com/tairui/gov_affairs_cloud/http/ResponseParser.java new file mode 100644 index 0000000..413bbea --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/http/ResponseParser.java @@ -0,0 +1,72 @@ +package com.tairui.gov_affairs_cloud.http; + +import java.io.IOException; +import java.lang.reflect.Type; + +import com.tairui.gov_affairs_cloud.entity.Api; +import com.tairui.gov_affairs_cloud.http.exception.AuthException; + +import android.annotation.SuppressLint; +import android.text.TextUtils; +import rxhttp.wrapper.annotation.Parser; +import rxhttp.wrapper.entity.ParameterizedTypeImpl; +import rxhttp.wrapper.exception.ParseException; +import rxhttp.wrapper.parse.AbstractParser; + +/** + * Response 数据解析器,解析完成对Response对象做判断,如果ok,返回数据 T + * User: ljx + * Date: 2018/10/23 + * Time: 13:49 + */ +@Parser(name = "Response") +public class ResponseParser extends AbstractParser { + + /** + * 此构造方法适用于任意Class对象,但更多用于带泛型的Class对象,如:List + *

+ * 用法: + * Java: .asParser(new ResponseParser>(){}) + * Kotlin: .asParser(object : ResponseParser>() {}) + *

+ * 注:此构造方法一定要用protected关键字修饰,否则调用此构造方法将拿不到泛型类型 + */ + protected ResponseParser() { + super(); + } + + /** + * 此构造方法仅适用于不带泛型的Class对象,如: Student.class + *

+ * 用法 + * Java: .asParser(new ResponseParser<>(Student.class)) 或者 .asResponse(Student.class) + * Kotlin: .asParser(ResponseParser(Student::class.java)) 或者 .asResponse(Student::class.java) + */ + public ResponseParser(Type type) { + super(type); + } + + @SuppressWarnings("unchecked") + @SuppressLint("NewApi") + @Override + public T onParse(okhttp3.Response response) throws IOException { + final Type type = ParameterizedTypeImpl.get(Response.class, mType); //获取泛型类型 + Response data = convert(response, type); + T t = data.getData(); //获取data字段 + if (t == null && mType == String.class) { + /* + * 考虑到有些时候服务端会返回:{"errorCode":0,"errorMsg":"关注成功"} 类似没有data的数据 + * 此时code正确,但是data字段为空,直接返回data的话,会报空指针错误, + * 所以,判断泛型为String类型时,重新赋值,并确保赋值不为null + */ + t = (T) (TextUtils.isEmpty(data.getMsg()) ? "" : data.getMsg()); + } + if (data.getCode() == Api.CODE_SUCCESS_REQUEST) { + return t; + } else if (data.getCode() == Api.CODE_AUTH_ERROR) { + throw new AuthException("-1", data.getMsg(), response); + } else { + throw new ParseException("-1", data.getMsg(), response); + } + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/http/SingleUploadParser.java b/app/src/main/java/com/tairui/gov_affairs_cloud/http/SingleUploadParser.java new file mode 100644 index 0000000..9b5a226 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/http/SingleUploadParser.java @@ -0,0 +1,51 @@ +package com.tairui.gov_affairs_cloud.http; + +import java.io.IOException; +import java.lang.reflect.Type; + +import com.tairui.gov_affairs_cloud.entity.Api; + +import android.text.TextUtils; +import rxhttp.wrapper.annotation.Parser; +import rxhttp.wrapper.entity.ParameterizedTypeImpl; +import rxhttp.wrapper.exception.ParseException; +import rxhttp.wrapper.parse.AbstractParser; + +/** + * Response 数据解析器,解析完成对Response对象做判断,如果ok,返回数据 T + * User: ljx + * Date: 2018/10/23 + * Time: 13:49 + */ +@Parser(name = "SingleUpload") +public class SingleUploadParser extends AbstractParser { + + protected SingleUploadParser() { + super(); + } + + public SingleUploadParser(Type type) { + super(type); + } + + @SuppressWarnings("unchecked") + @Override + public T onParse(okhttp3.Response response) throws IOException { + final Type type = ParameterizedTypeImpl.get(Response.class, mType); //获取泛型类型 + Response data = convert(response, type); + T t = data.getData(); //获取data字段 + if (t == null && mType == String.class) { + /* + * 考虑到有些时候服务端会返回:{"errorCode":0,"errorMsg":"关注成功"} 类似没有data的数据 + * 此时code正确,但是data字段为空,直接返回data的话,会报空指针错误, + * 所以,判断泛型为String类型时,重新赋值,并确保赋值不为null + */ + t = (T) (TextUtils.isEmpty(data.getMsg()) ? "" : data.getMsg()); + } + if (data.getCode() == Api.CODE_SUCCESS_REQUEST) { + return t; + } else { + throw new ParseException(String.valueOf(data.getCode()), data.getMsg(), response); + } + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/http/exception/AuthException.java b/app/src/main/java/com/tairui/gov_affairs_cloud/http/exception/AuthException.java new file mode 100644 index 0000000..d68d4db --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/http/exception/AuthException.java @@ -0,0 +1,79 @@ +package com.tairui.gov_affairs_cloud.http.exception; + +import java.io.IOException; + +import io.reactivex.annotations.NonNull; +import io.reactivex.annotations.Nullable; +import okhttp3.Headers; +import okhttp3.Request; +import okhttp3.Response; + +/** + * 没有身份信息,需要重新登录 + */ +public class AuthException extends IOException { + + private String errorCode; + + private String requestMethod; //请求方法,Get/Post等 + private Headers responseHeaders; //响应头 + private String requestResult; //请求结果 + + @Deprecated + public AuthException(String message, Response response) { + this("-1", message, response, null); + } + + @Deprecated + public AuthException(String message, Response response, String result) { + this("-1", message, response, result); + } + + public AuthException(@NonNull String code, String message, Response response) { + this(code, message, response, null); + } + + public AuthException(@NonNull String code, String message, Response response, String result) { + super(message); + errorCode = code; + requestResult = result; + + Request request = response.request(); + requestMethod = request.method(); + responseHeaders = response.headers(); + + + } + + public String getRequestResult() { + return requestResult; + } + + public String getErrorCode() { + return errorCode; + } + + public String getRequestMethod() { + return requestMethod; + } + + + public Headers getResponseHeaders() { + return responseHeaders; + } + + @Nullable + @Override + public String getLocalizedMessage() { + return errorCode; + } + + @Override + public String toString() { + return getClass().getName() + ":" + + " Method=" + requestMethod + + " Code=" + errorCode + + "\n\n" + responseHeaders + + "\nmessage = " + getMessage(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/MainActivity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/MainActivity.java new file mode 100644 index 0000000..8968b6f --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/MainActivity.java @@ -0,0 +1,122 @@ +package com.tairui.gov_affairs_cloud.ui; + +import java.util.ArrayList; + +import com.flyco.tablayout.listener.CustomTabEntity; +import com.flyco.tablayout.listener.OnTabSelectListener; +import com.gyf.immersionbar.ImmersionBar; +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.base.BaseActivity; +import com.tairui.gov_affairs_cloud.base.BaseFragment; +import com.tairui.gov_affairs_cloud.base.adapter.TabFragmentPagerAdapter; +import com.tairui.gov_affairs_cloud.databinding.ActivityMainBinding; +import com.tairui.gov_affairs_cloud.entity.TabEntity; +import com.tairui.gov_affairs_cloud.ui.ai.AiFragment; +import com.tairui.gov_affairs_cloud.ui.home.HomeFragment; +import com.tairui.gov_affairs_cloud.ui.my.MyFragment; +import com.tairui.gov_affairs_cloud.ui.todo.TodoFragment; +import com.tairui.gov_affairs_cloud.ui.workspace.WorkSpaceFragment; + +import android.os.Bundle; +import androidx.viewpager.widget.ViewPager; + +public class MainActivity extends BaseActivity { + + private boolean isInit = false; + + private ArrayList mFragments = new ArrayList<>(); + private ArrayList mTitles = new ArrayList<>(); + private ArrayList mTabEntities = new ArrayList<>(); + private TabFragmentPagerAdapter mPagerAdapter; + + @Override + protected void initStatusBar() { + ImmersionBar.with(this).fitsSystemWindows(false).transparentStatusBar() + .statusBarDarkFont(false).init(); + } + + @Override + protected Class getBindingClass() { + return ActivityMainBinding.class; + } + + @Override + protected void onFindView(Bundle savedInstanceState) { + mTabEntities.add(new TabEntity("首页", R.mipmap.tab_home_select, R.mipmap.tab_home_normal)); + mTitles.add("首页"); + mFragments.add(new HomeFragment()); + mTabEntities.add(new TabEntity("工作台", R.mipmap.tab_workspace_select, R.mipmap.tab_workspace_normal)); + mTitles.add("工作台"); + mFragments.add(new WorkSpaceFragment()); + mTabEntities.add(new TabEntity("待办", R.mipmap.tab_todo_select, R.mipmap.tab_todo_normal)); + mTitles.add("待办"); + mFragments.add(new TodoFragment()); + mTabEntities.add(new TabEntity("AI智能", R.mipmap.tab_ai_select, R.mipmap.tab_ai_normal)); + mTitles.add("AI智能"); + mFragments.add(new AiFragment()); + mTabEntities.add(new TabEntity("我的", R.mipmap.tab_my_select, R.mipmap.tab_my_normal)); + mTitles.add("我的"); + mFragments.add(new MyFragment()); + + mPagerAdapter = new TabFragmentPagerAdapter(getSupportFragmentManager(), mTitles, mFragments); + binding.vpContent.setAdapter(mPagerAdapter);//给ViewPager设置适配器 + binding.mainTab.setTabData(mTabEntities); + } + + @Override + protected void onBindListener() { + + binding.mainTab.setOnTabSelectListener(new OnTabSelectListener() { + @Override + public void onTabSelect(int position) { + binding.vpContent.setCurrentItem(position); + if (position == 0 || position == 4) { + ImmersionBar.with(MainActivity.this).fitsSystemWindows(false).transparentStatusBar() + .statusBarDarkFont(false).init(); + } else if (position == 1) { + ImmersionBar.with(MainActivity.this).fitsSystemWindows(false).transparentStatusBar() + .statusBarDarkFont(true).init(); + } else { + ImmersionBar.with(MainActivity.this).fitsSystemWindows(true).statusBarColor(getStatusBarColor()) + .statusBarDarkFont(true).init(); + } + } + + @Override + public void onTabReselect(int position) { + } + }); + + binding.vpContent.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + + } + + @Override + public void onPageSelected(int position) { + binding.mainTab.setCurrentTab(position); + if (position == 0 || position == 4) { + ImmersionBar.with(MainActivity.this).fitsSystemWindows(false).transparentStatusBar() + .statusBarDarkFont(false).init(); + } else if (position == 1) { + ImmersionBar.with(MainActivity.this).fitsSystemWindows(false).transparentStatusBar() + .statusBarDarkFont(true).init(); + } else { + ImmersionBar.with(MainActivity.this).fitsSystemWindows(true).statusBarColor(getStatusBarColor()) + .statusBarDarkFont(true).init(); + } + } + + @Override + public void onPageScrollStateChanged(int state) { + + } + }); + } + + @Override + protected void onApplyData() { + super.onApplyData(); + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/SplashActivity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/SplashActivity.java new file mode 100644 index 0000000..b49e285 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/SplashActivity.java @@ -0,0 +1,136 @@ +package com.tairui.gov_affairs_cloud.ui; + +import java.lang.ref.WeakReference; + +import com.gyf.immersionbar.ImmersionBar; +import com.tairui.gov_affairs_cloud.base.BaseActivity; +import com.tairui.gov_affairs_cloud.config.AppConfig; +import com.tairui.gov_affairs_cloud.databinding.ActivitySplashBinding; +import com.tairui.gov_affairs_cloud.ui.login.LoginActivity; +import com.tairui.gov_affairs_cloud.util.IntentUtil; +import com.tairui.gov_affairs_cloud.util.MyCountDownTimer; +import com.tairui.gov_affairs_cloud.util.SingleClickListener; + +import android.text.TextUtils; +import android.view.View; + +public class SplashActivity extends BaseActivity { + + private CountTimer countTimer; + private static final int INTERVAL = 1000; + private boolean isSkipAble = true;// 跳过按钮可以点击 + + @Override + protected Class getBindingClass() { + return ActivitySplashBinding.class; + } + + @Override + protected void initStatusBar() { + ImmersionBar.with(this).fitsSystemWindows(true).statusBarColor(getStatusBarColor()) + .statusBarDarkFont(true).init(); + } + + @Override + protected void onBindListener() { + binding.txtTimerSplash.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + skipTimeCountDown(); + } + }); + } + + @Override + protected void onApplyData() { + goMain(); + } + + private void goMain() { + // KpLog.getInstance().doSaveEventLog(mContext, true); + //KpLog.getInstance().onAppStart(mContext); + + if (null != binding.txtTimerSplash) { + setGone(binding.txtTimerSplash, true); + countTimer = new CountTimer(3 * 1000, INTERVAL); + WeakReference weakTimerCountDowner = new WeakReference<>(countTimer); + if (null != weakTimerCountDowner.get()) { + weakTimerCountDowner.get().start(); + } + } + } + + /** + * 跳过倒计时 + */ + private void skipTimeCountDown() { + if (isSkipAble) { + isSkipAble = false; + if (null != binding.txtTimerSplash) { + binding.txtTimerSplash.setClickable(false); + } + if (null != countTimer) { + countTimer.cancel(); + countTimer = null; + } + if (TextUtils.isEmpty(AppConfig.getInstance().getToken())) { + IntentUtil.startActivity(mContext, LoginActivity.class, null); + finish(); + } else { + gotoMain(); + } + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (null != countTimer) { + countTimer.cancel(); + countTimer = null; + } + } + + private void gotoMain() { + IntentUtil.startActivity(mContext, MainActivity.class, null); + finish(); + } + + /** + * 倒计时 + */ + class CountTimer extends MyCountDownTimer { + + /** + * @param millisInFuture The number of millis in the future from the call + * to {@link #start()} until the countdown is done and {@link #onFinish()} + * is called. + * @param countDownInterval The interval along the way to receive + * {@link #onTick(long)} callbacks. + */ + CountTimer(long millisInFuture, long countDownInterval) { + super(millisInFuture, countDownInterval); + } + + @Override + public void onTick(long millisUntilFinished) { + int time = (int) (millisUntilFinished / INTERVAL) + 1; + if (null != binding.txtTimerSplash) { + String TIME_PASS = "跳过 "; + binding.txtTimerSplash.setText(TIME_PASS + time); + } + } + + @Override + public void onFinish() { + if (TextUtils.isEmpty(AppConfig.getInstance().getToken())) { + IntentUtil.startActivity(mContext, LoginActivity.class, null); + finish(); + } else { + gotoMain(); + } + } + + } + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/ai/AiFragment.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/ai/AiFragment.java new file mode 100644 index 0000000..cd90576 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/ai/AiFragment.java @@ -0,0 +1,23 @@ +package com.tairui.gov_affairs_cloud.ui.ai; + +import com.tairui.gov_affairs_cloud.base.BaseFragment; +import com.tairui.gov_affairs_cloud.databinding.FragmentAiBinding; + +import android.os.Bundle; +import android.view.View; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +public class AiFragment extends BaseFragment { + + @Override + protected Class getBindingClass() { + return FragmentAiBinding.class; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/grid/GridInfoActivity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/grid/GridInfoActivity.java new file mode 100644 index 0000000..15473bc --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/grid/GridInfoActivity.java @@ -0,0 +1,114 @@ +package com.tairui.gov_affairs_cloud.ui.grid; + +import java.util.List; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.rxjava.rxlife.RxLife; +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.base.BaseActivity; +import com.tairui.gov_affairs_cloud.databinding.ActivityGridInfoBinding; +import com.tairui.gov_affairs_cloud.entity.Api; +import com.tairui.gov_affairs_cloud.http.OnError; +import com.tairui.gov_affairs_cloud.ui.land.entity.LandGridEntity; +import com.tairui.gov_affairs_cloud.util.SingleClickListener; +import com.tairui.gov_affairs_cloud.widget.blankview.interfaces.BlankViewClickListener; + +import android.graphics.Color; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; +import rxhttp.RxHttp; + +public class GridInfoActivity extends BaseActivity { + + private LandGridEntity mData; + private GridAdapter mAdapter; + + @Override + protected Class getBindingClass() { + return ActivityGridInfoBinding.class; + } + + @Override + protected void onFindView(Bundle savedInstanceState) { + binding.recycleView.setHasFixedSize(true); // 如果item布局不会改变大小,设置此属性可提高性能 + binding.recycleView.setLayoutManager(new LinearLayoutManager(mContext)); + binding.recycleView.setNestedScrollingEnabled(false); // 禁用RecyclerView的嵌套滚动 + mAdapter = new GridAdapter(); + binding.recycleView.setAdapter(mAdapter); + } + + @Override + protected void onBindListener() { + binding.btnBack.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + finish(); + } + }); + binding.blankView.setOnBlankViewClickListener(new BlankViewClickListener() { + @Override + public void onBlankViewClickListener(View view) { + onApplyData(); + } + }); + } + + @Override + protected void onApplyData() { + setGone(binding.loadingView, true); + setGone(binding.contentLayout, false); + setGone(binding.blankView, false); + RxHttp.get(Api.LAND_GRID) + .asResponse(LandGridEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + mData = data; + initView(); + }, (OnError) error -> { + showToast(error.getErrorMsg()); + setGone(binding.loadingView, false); + setGone(binding.contentLayout, false); + setGone(binding.blankView, true); + }); + } + + private void initView() { + setText(binding.tvFarmerCount, mData.getFarmerCount().toString()); + setText(binding.tvCooperativeCount, mData.getCooperativeCount().toString()); + setText(binding.tvGridCount, mData.getTotal().toString()); + + LandGridEntity headerItem = new LandGridEntity(); + List childList = mData.getChildren(); + childList.add(0, headerItem); + mAdapter.setNewData(childList); + setGone(binding.loadingView, false); + setGone(binding.contentLayout, true); + setGone(binding.blankView, false); + } + + private class GridAdapter extends BaseQuickAdapter { + + public GridAdapter() { + super(R.layout.item_grid_info); + } + + @Override + protected void convert(@NonNull BaseViewHolder holder, LandGridEntity entity) { + if (TextUtils.isEmpty(entity.getRegionCode())) { + holder.setTextColor(R.id.tvItemGridName, getResColor(R.color.color_txt_black)); + holder.setText(R.id.tvItemGridName, "网格名称"); + holder.setText(R.id.tvItemFarmerCount, "绑定用户数"); + holder.setText(R.id.tvItemCooperativeCount, "绑定合作社"); + } else { + holder.setTextColor(R.id.tvItemGridName, Color.parseColor("#80000000")); + holder.setText(R.id.tvItemGridName, entity.getRegionName()); + holder.setText(R.id.tvItemFarmerCount, entity.getFarmerCount().toString()); + holder.setText(R.id.tvItemCooperativeCount, entity.getCooperativeCount().toString()); + } + } + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/home/HomeFragment.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/home/HomeFragment.java new file mode 100644 index 0000000..1787432 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/home/HomeFragment.java @@ -0,0 +1,171 @@ +package com.tairui.gov_affairs_cloud.ui.home; + +import java.util.ArrayList; +import java.util.List; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.rxjava.rxlife.RxLife; +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.base.BaseFragment; +import com.tairui.gov_affairs_cloud.databinding.FragmentHomeBinding; +import com.tairui.gov_affairs_cloud.entity.Api; +import com.tairui.gov_affairs_cloud.entity.PieBean; +import com.tairui.gov_affairs_cloud.http.OnError; +import com.tairui.gov_affairs_cloud.ui.home.entity.HomeEntity; +import com.tairui.gov_affairs_cloud.ui.land.LandActivity; +import com.tairui.gov_affairs_cloud.util.DensityUtils; +import com.tairui.gov_affairs_cloud.util.IntentUtil; +import com.tairui.gov_affairs_cloud.util.glide.GlideLoader; +import com.tairui.gov_affairs_cloud.widget.charts.bean.BarBean; +import com.tairui.gov_affairs_cloud.widget.charts.piechart.PieChartLayout; + +import android.graphics.Color; +import android.view.View; +import android.widget.ImageView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.GridLayoutManager; +import rxhttp.RxHttp; + +public class HomeFragment extends BaseFragment { + + private FuncAdapter funcAdapter; + + @Override + protected Class getBindingClass() { + return FragmentHomeBinding.class; + } + + @Override + protected void onFindView(View rootView) { + + binding.funcRecycleview.setLayoutManager(new GridLayoutManager(mContext, 4)); + funcAdapter = new FuncAdapter(); + binding.funcRecycleview.setAdapter(funcAdapter); + + binding.tudiChart.setRingWidth(DensityUtils.dp2px(getActivity(), 6)); + binding.tudiChart.setOutSpace(DensityUtils.dp2px(getActivity(), 0)); + binding.tudiChart.setTextSpace(DensityUtils.dp2px(getActivity(), 0)); + binding.tudiChart.setRectSpace(DensityUtils.dp2px(getActivity(), 3)); + binding.tudiChart.setTagModul(PieChartLayout.TAG_MODUL.MODEUL_NULL); + binding.tudiChart.setLoading(true); + + binding.tourupinChart.setLoading(true); + binding.tourupinChart.setBarNum(1); + binding.tourupinChart.setBarColor(new int[] {Color.parseColor("#007AFF")}); + binding.tourupinChart.setBarItemSpace(DensityUtils.dp2px(getActivity(), 10)); + binding.tourupinChart.setBarWidth(DensityUtils.dp2px(getActivity(), 5)); + binding.tourupinChart.setTextSizeTag(0); + + binding.zhutiChart.setRingWidth(DensityUtils.dp2px(getActivity(), 6)); + binding.zhutiChart.setOutSpace(DensityUtils.dp2px(getActivity(), 0)); + binding.zhutiChart.setTextSpace(DensityUtils.dp2px(getActivity(), 0)); + binding.zhutiChart.setRectSpace(DensityUtils.dp2px(getActivity(), 3)); + binding.zhutiChart.setTagModul(PieChartLayout.TAG_MODUL.MODEUL_NULL); + binding.zhutiChart.setLoading(true); + + binding.suyuanChart.setLoading(true); + binding.suyuanChart.setBarNum(1); + binding.suyuanChart.setBarColor(new int[] {Color.parseColor("#007AFF")}); + binding.suyuanChart.setBarItemSpace(DensityUtils.dp2px(getActivity(), 10)); + binding.suyuanChart.setBarWidth(DensityUtils.dp2px(getActivity(), 5)); + binding.suyuanChart.setTextSizeTag(0); + } + + @Override + protected void onBindListener() { + binding.blankView.setOnBlankViewClickListener(view -> { + onApplyData(); + }); + funcAdapter.setOnItemClickListener((baseQuickAdapter, view, i) -> { + if (i == 1) { + IntentUtil.startActivity(mContext, LandActivity.class); + } + }); + } + + @Override + protected void onApplyData() { + binding.loadingView.setVisibility(View.VISIBLE); + binding.blankView.setVisibility(View.GONE); + RxHttp.get(Api.HOME) + .asResponse(HomeEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + initView(data); + setGone(binding.container, true); + if (binding.loadingView.getVisibility() == View.VISIBLE) { + binding.loadingView.setVisibility(View.GONE); + } + }, (OnError) error -> { + showToast(error.getErrorMsg()); + binding.loadingView.setVisibility(View.GONE); + binding.blankView.setVisibility(View.VISIBLE); + }); + } + + private void initView(HomeEntity data) { + setText(binding.tvTodoCount, data.getTodoCount().toString()); + setText(binding.userNameTv, data.getUserInfo().getUsername()); + setText(binding.userDepartmentTv, data.getUserInfo().getOrganization() + " - " + data.getUserInfo().getDepartmental()); + setText(binding.userTelTv, data.getUserInfo().getPhone() + " " + data.getUserInfo().getNo()); + GlideLoader.loadCircle(binding.userHeadIv, data.getUserInfo().getHeadPic()); + funcAdapter.setNewData(data.getFunction()); + + setText(binding.tudiCount, data.getDatas().getLandArea().getTotal().toString()); + List datalist = new ArrayList<>(); + for (HomeEntity.DatasEntity.LandAreaEntity.ListEntity entity : data.getDatas().getLandArea().getList()) { + datalist.add(new PieBean(entity.getArea(), entity.getName())); + } + binding.tudiChart.setLoading(false); + binding.tudiChart.setChartData(PieBean.class, "Numner", "Name", datalist, null); + + setText(binding.tourupinCount, data.getDatas().getAdditives().getTotal().toString()); + List strXList = new ArrayList<>(); + List> dataList = new ArrayList<>(); + for (HomeEntity.DatasEntity.AdditivesEntity.ListEntityX entity : data.getDatas().getAdditives().getList()) { + List list = new ArrayList<>(); + list.add(new BarBean(entity.getCount(), entity.getName())); + dataList.add(list); + strXList.add(entity.getName()); + } + binding.tourupinChart.setLoading(false); + binding.tourupinChart.setData(dataList, strXList); + + //TODO + setText(binding.zhutiCount, data.getDatas().getBusiness().getTotal().toString()); + datalist.clear(); + datalist.add(new PieBean(24, "农企合作社")); + datalist.add(new PieBean(12, "农资企业")); + datalist.add(new PieBean(20, "加工企业")); + datalist.add(new PieBean(5, "种源企业")); + binding.zhutiChart.setLoading(false); + binding.zhutiChart.setChartData(PieBean.class, "Numner", "Name", datalist, null); + + strXList.clear(); + dataList.clear(); + setText(binding.suyuanCount, data.getDatas().getProducts().getTotal().toString()); + for (HomeEntity.DatasEntity.ProductsEntity.ListEntityXXX entity : data.getDatas().getProducts().getList()) { + List list = new ArrayList<>(); + list.add(new BarBean(entity.getCount(), entity.getName())); + dataList.add(list); + strXList.add(entity.getName()); + } + binding.suyuanChart.setLoading(false); + binding.suyuanChart.setData(dataList, strXList); + } + + private class FuncAdapter extends BaseQuickAdapter { + + public FuncAdapter() { + super(R.layout.item_func_layout); + } + + @Override + protected void convert(@NonNull BaseViewHolder holder, HomeEntity.FunctionEntity entity) { + holder.setText(R.id.funcTv, entity.getName()); + ImageView iv = holder.getView(R.id.funcIv); + GlideLoader.loadOriginal(iv, entity.getIcon(), R.mipmap.func_1); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/home/entity/HomeEntity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/home/entity/HomeEntity.java new file mode 100644 index 0000000..3edffe2 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/home/entity/HomeEntity.java @@ -0,0 +1,312 @@ +package com.tairui.gov_affairs_cloud.ui.home.entity; + +import java.io.Serializable; +import java.util.List; + +import com.google.gson.annotations.SerializedName; +import com.tairui.gov_affairs_cloud.ui.my.entity.UserInfoEntity; + +public class HomeEntity implements Serializable { + + @SerializedName("todoCount") + private Integer todoCount; + @SerializedName("userInfo") + private UserInfoEntity userInfo; + @SerializedName("datas") + private DatasEntity datas; + @SerializedName("function") + private List function; + + public Integer getTodoCount() { + return todoCount; + } + + public void setTodoCount(Integer todoCount) { + this.todoCount = todoCount; + } + + public UserInfoEntity getUserInfo() { + return userInfo; + } + + public void setUserInfo(UserInfoEntity userInfo) { + this.userInfo = userInfo; + } + + public DatasEntity getDatas() { + return datas; + } + + public void setDatas(DatasEntity datas) { + this.datas = datas; + } + + public List getFunction() { + return function; + } + + public void setFunction(List function) { + this.function = function; + } + + + public static class DatasEntity { + @SerializedName("landArea") + private LandAreaEntity landArea; + @SerializedName("additives") + private AdditivesEntity additives; + @SerializedName("business") + private BusinessEntity business; + @SerializedName("products") + private ProductsEntity products; + + public LandAreaEntity getLandArea() { + return landArea; + } + + public void setLandArea(LandAreaEntity landArea) { + this.landArea = landArea; + } + + public AdditivesEntity getAdditives() { + return additives; + } + + public void setAdditives(AdditivesEntity additives) { + this.additives = additives; + } + + public BusinessEntity getBusiness() { + return business; + } + + public void setBusiness(BusinessEntity business) { + this.business = business; + } + + public ProductsEntity getProducts() { + return products; + } + + public void setProducts(ProductsEntity products) { + this.products = products; + } + + public static class LandAreaEntity { + @SerializedName("total") + private Double total; + @SerializedName("list") + private List list; + + public Double getTotal() { + return total; + } + + public void setTotal(Double total) { + this.total = total; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public static class ListEntity { + @SerializedName("name") + private String name; + @SerializedName("area") + private float area; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public float getArea() { + return area; + } + + public void setArea(float area) { + this.area = area; + } + } + } + + public static class AdditivesEntity { + @SerializedName("total") + private Integer total; + @SerializedName("list") + private List list; + + public Integer getTotal() { + return total; + } + + public void setTotal(Integer total) { + this.total = total; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public static class ListEntityX { + @SerializedName("name") + private String name; + @SerializedName("count") + private Integer count; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + } + } + + public static class BusinessEntity { + @SerializedName("total") + private Integer total; + @SerializedName("list") + private List list; + + public Integer getTotal() { + return total; + } + + public void setTotal(Integer total) { + this.total = total; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public static class ListEntityXX { + @SerializedName("name") + private String name; + @SerializedName("count") + private Integer count; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + } + } + + public static class ProductsEntity { + @SerializedName("total") + private Integer total; + @SerializedName("list") + private List list; + + public Integer getTotal() { + return total; + } + + public void setTotal(Integer total) { + this.total = total; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public static class ListEntityXXX { + @SerializedName("name") + private String name; + @SerializedName("count") + private Integer count; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + } + } + } + + public static class FunctionEntity { + @SerializedName("id") + private Integer id; + @SerializedName("icon") + private String icon; + @SerializedName("name") + private String name; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getIcon() { + return icon; + } + + public void setIcon(String icon) { + this.icon = icon; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/AddLandActivity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/AddLandActivity.java new file mode 100644 index 0000000..9d64082 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/AddLandActivity.java @@ -0,0 +1,491 @@ +package com.tairui.gov_affairs_cloud.ui.land; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import com.amap.api.maps.MapsInitializer; +import com.bigkoo.pickerview.builder.OptionsPickerBuilder; +import com.bigkoo.pickerview.view.OptionsPickerView; +import com.google.gson.Gson; +import com.hjq.permissions.OnPermissionCallback; +import com.hjq.permissions.Permission; +import com.hjq.permissions.XXPermissions; +import com.kongzue.albumdialog.PhotoAlbumDialog; +import com.kongzue.albumdialog.util.SelectPhotoCallback; +import com.kongzue.dialogx.dialogs.PopTip; +import com.rxjava.rxlife.RxLife; +import com.tairui.gov_affairs_cloud.base.BaseActivity; +import com.tairui.gov_affairs_cloud.databinding.ActivityAddLandBinding; +import com.tairui.gov_affairs_cloud.entity.Api; +import com.tairui.gov_affairs_cloud.entity.EventConstant; +import com.tairui.gov_affairs_cloud.entity.EventMessage; +import com.tairui.gov_affairs_cloud.entity.UploadEntity; +import com.tairui.gov_affairs_cloud.http.OnError; +import com.tairui.gov_affairs_cloud.ui.land.entity.AddLandEntity; +import com.tairui.gov_affairs_cloud.ui.land.entity.LandAreaRegionEntity; +import com.tairui.gov_affairs_cloud.ui.land.entity.LandGridEntity; +import com.tairui.gov_affairs_cloud.ui.land.entity.LandGroudTypeEntity; +import com.tairui.gov_affairs_cloud.ui.land.entity.LandTypeEntity; +import com.tairui.gov_affairs_cloud.util.ArrayUtil; +import com.tairui.gov_affairs_cloud.util.DensityUtils; +import com.tairui.gov_affairs_cloud.util.IntentUtil; +import com.tairui.gov_affairs_cloud.util.KeybordUtil; +import com.tairui.gov_affairs_cloud.util.SingleClickListener; +import com.tairui.gov_affairs_cloud.util.glide.GlideLoader; +import com.tairui.gov_affairs_cloud.util.location.bean.DrawLatLng; + +import android.graphics.Color; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import androidx.annotation.NonNull; +import rxhttp.RxHttp; +import rxhttp.RxHttpFormParam; + +public class AddLandActivity extends BaseActivity { + + private OptionsPickerView landLandTypePickerView; + private OptionsPickerView landRegionPickerView; + private OptionsPickerView landGridPickerView; + private OptionsPickerView landGroudTypePickerView; + + private List areaPoints; + private String areaPath; + private String landImgPath; + private List landLandTypeData; + private LandTypeEntity selectLandType; + private List landAreaRegionData; + private LandAreaRegionEntity selectRegion; + private LandGridEntity landGridData; + private LandGridEntity selectGrid; + private LandGroudTypeEntity landGroudTypeData; + private LandGroudTypeEntity.RecordsEntity selectLandGroudType; + + private UploadEntity landImgEntity; + private UploadEntity areaImgEntity; + + private AddLandEntity addLandEntity; + + @Override + protected Class getBindingClass() { + return ActivityAddLandBinding.class; + } + + @Override + protected void onQueryArguments() { + EventBus.getDefault().register(this); + } + + @Override + protected void onBindListener() { + binding.btnBack.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + finish(); + } + }); + binding.btnSelectImg.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + selectImg(); + } + }); + binding.btnReSelectImg.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + selectImg(); + } + }); + binding.btnSelectArea.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + checkLocationPermission(); + } + }); + binding.btnReSelectArea.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + checkLocationPermission(); + } + }); + binding.btnSubmit.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + checkSubmit(); + } + }); + binding.inputLandType.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + if (ArrayUtil.notNull(landLandTypeData)) { + KeybordUtil.hideSoftInput(mContext, AddLandActivity.this); + showLandTypeSelectDialog(); + } + } + }); + binding.inputLandRegion.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + if (ArrayUtil.notNull(landAreaRegionData)) { + KeybordUtil.hideSoftInput(mContext, AddLandActivity.this); + showRegionDialog(); + } + } + }); + binding.inputLandGrid.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + if (landGridData != null && ArrayUtil.notNull(landGridData.getChildren())) { + KeybordUtil.hideSoftInput(mContext, AddLandActivity.this); + showLandGridDialog(); + } + } + }); + binding.inputGroudType.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + if (landGroudTypeData != null && ArrayUtil.notNull(landGroudTypeData.getRecords())) { + KeybordUtil.hideSoftInput(mContext, AddLandActivity.this); + showLandGroudTypeDialog(); + } + } + }); + } + + @Override + protected void onApplyData() { + getTypeData(); + getRegionData(); + getGridData(); + getGroudTypeData(); + } + + private void getTypeData() { + RxHttp.get(Api.LAND_TYPE) + .asResponseList(LandTypeEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + landLandTypeData = data; + }, (OnError) error -> showError(error.getErrorMsg())); + } + + private void getRegionData() { + RxHttp.get(Api.LAND_AREA_REGION) + .add("areaCode", "530926") + .asResponseList(LandAreaRegionEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + landAreaRegionData = data; + }, (OnError) error -> showToast(error.getErrorMsg())); + } + + private void getGridData() { + RxHttp.get(Api.LAND_GRID) + .asResponse(LandGridEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + landGridData = data; + }, (OnError) error -> showToast(error.getErrorMsg())); + } + + private void getGroudTypeData() { + RxHttp.get(Api.LAND_GROUD_TYPE) + .add("current", 1) + .add("size", 999) + .asResponse(LandGroudTypeEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + landGroudTypeData = data; + }, (OnError) error -> showToast(error.getErrorMsg())); + } + + private void showLandTypeSelectDialog() { + if (landLandTypePickerView == null) { + List> subLandData = new ArrayList<>(); + List>> childLandData = new ArrayList<>(); + for (LandTypeEntity itemData : landLandTypeData) { + List> childList = new ArrayList<>(); + List aa = new ArrayList<>(); + aa.add(new LandTypeEntity("不限")); + childList.add(aa); + for (LandTypeEntity subItem : itemData.getChildren()) { + List childItemList = new ArrayList<>(); + childItemList.add(new LandTypeEntity("不限")); + childItemList.addAll(subItem.getChildren()); + childList.add(childItemList); + } + List subList = new ArrayList<>(); + subList.add(new LandTypeEntity("不限")); + subList.addAll(itemData.getChildren()); + subLandData.add(subList); + childLandData.add(childList); + } + + landLandTypePickerView = new OptionsPickerBuilder(this, (options1, options2, options3, v) -> { + if (options2 == 0 && options3 == 0) { + selectLandType = landLandTypeData.get(options1); + } else if (options2 != 0 && options3 == 0) { + selectLandType = landLandTypeData.get(options1).getChildren().get(options2 - 1); + } else if (options2 != 0 && options3 != 0) { + selectLandType = landLandTypeData.get(options1).getChildren().get(options2 - 1).getChildren().get(options3 - 1); + } + setText(binding.inputLandType, selectLandType.getLandType()); + binding.inputLandType.requestFocus(); + }).setTitleText("土地类型选择").setContentTextSize(20)//设置滚轮文字大小 + .setSelectOptions(0, 0, 0)//默认选中项 + .setTitleBgColor(Color.WHITE) + .isRestoreItem(true)//切换时是否还原,设置默认选中第一项。 + .isCenterLabel(false) //是否只显示中间选中项的label文字,false则每项item全部都带有label。 + .setOutSideColor(0x00000000) //设置外部遮罩颜色 + .build(); + + landLandTypePickerView.setPicker(landLandTypeData, subLandData, childLandData);//二级选择器 + } + landLandTypePickerView.show(); + } + + private void showRegionDialog() { + if (landRegionPickerView == null) { + List> subLandData = new ArrayList<>(); + for (LandAreaRegionEntity itemData : landAreaRegionData.get(0).getAreaChildVOS()) { + subLandData.add(itemData.getAreaChildVOS()); + } + + landRegionPickerView = new OptionsPickerBuilder(this, (options1, options2, options3, v) -> { + selectRegion = landAreaRegionData.get(0).getAreaChildVOS().get(options1).getAreaChildVOS().get(options2); + setText(binding.inputLandRegion, + landAreaRegionData.get(0).getAreaChildVOS().get(options1).getAreaName() + selectRegion.getAreaName()); + binding.inputLandRegion.requestFocus(); + }).setTitleText("土地区域选择").setContentTextSize(20) + .setSelectOptions(0, 0) + .setTitleBgColor(Color.WHITE) + .isRestoreItem(true)//切换时是否还原,设置默认选中第一项。 + .isCenterLabel(false) //是否只显示中间选中项的label文字,false则每项item全部都带有label。 + .setOutSideColor(0x00000000) //设置外部遮罩颜色 + .build(); + + landRegionPickerView.setPicker(landAreaRegionData.get(0).getAreaChildVOS(), subLandData);//二级选择器 + } + landRegionPickerView.show(); + } + + private void showLandGridDialog() { + if (landGridPickerView == null) { + landGridPickerView = new OptionsPickerBuilder(this, (options1, options2, options3, v) -> { + selectGrid = landGridData.getChildren().get(options1); + setText(binding.inputLandGrid, selectGrid.getRegionName() + "网格"); + binding.inputLandGrid.requestFocus(); + }).setTitleText("土地网格选择").setContentTextSize(20) + .setSelectOptions(0) + .setTitleBgColor(Color.WHITE) + .isRestoreItem(true) + .isCenterLabel(false) + .setOutSideColor(0x00000000) + .build(); + + landGridPickerView.setPicker(landGridData.getChildren()); + } + landGridPickerView.show(); + } + + private void showLandGroudTypeDialog() { + if (landGroudTypePickerView == null) { + landGroudTypePickerView = new OptionsPickerBuilder(this, (options1, options2, options3, v) -> { + selectLandGroudType = landGroudTypeData.getRecords().get(options1); + setText(binding.inputGroudType, selectLandGroudType.getSoilType()); + binding.inputGroudType.requestFocus(); + }).setTitleText("土壤类型选择").setContentTextSize(20) + .setSelectOptions(0) + .setTitleBgColor(Color.WHITE) + .isRestoreItem(true) + .isCenterLabel(false) + .setOutSideColor(0x00000000) + .build(); + + landGroudTypePickerView.setPicker(landGroudTypeData.getRecords()); + } + landGroudTypePickerView.show(); + } + + private void checkSubmit() { + String landName = binding.inputLandName.getText().toString().trim(); + if (TextUtils.isEmpty(landName)) { + PopTip.show("地块名称不能为空").iconError(); + return; + } + String landArea = binding.inputLandArea.getText().toString().trim(); + if (TextUtils.isEmpty(landArea)) { + PopTip.show("地块面积不能为空").iconError(); + return; + } + if (selectLandType == null) { + PopTip.show("请选择土地类型").iconError(); + return; + } + if (selectRegion == null) { + PopTip.show("请选择土地所属区域").iconError(); + return; + } + String landAddress = binding.inputLandAddress.getText().toString().trim(); + if (TextUtils.isEmpty(landAddress)) { + PopTip.show("土地具体位置不能为空").iconError(); + return; + } + if (selectGrid == null) { + PopTip.show("请选择土地所属网格").iconError(); + return; + } + if (selectLandGroudType == null) { + PopTip.show("请选择土壤类型").iconError(); + return; + } + if (landImgPath == null) { + PopTip.show("请选择土地照片").iconError(); + return; + } + if (areaPoints == null) { + PopTip.show("请选择土地范围").iconError(); + return; + } + showLoading(); + uploadLandImg(); + } + + private void uploadLandImg() { + RxHttpFormParam http = RxHttp.postForm(Api.FILE_UPLOAD); + http.addFile("file", new File(landImgPath)); + http.asSingleUpload(UploadEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + landImgEntity = data; + uploadAreaImg(); + }, (OnError) error -> { + PopTip.show("图片上传失败:" + error.getErrorMsg()).iconError(); + hideLoading(); + }); + } + + private void uploadAreaImg() { + RxHttpFormParam http = RxHttp.postForm(Api.FILE_UPLOAD); + http.addFile("file", new File(areaPath)); + http.asSingleUpload(UploadEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + areaImgEntity = data; + doAddLand(); + }, (OnError) error -> { + PopTip.show("图片上传失败:" + error.getErrorMsg()).iconError(); + hideLoading(); + }); + } + + private void doAddLand() { + String landName = binding.inputLandName.getText().toString().trim(); + Double landArea = Double.parseDouble(binding.inputLandArea.getText().toString().trim()); + String landAddress = binding.inputLandAddress.getText().toString().trim(); + String scope = new Gson().toJson(areaPoints); + RxHttp.postJson(Api.ADD_LAND) + .add("landName", landName) + .add("area", landArea) + .add("landType", selectLandType.getId()) + .add("villageCode", selectRegion.getAreaCode()) + .add("address", landAddress) + .add("gridId", selectGrid.getRegionCode()) + .add("soilTypeId", selectLandGroudType.getId()) + .add("landUrl", landImgEntity.getUrl()) + .add("scope", scope) + .add("scopeImg", areaImgEntity.getUrl()) + .asResponse(AddLandEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + hideLoading(); + PopTip.show("基本信息提交成功,请补充产权信息").iconSuccess(); + Bundle bundle = new Bundle(); + bundle.putString("id", data.getId()); + IntentUtil.startActivity(mContext, AddLandProductActivity.class, bundle); + finish(); + }, (OnError) error -> { + PopTip.show(error.getErrorMsg()).iconError(); + hideLoading(); + }); + } + + private void selectImg() { + PhotoAlbumDialog.build() + .setCompressQuality(90) //开启压缩并指定质量 90% + .setCompressPhoto(false) //是否压缩(开启回调格式为 jpg,不开启回调格式为 png) + .setMaxSelectPhotoCount(1) //最多选择三张照片 + .setClip(false) //开启裁剪模式 + .setMaxSize(1000) //最高分辨率 1000(宽或高大于 1000会被等比缩小到 1000内) + .setMaxWidth(1000) //最大宽度 + .setMaxHeight(1000) //最大高度 + .setCallback(new SelectPhotoCallback() { + + //单张模式回调(二者其一任选) + @Override + public void selectedPhoto(String selectedPhotos) { + landImgPath = selectedPhotos; + GlideLoader.loadOriginal(binding.imgLand, selectedPhotos); + setGone(binding.imgLand, true); + setGone(binding.btnReSelectImg, true); + } + }) + .setDialogDialogImplCallback(dialog -> dialog.setRadius(DensityUtils.dp2px(mContext, 25))) + .show(this); + } + + private void checkLocationPermission() { + XXPermissions.with(this) + // 申请单个权限 + .permission(Permission.ACCESS_FINE_LOCATION) + .permission(Permission.ACCESS_COARSE_LOCATION) + .request(new OnPermissionCallback() { + @Override + public void onGranted(@NonNull List permissions, boolean allGranted) { + if (!allGranted) { + showToast("获取部分权限成功,但部分权限未正常授予"); + return; + } + MapsInitializer.updatePrivacyShow(mContext, true, true); + MapsInitializer.updatePrivacyAgree(mContext, true); + IntentUtil.startActivity(mContext, SelectLandAreaActivity.class); + } + + @Override + public void onDenied(@NonNull List permissions, boolean doNotAskAgain) { + if (doNotAskAgain) { + showToast("被永久拒绝授权,请手动授予定位权限"); + // 如果是被永久拒绝就跳转到应用权限系统设置页面 + XXPermissions.startPermissionActivity(mContext, permissions); + } else { + showToast("获取定位权限失败"); + } + } + }); + } + + @Override + protected void onDestroy() { + EventBus.getDefault().unregister(this); + super.onDestroy(); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageReceive(EventMessage message) { + if (null != message && !TextUtils.isEmpty(message.getLabel())) { + if (EventConstant.SELECT_AREA.equals(message.getLabel())) { + areaPoints = (List) message.getData(); + areaPath = (String) message.getSubData(); + GlideLoader.loadOriginal(binding.imgArea, areaPath); + setGone(binding.btnSelectArea, false); + setGone(binding.btnReSelectArea, true); + setGone(binding.layoutArea, true); + } + } + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/AddLandProductActivity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/AddLandProductActivity.java new file mode 100644 index 0000000..c531e4a --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/AddLandProductActivity.java @@ -0,0 +1,154 @@ +package com.tairui.gov_affairs_cloud.ui.land; + +import java.io.File; + +import com.kongzue.albumdialog.PhotoAlbumDialog; +import com.kongzue.albumdialog.util.SelectPhotoCallback; +import com.kongzue.dialogx.dialogs.PopTip; +import com.rxjava.rxlife.RxLife; +import com.tairui.gov_affairs_cloud.base.BaseActivity; +import com.tairui.gov_affairs_cloud.databinding.ActivityAddLandProductBinding; +import com.tairui.gov_affairs_cloud.entity.Api; +import com.tairui.gov_affairs_cloud.entity.UploadEntity; +import com.tairui.gov_affairs_cloud.http.OnError; +import com.tairui.gov_affairs_cloud.util.DensityUtils; +import com.tairui.gov_affairs_cloud.util.SingleClickListener; +import com.tairui.gov_affairs_cloud.util.glide.GlideLoader; + +import android.text.TextUtils; +import android.view.View; +import rxhttp.RxHttp; +import rxhttp.RxHttpFormParam; + +public class AddLandProductActivity extends BaseActivity { + private String landImgPath; + private UploadEntity landImgEntity; + + private String addLandId; + + @Override + protected Class getBindingClass() { + return ActivityAddLandProductBinding.class; + } + + @Override + protected void onQueryArguments() { + addLandId = getIntent().getStringExtra("id"); + } + + @Override + protected void onBindListener() { + binding.btnBack.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + finish(); + } + }); + binding.btnSelectImg.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + selectImg(); + } + }); + binding.btnReSelectImg.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + selectImg(); + } + }); + binding.btnSubmit.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + checkSubmit(); + } + }); + } + + private void checkSubmit() { + if (addLandId == null) { + PopTip.show("前置数据为空").iconError(); + return; + } + String properName = binding.inputPropertyName.getText().toString().trim(); + if (TextUtils.isEmpty(properName)) { + PopTip.show("姓名不能为空").iconError(); + return; + } + String properPhone = binding.inputPropertyPhone.getText().toString().trim(); + if (TextUtils.isEmpty(properPhone)) { + PopTip.show("电话不能为空").iconError(); + return; + } + String landCode = binding.inputLandCode.getText().toString().trim(); + if (TextUtils.isEmpty(landCode)) { + PopTip.show("产权编号不能为空").iconError(); + return; + } + if (landImgPath == null) { + PopTip.show("请选择产权证明文件").iconError(); + return; + } + showLoading(); + uploadLandImg(); + } + + private void uploadLandImg() { + RxHttpFormParam http = RxHttp.postForm(Api.FILE_UPLOAD); + http.addFile("file", new File(landImgPath)); + http.asSingleUpload(UploadEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + landImgEntity = data; + doAddLandProduct(); + }, (OnError) error -> { + PopTip.show("图片上传失败:" + error.getErrorMsg()).iconError(); + hideLoading(); + }); + } + + private void doAddLandProduct() { + String properName = binding.inputPropertyName.getText().toString().trim(); + String properPhone = binding.inputPropertyPhone.getText().toString().trim(); + String landCode = binding.inputLandCode.getText().toString().trim(); + RxHttp.postJson(Api.EDIT_LAND) + .add("id", addLandId) + .add("propertyName", properName) + .add("propertyPhone", properPhone) + .add("landCode", landCode) + .add("propertyCertificateUrl", landImgEntity.getUrl()) + .asResponse(Boolean.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + hideLoading(); + PopTip.show("提交成功").iconSuccess(); + finish(); + }, (OnError) error -> { + PopTip.show(error.getErrorMsg()).iconError(); + hideLoading(); + }); + } + + private void selectImg() { + PhotoAlbumDialog.build() + .setCompressQuality(90) //开启压缩并指定质量 90% + .setCompressPhoto(false) //是否压缩(开启回调格式为 jpg,不开启回调格式为 png) + .setMaxSelectPhotoCount(1) //最多选择三张照片 + .setClip(false) //开启裁剪模式 + .setMaxSize(1000) //最高分辨率 1000(宽或高大于 1000会被等比缩小到 1000内) + .setMaxWidth(1000) //最大宽度 + .setMaxHeight(1000) //最大高度 + .setCallback(new SelectPhotoCallback() { + + //单张模式回调(二者其一任选) + @Override + public void selectedPhoto(String selectedPhotos) { + landImgPath = selectedPhotos; + GlideLoader.loadOriginal(binding.imgLand, selectedPhotos); + setGone(binding.imgLand, true); + setGone(binding.btnReSelectImg, true); + } + }) + .setDialogDialogImplCallback(dialog -> dialog.setRadius(DensityUtils.dp2px(mContext, 25))) + .show(this); + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/EditLandBaseInfoActivity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/EditLandBaseInfoActivity.java new file mode 100644 index 0000000..bcf6306 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/EditLandBaseInfoActivity.java @@ -0,0 +1,498 @@ +package com.tairui.gov_affairs_cloud.ui.land; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import com.amap.api.maps.MapsInitializer; +import com.bigkoo.pickerview.builder.OptionsPickerBuilder; +import com.bigkoo.pickerview.view.OptionsPickerView; +import com.google.gson.Gson; +import com.hjq.permissions.OnPermissionCallback; +import com.hjq.permissions.Permission; +import com.hjq.permissions.XXPermissions; +import com.kongzue.albumdialog.PhotoAlbumDialog; +import com.kongzue.albumdialog.util.SelectPhotoCallback; +import com.kongzue.dialogx.dialogs.PopTip; +import com.rxjava.rxlife.RxLife; +import com.tairui.gov_affairs_cloud.base.BaseActivity; +import com.tairui.gov_affairs_cloud.databinding.ActivityEditLandBaseInfoBinding; +import com.tairui.gov_affairs_cloud.entity.Api; +import com.tairui.gov_affairs_cloud.entity.EventConstant; +import com.tairui.gov_affairs_cloud.entity.EventMessage; +import com.tairui.gov_affairs_cloud.entity.UploadEntity; +import com.tairui.gov_affairs_cloud.http.OnError; +import com.tairui.gov_affairs_cloud.ui.land.entity.LandAreaRegionEntity; +import com.tairui.gov_affairs_cloud.ui.land.entity.LandGridEntity; +import com.tairui.gov_affairs_cloud.ui.land.entity.LandGroudTypeEntity; +import com.tairui.gov_affairs_cloud.ui.land.entity.LandResourceEntity; +import com.tairui.gov_affairs_cloud.ui.land.entity.LandTypeEntity; +import com.tairui.gov_affairs_cloud.util.AppUtil; +import com.tairui.gov_affairs_cloud.util.ArrayUtil; +import com.tairui.gov_affairs_cloud.util.DensityUtils; +import com.tairui.gov_affairs_cloud.util.IntentUtil; +import com.tairui.gov_affairs_cloud.util.KeybordUtil; +import com.tairui.gov_affairs_cloud.util.SingleClickListener; +import com.tairui.gov_affairs_cloud.util.glide.GlideLoader; +import com.tairui.gov_affairs_cloud.util.location.bean.DrawLatLng; + +import android.graphics.Color; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import androidx.annotation.NonNull; +import rxhttp.RxHttp; +import rxhttp.RxHttpFormParam; +import rxhttp.RxHttpJsonParam; + +public class EditLandBaseInfoActivity extends BaseActivity { + + private OptionsPickerView landLandTypePickerView; + private OptionsPickerView landRegionPickerView; + private OptionsPickerView landGridPickerView; + private OptionsPickerView landGroudTypePickerView; + + private List areaPoints; + private String areaPath; + private String landImgPath; + private List landLandTypeData; + private LandTypeEntity selectLandType; + private List landAreaRegionData; + private LandAreaRegionEntity selectRegion; + private LandGridEntity landGridData; + private LandGridEntity selectGrid; + private LandGroudTypeEntity landGroudTypeData; + private LandGroudTypeEntity.RecordsEntity selectLandGroudType; + + private UploadEntity landImgEntity; + private UploadEntity areaImgEntity; + + private LandResourceEntity.RecordsEntity mData; + + @Override + protected Class getBindingClass() { + return ActivityEditLandBaseInfoBinding.class; + } + + @Override + protected void onQueryArguments() { + EventBus.getDefault().register(this); + mData = (LandResourceEntity.RecordsEntity) getIntent().getSerializableExtra("data"); + } + + @Override + protected void onFindView(Bundle savedInstanceState) { + setText(binding.inputLandName, mData.getLandName()); + setText(binding.inputLandArea, mData.getArea().toString()); + setText(binding.inputLandType, mData.getLandTypeName()); + setText(binding.inputLandRegion, mData.getFullRegionName()); + setText(binding.inputLandAddress, mData.getAddress()); + setText(binding.inputLandGrid, mData.getGridName()); + setText(binding.inputGroudType, mData.getSoilType()); + if (mData.getLandUrl().startsWith("http")) { + GlideLoader.loadOriginal(binding.imgLand, mData.getLandUrl()); + } else { + GlideLoader.loadOriginal(binding.imgLand, AppUtil.getImageUrl(mData.getLandUrl())); + } + GlideLoader.loadOriginal(binding.imgArea, AppUtil.getImageUrl(mData.getScopeImg())); + } + + @Override + protected void onBindListener() { + binding.btnBack.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + finish(); + } + }); + binding.btnSelectImg.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + selectImg(); + } + }); + binding.btnReSelectImg.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + selectImg(); + } + }); + binding.btnReSelectArea.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + checkLocationPermission(); + } + }); + binding.btnSubmit.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + checkSubmit(); + } + }); + binding.inputLandType.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + if (ArrayUtil.notNull(landLandTypeData)) { + KeybordUtil.hideSoftInput(mContext, EditLandBaseInfoActivity.this); + showLandTypeSelectDialog(); + } + } + }); + binding.inputLandRegion.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + if (ArrayUtil.notNull(landAreaRegionData)) { + KeybordUtil.hideSoftInput(mContext, EditLandBaseInfoActivity.this); + showRegionDialog(); + } + } + }); + binding.inputLandGrid.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + if (landGridData != null && ArrayUtil.notNull(landGridData.getChildren())) { + KeybordUtil.hideSoftInput(mContext, EditLandBaseInfoActivity.this); + showLandGridDialog(); + } + } + }); + binding.inputGroudType.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + if (landGroudTypeData != null && ArrayUtil.notNull(landGroudTypeData.getRecords())) { + KeybordUtil.hideSoftInput(mContext, EditLandBaseInfoActivity.this); + showLandGroudTypeDialog(); + } + } + }); + } + + @Override + protected void onApplyData() { + getTypeData(); + getRegionData(); + getGridData(); + getGroudTypeData(); + } + + private void getTypeData() { + RxHttp.get(Api.LAND_TYPE) + .asResponseList(LandTypeEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + landLandTypeData = data; + }, (OnError) error -> showError(error.getErrorMsg())); + } + + private void getRegionData() { + RxHttp.get(Api.LAND_AREA_REGION) + .add("areaCode", "530926") + .asResponseList(LandAreaRegionEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + landAreaRegionData = data; + }, (OnError) error -> showToast(error.getErrorMsg())); + } + + private void getGridData() { + RxHttp.get(Api.LAND_GRID) + .asResponse(LandGridEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + landGridData = data; + }, (OnError) error -> showToast(error.getErrorMsg())); + } + + private void getGroudTypeData() { + RxHttp.get(Api.LAND_GROUD_TYPE) + .add("current", 1) + .add("size", 999) + .asResponse(LandGroudTypeEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + landGroudTypeData = data; + }, (OnError) error -> showToast(error.getErrorMsg())); + } + + private void showLandTypeSelectDialog() { + if (landLandTypePickerView == null) { + List> subLandData = new ArrayList<>(); + List>> childLandData = new ArrayList<>(); + for (LandTypeEntity itemData : landLandTypeData) { + List> childList = new ArrayList<>(); + List aa = new ArrayList<>(); + aa.add(new LandTypeEntity("不限")); + childList.add(aa); + for (LandTypeEntity subItem : itemData.getChildren()) { + List childItemList = new ArrayList<>(); + childItemList.add(new LandTypeEntity("不限")); + childItemList.addAll(subItem.getChildren()); + childList.add(childItemList); + } + List subList = new ArrayList<>(); + subList.add(new LandTypeEntity("不限")); + subList.addAll(itemData.getChildren()); + subLandData.add(subList); + childLandData.add(childList); + } + + landLandTypePickerView = new OptionsPickerBuilder(this, (options1, options2, options3, v) -> { + if (options2 == 0 && options3 == 0) { + selectLandType = landLandTypeData.get(options1); + } else if (options2 != 0 && options3 == 0) { + selectLandType = landLandTypeData.get(options1).getChildren().get(options2 - 1); + } else if (options2 != 0 && options3 != 0) { + selectLandType = landLandTypeData.get(options1).getChildren().get(options2 - 1).getChildren().get(options3 - 1); + } + setText(binding.inputLandType, selectLandType.getLandType()); + binding.inputLandType.requestFocus(); + }).setTitleText("土地类型选择").setContentTextSize(20)//设置滚轮文字大小 + .setSelectOptions(0, 0, 0)//默认选中项 + .setTitleBgColor(Color.WHITE) + .isRestoreItem(true)//切换时是否还原,设置默认选中第一项。 + .isCenterLabel(false) //是否只显示中间选中项的label文字,false则每项item全部都带有label。 + .setOutSideColor(0x00000000) //设置外部遮罩颜色 + .build(); + + landLandTypePickerView.setPicker(landLandTypeData, subLandData, childLandData);//二级选择器 + } + landLandTypePickerView.show(); + } + + private void showRegionDialog() { + if (landRegionPickerView == null) { + List> subLandData = new ArrayList<>(); + for (LandAreaRegionEntity itemData : landAreaRegionData.get(0).getAreaChildVOS()) { + subLandData.add(itemData.getAreaChildVOS()); + } + + landRegionPickerView = new OptionsPickerBuilder(this, (options1, options2, options3, v) -> { + selectRegion = landAreaRegionData.get(0).getAreaChildVOS().get(options1).getAreaChildVOS().get(options2); + setText(binding.inputLandRegion, + landAreaRegionData.get(0).getAreaChildVOS().get(options1).getAreaName() + selectRegion.getAreaName()); + binding.inputLandRegion.requestFocus(); + }).setTitleText("土地区域选择").setContentTextSize(20) + .setSelectOptions(0, 0) + .setTitleBgColor(Color.WHITE) + .isRestoreItem(true)//切换时是否还原,设置默认选中第一项。 + .isCenterLabel(false) //是否只显示中间选中项的label文字,false则每项item全部都带有label。 + .setOutSideColor(0x00000000) //设置外部遮罩颜色 + .build(); + + landRegionPickerView.setPicker(landAreaRegionData.get(0).getAreaChildVOS(), subLandData);//二级选择器 + } + landRegionPickerView.show(); + } + + private void showLandGridDialog() { + if (landGridPickerView == null) { + landGridPickerView = new OptionsPickerBuilder(this, (options1, options2, options3, v) -> { + selectGrid = landGridData.getChildren().get(options1); + setText(binding.inputLandGrid, selectGrid.getRegionName() + "网格"); + binding.inputLandGrid.requestFocus(); + }).setTitleText("土地网格选择").setContentTextSize(20) + .setSelectOptions(0) + .setTitleBgColor(Color.WHITE) + .isRestoreItem(true) + .isCenterLabel(false) + .setOutSideColor(0x00000000) + .build(); + + landGridPickerView.setPicker(landGridData.getChildren()); + } + landGridPickerView.show(); + } + + private void showLandGroudTypeDialog() { + if (landGroudTypePickerView == null) { + landGroudTypePickerView = new OptionsPickerBuilder(this, (options1, options2, options3, v) -> { + selectLandGroudType = landGroudTypeData.getRecords().get(options1); + setText(binding.inputGroudType, selectLandGroudType.getSoilType()); + binding.inputGroudType.requestFocus(); + }).setTitleText("土壤类型选择").setContentTextSize(20) + .setSelectOptions(0) + .setTitleBgColor(Color.WHITE) + .isRestoreItem(true) + .isCenterLabel(false) + .setOutSideColor(0x00000000) + .build(); + + landGroudTypePickerView.setPicker(landGroudTypeData.getRecords()); + } + landGroudTypePickerView.show(); + } + + private void checkSubmit() { + String landName = binding.inputLandName.getText().toString().trim(); + if (TextUtils.isEmpty(landName)) { + PopTip.show("地块名称不能为空").iconError(); + return; + } + String landArea = binding.inputLandArea.getText().toString().trim(); + if (TextUtils.isEmpty(landArea)) { + PopTip.show("地块面积不能为空").iconError(); + return; + } + String landAddress = binding.inputLandAddress.getText().toString().trim(); + if (TextUtils.isEmpty(landAddress)) { + PopTip.show("土地具体位置不能为空").iconError(); + return; + } + showLoading(); + if (!TextUtils.isEmpty(landImgPath)) { + uploadLandImg(); + } else if (!TextUtils.isEmpty(areaPath)) { + uploadAreaImg(); + } else { + doAddLand(); + } + } + + private void uploadLandImg() { + RxHttpFormParam http = RxHttp.postForm(Api.FILE_UPLOAD); + http.addFile("file", new File(landImgPath)); + http.asSingleUpload(UploadEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + landImgEntity = data; + if (!TextUtils.isEmpty(areaPath)) { + uploadAreaImg(); + } else { + doAddLand(); + } + }, (OnError) error -> { + PopTip.show("图片上传失败:" + error.getErrorMsg()).iconError(); + hideLoading(); + }); + } + + private void uploadAreaImg() { + RxHttpFormParam http = RxHttp.postForm(Api.FILE_UPLOAD); + http.addFile("file", new File(areaPath)); + http.asSingleUpload(UploadEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + areaImgEntity = data; + doAddLand(); + }, (OnError) error -> { + PopTip.show("图片上传失败:" + error.getErrorMsg()).iconError(); + hideLoading(); + }); + } + + private void doAddLand() { + RxHttpJsonParam http = RxHttp.postJson(Api.EDIT_LAND); + String landName = binding.inputLandName.getText().toString().trim(); + Double landArea = Double.parseDouble(binding.inputLandArea.getText().toString().trim()); + String landAddress = binding.inputLandAddress.getText().toString().trim(); + http.add("id", mData.getId()).add("landName", landName).add("area", landArea).add("address", landAddress); + if (ArrayUtil.notNull(areaPoints)) { + String scope = new Gson().toJson(areaPoints); + http.add("scope", scope); + http.add("scopeImg", areaImgEntity.getUrl()); + } + if (selectLandType != null) { + http.add("landType", selectLandType.getId()); + } + if (selectRegion != null) { + http.add("villageCode", selectRegion.getAreaCode()); + } + if (selectGrid != null) { + http.add("gridId", selectGrid.getRegionCode()); + } + if (selectLandGroudType != null) { + http.add("soilTypeId", selectLandGroudType.getId()); + } + if (landImgEntity != null) { + http.add("landUrl", landImgEntity.getUrl()); + } + http.asResponse(Boolean.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + hideLoading(); + PopTip.show("编辑成功").iconSuccess(); + EventBus.getDefault().post(new EventMessage(EventConstant.REFRESH_LIST)); + finish(); + }, (OnError) error -> { + PopTip.show(error.getErrorMsg()).iconError(); + hideLoading(); + }); + } + + private void selectImg() { + PhotoAlbumDialog.build() + .setCompressQuality(90) //开启压缩并指定质量 90% + .setCompressPhoto(false) //是否压缩(开启回调格式为 jpg,不开启回调格式为 png) + .setMaxSelectPhotoCount(1) //最多选择三张照片 + .setClip(false) //开启裁剪模式 + .setMaxSize(1000) //最高分辨率 1000(宽或高大于 1000会被等比缩小到 1000内) + .setMaxWidth(1000) //最大宽度 + .setMaxHeight(1000) //最大高度 + .setCallback(new SelectPhotoCallback() { + + //单张模式回调(二者其一任选) + @Override + public void selectedPhoto(String selectedPhotos) { + landImgPath = selectedPhotos; + GlideLoader.loadOriginal(binding.imgLand, selectedPhotos); + setGone(binding.imgLand, true); + setGone(binding.btnReSelectImg, true); + } + }) + .setDialogDialogImplCallback(dialog -> dialog.setRadius(DensityUtils.dp2px(mContext, 25))) + .show(this); + } + + private void checkLocationPermission() { + XXPermissions.with(this) + // 申请单个权限 + .permission(Permission.ACCESS_FINE_LOCATION) + .permission(Permission.ACCESS_COARSE_LOCATION) + .request(new OnPermissionCallback() { + @Override + public void onGranted(@NonNull List permissions, boolean allGranted) { + if (!allGranted) { + showToast("获取部分权限成功,但部分权限未正常授予"); + return; + } + MapsInitializer.updatePrivacyShow(mContext, true, true); + MapsInitializer.updatePrivacyAgree(mContext, true); + IntentUtil.startActivity(mContext, SelectLandAreaActivity.class); + } + + @Override + public void onDenied(@NonNull List permissions, boolean doNotAskAgain) { + if (doNotAskAgain) { + showToast("被永久拒绝授权,请手动授予定位权限"); + // 如果是被永久拒绝就跳转到应用权限系统设置页面 + XXPermissions.startPermissionActivity(mContext, permissions); + } else { + showToast("获取定位权限失败"); + } + } + }); + } + + @Override + protected void onDestroy() { + EventBus.getDefault().unregister(this); + super.onDestroy(); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageReceive(EventMessage message) { + if (null != message && !TextUtils.isEmpty(message.getLabel())) { + if (EventConstant.SELECT_AREA.equals(message.getLabel())) { + areaPoints = (List) message.getData(); + areaPath = (String) message.getSubData(); + GlideLoader.loadOriginal(binding.imgArea, areaPath); + setGone(binding.btnReSelectArea, true); + setGone(binding.layoutArea, true); + } + } + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/EditLandProductActivity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/EditLandProductActivity.java new file mode 100644 index 0000000..6ef5241 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/EditLandProductActivity.java @@ -0,0 +1,173 @@ +package com.tairui.gov_affairs_cloud.ui.land; + +import java.io.File; + +import org.greenrobot.eventbus.EventBus; + +import com.kongzue.albumdialog.PhotoAlbumDialog; +import com.kongzue.albumdialog.util.SelectPhotoCallback; +import com.kongzue.dialogx.dialogs.PopTip; +import com.rxjava.rxlife.RxLife; +import com.tairui.gov_affairs_cloud.base.BaseActivity; +import com.tairui.gov_affairs_cloud.databinding.ActivityEditLandProductBinding; +import com.tairui.gov_affairs_cloud.entity.Api; +import com.tairui.gov_affairs_cloud.entity.EventConstant; +import com.tairui.gov_affairs_cloud.entity.EventMessage; +import com.tairui.gov_affairs_cloud.entity.UploadEntity; +import com.tairui.gov_affairs_cloud.http.OnError; +import com.tairui.gov_affairs_cloud.ui.land.entity.LandResourceEntity; +import com.tairui.gov_affairs_cloud.util.AppUtil; +import com.tairui.gov_affairs_cloud.util.DensityUtils; +import com.tairui.gov_affairs_cloud.util.SingleClickListener; +import com.tairui.gov_affairs_cloud.util.glide.GlideLoader; + +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import rxhttp.RxHttp; +import rxhttp.RxHttpFormParam; +import rxhttp.RxHttpJsonParam; + +public class EditLandProductActivity extends BaseActivity { + private String landImgPath; + private UploadEntity landImgEntity; + + private LandResourceEntity.RecordsEntity mData; + + @Override + protected Class getBindingClass() { + return ActivityEditLandProductBinding.class; + } + + @Override + protected void onQueryArguments() { + mData = (LandResourceEntity.RecordsEntity) getIntent().getSerializableExtra("data"); + } + + @Override + protected void onFindView(Bundle savedInstanceState) { + setText(binding.inputPropertyName, mData.getPropertyName()); + setText(binding.inputPropertyPhone, mData.getPropertyPhone()); + setText(binding.inputLandCode, mData.getLandCode()); + if (mData.getLandUrl().startsWith("http")) { + GlideLoader.loadOriginal(binding.imgProduct, mData.getPropertyCertificateUrl()); + } else { + GlideLoader.loadOriginal(binding.imgProduct, AppUtil.getImageUrl(mData.getPropertyCertificateUrl())); + } + } + + @Override + protected void onBindListener() { + binding.btnBack.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + finish(); + } + }); + binding.btnSelectImg.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + selectImg(); + } + }); + binding.btnReSelectImg.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + selectImg(); + } + }); + binding.btnSubmit.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + checkSubmit(); + } + }); + } + + private void checkSubmit() { + String properName = binding.inputPropertyName.getText().toString().trim(); + if (TextUtils.isEmpty(properName)) { + PopTip.show("姓名不能为空").iconError(); + return; + } + String properPhone = binding.inputPropertyPhone.getText().toString().trim(); + if (TextUtils.isEmpty(properPhone)) { + PopTip.show("电话不能为空").iconError(); + return; + } + String landCode = binding.inputLandCode.getText().toString().trim(); + if (TextUtils.isEmpty(landCode)) { + PopTip.show("产权编号不能为空").iconError(); + return; + } + showLoading(); + if (!TextUtils.isEmpty(landImgPath)) { + uploadLandImg(); + } else { + doAddLandProduct(); + } + } + + private void uploadLandImg() { + RxHttpFormParam http = RxHttp.postForm(Api.FILE_UPLOAD); + http.addFile("file", new File(landImgPath)); + http.asSingleUpload(UploadEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + landImgEntity = data; + doAddLandProduct(); + }, (OnError) error -> { + PopTip.show("图片上传失败:" + error.getErrorMsg()).iconError(); + hideLoading(); + }); + } + + private void doAddLandProduct() { + String properName = binding.inputPropertyName.getText().toString().trim(); + String properPhone = binding.inputPropertyPhone.getText().toString().trim(); + String landCode = binding.inputLandCode.getText().toString().trim(); + RxHttpJsonParam http = RxHttp.postJson(Api.EDIT_LAND) + .add("id", mData.getId()) + .add("propertyName", properName) + .add("propertyPhone", properPhone) + .add("landCode", landCode); + if (landImgEntity != null) { + http.add("propertyCertificateUrl", landImgEntity.getUrl()); + } + http.asResponse(Boolean.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + hideLoading(); + PopTip.show("编辑成功").iconSuccess(); + EventBus.getDefault().post(new EventMessage(EventConstant.REFRESH_LIST)); + finish(); + }, (OnError) error -> { + PopTip.show(error.getErrorMsg()).iconError(); + hideLoading(); + }); + } + + private void selectImg() { + PhotoAlbumDialog.build() + .setCompressQuality(90) //开启压缩并指定质量 90% + .setCompressPhoto(false) //是否压缩(开启回调格式为 jpg,不开启回调格式为 png) + .setMaxSelectPhotoCount(1) //最多选择三张照片 + .setClip(false) //开启裁剪模式 + .setMaxSize(1000) //最高分辨率 1000(宽或高大于 1000会被等比缩小到 1000内) + .setMaxWidth(1000) //最大宽度 + .setMaxHeight(1000) //最大高度 + .setCallback(new SelectPhotoCallback() { + + //单张模式回调(二者其一任选) + @Override + public void selectedPhoto(String selectedPhotos) { + landImgPath = selectedPhotos; + GlideLoader.loadOriginal(binding.imgProduct, selectedPhotos); + setGone(binding.imgProduct, true); + setGone(binding.btnReSelectImg, true); + } + }) + .setDialogDialogImplCallback(dialog -> dialog.setRadius(DensityUtils.dp2px(mContext, 25))) + .show(this); + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/LandActivity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/LandActivity.java new file mode 100644 index 0000000..cfe8aa4 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/LandActivity.java @@ -0,0 +1,205 @@ +package com.tairui.gov_affairs_cloud.ui.land; + +import java.util.ArrayList; +import java.util.List; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.rxjava.rxlife.RxLife; +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.base.BaseActivity; +import com.tairui.gov_affairs_cloud.databinding.ActivityLandBinding; +import com.tairui.gov_affairs_cloud.entity.Api; +import com.tairui.gov_affairs_cloud.entity.RoseBean; +import com.tairui.gov_affairs_cloud.http.OnError; +import com.tairui.gov_affairs_cloud.ui.land.entity.LandOverviewEntity; +import com.tairui.gov_affairs_cloud.util.DensityUtils; +import com.tairui.gov_affairs_cloud.util.SingleClickListener; +import com.tairui.gov_affairs_cloud.widget.GridSpacingItemDecoration; +import com.tairui.gov_affairs_cloud.widget.charts.bean.BarBean; + +import android.graphics.Color; +import android.os.Bundle; +import android.view.View; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.GridLayoutManager; +import rxhttp.RxHttp; + +public class LandActivity extends BaseActivity { + + private LandOverviewAdapter landOverviewAdapter; + + @Override + protected Class getBindingClass() { + return ActivityLandBinding.class; + } + + @Override + protected void onFindView(Bundle savedInstanceState) { + landOverviewAdapter = new LandOverviewAdapter(new ArrayList<>()); + binding.landTotalChart.setShowChartLable(true); //是否在图表上显示指示lable + binding.landTotalChart.setShowChartNum(false); //是否在图表上显示指示num + binding.landTotalChart.setShowNumTouched(false); //点击显示数量 + binding.landTotalChart.setShowRightNum(true); //右侧显示数量 + + binding.landItemChart.setLoading(true); + binding.landItemChart.setBarNum(1); + binding.landItemChart.setBarColor(new int[] {Color.parseColor("#007AFF")}); + binding.landItemChart.setBarItemSpace(DensityUtils.dp2px(mContext, 20)); + binding.landItemChart.setBarWidth(DensityUtils.dp2px(mContext, 10)); + binding.landItemChart.setBackColor(getResColor(R.color.white)); + binding.landItemChart.setXMARK_NUM(5); + binding.landItemChart.setTextSizeTag((int) getResources().getDimension(R.dimen.text_size_level_mid)); + binding.landItemChart.setTextSizeCoordinate((int) getResources().getDimension(R.dimen.text_size_level_mid)); + binding.landItemChart.setTextSizeTag(0); + } + + @Override + protected void onBindListener() { + binding.btnBack.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + finish(); + } + }); + landOverviewAdapter.setOnItemClickListener((baseQuickAdapter, view, i) -> { + if (i == 0) { + setGone(binding.landTotalChart, true); + setGone(binding.landItemChart, false); + } else { + setGone(binding.landTotalChart, false); + binding.landItemChart.setLoading(true); + setGone(binding.landItemChart, true); + LandOverviewEntity.ListEntity item = landOverviewAdapter.getData().get(i); + getItemLandData(item.getLandTypeId()); + } + }); + } + + private void getItemLandData(String pid) { + RxHttp.get(Api.LAND_SUB_AREA) + .add("pid", pid) + .asResponseList(LandOverviewEntity.ListEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + initSubAreaChart(data); + }, (OnError) error -> showToast(error.getErrorMsg())); + } + + @Override + protected void onApplyData() { + getLandOverViewData(); + } + + private void getLandOverViewData() { + RxHttp.get(Api.LAND_OVERVIEW) + .asResponse(LandOverviewEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + initView(data); + }, (OnError) error -> showToast(error.getErrorMsg())); + } + + private void initView(LandOverviewEntity overviewEntity) { + List chartDataList = new ArrayList<>(); + for (LandOverviewEntity.ListEntity listEntity : overviewEntity.getList()) { + chartDataList.add(new RoseBean(listEntity.getArea(), listEntity.getLandTypeName())); + } + + binding.landTotalChart.setData(RoseBean.class, "count", "ClassName", chartDataList); + binding.landTotalChart.setLoading(false);//是否正在加载,数据加载完毕后置为false + + LandOverviewEntity.ListEntity totalItem = new LandOverviewEntity.ListEntity(); + totalItem.setLandTypeName("土地总"); + totalItem.setArea(overviewEntity.getTotal()); + totalItem.setLandTypeId("-1"); + List list = overviewEntity.getList(); + list.add(0, totalItem); + binding.recycleView.setLayoutManager(new GridLayoutManager(mContext, 2)); + binding.recycleView.addItemDecoration(new GridSpacingItemDecoration(2, DensityUtils.dp2px(mContext, 10), true)); + landOverviewAdapter.setNewData(list); + binding.recycleView.setAdapter(landOverviewAdapter); + } + + private void initSubAreaChart(List data) { + List strXList = new ArrayList<>(); + List> dataList = new ArrayList<>( ); + for (LandOverviewEntity.ListEntity entity : data) { + List list = new ArrayList<>(); + list.add(new BarBean(entity.getArea(), entity.getLandTypeName())); + dataList.add(list); + strXList.add(entity.getLandTypeName()); + } + binding.landItemChart.setLoading(false); + binding.landItemChart.setData(dataList, strXList); + } + + private class LandOverviewAdapter extends BaseQuickAdapter { + + public LandOverviewAdapter(List data) { + super(R.layout.item_land_overview_item, data); + } + + @Override + protected void convert(@NonNull BaseViewHolder holder, LandOverviewEntity.ListEntity entity) { + int pos = holder.getLayoutPosition(); + View rootView = holder.getView(R.id.rootView); + if (pos == 0) { + rootView.setBackgroundResource(R.mipmap.bg_land_overview_1); + holder.setImageResource(R.id.ivOverView, R.mipmap.bg_land_overview_icon_1); + } else if (pos == 1) { + rootView.setBackgroundResource(R.mipmap.bg_land_overview_2); + holder.setImageResource(R.id.ivOverView, R.mipmap.bg_land_overview_icon_2); + } else if (pos == 2) { + rootView.setBackgroundResource(R.mipmap.bg_land_overview_3); + holder.setImageResource(R.id.ivOverView, R.mipmap.bg_land_overview_icon_3); + } else if (pos == 3) { + rootView.setBackgroundResource(R.mipmap.bg_land_overview_4); + holder.setImageResource(R.id.ivOverView, R.mipmap.bg_land_overview_icon_4); + } + + holder.setText(R.id.tvCount, String.valueOf(entity.getArea())); + holder.setText(R.id.tvName, entity.getLandTypeName() + "面积(万亩)"); + } + } + + /* private void generateFuncData(){ + List data = new ArrayList<>(); + WorkSpaceEntity.FuncsEntity item = new WorkSpaceEntity.FuncsEntity(); + item.setName("年度计划"); + item.setIcon(R.mipmap.ic_land_overview_func_1); + data.add(item); + + item = new WorkSpaceEntity.FuncsEntity(); + item.setName("网格信息"); + item.setIcon(R.mipmap.ic_land_overview_func_2); + data.add(item); + + item = new WorkSpaceEntity.FuncsEntity(); + item.setName("农事作业"); + item.setIcon(R.mipmap.ic_land_overview_func_3); + data.add(item); + + item = new WorkSpaceEntity.FuncsEntity(); + item.setName("土地违规"); + item.setIcon(R.mipmap.ic_land_overview_func_4); + data.add(item); + + item = new WorkSpaceEntity.FuncsEntity(); + item.setName("土地巡查"); + item.setIcon(R.mipmap.ic_land_overview_func_5); + data.add(item); + + item = new WorkSpaceEntity.FuncsEntity(); + item.setName("土地资源信息"); + item.setIcon(R.mipmap.ic_land_overview_func_6); + data.add(item); + + BaseHolderEntity entity = new BaseHolderEntity(); + entity.setType(2); + entity.setData(data); + mData.add(entity); + + landAdapter.setNewData(mData); + }*/ +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/LandInfoDetailActivity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/LandInfoDetailActivity.java new file mode 100644 index 0000000..1f04f1f --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/LandInfoDetailActivity.java @@ -0,0 +1,148 @@ +package com.tairui.gov_affairs_cloud.ui.land; + +import java.util.ArrayList; + +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.base.BaseActivity; +import com.tairui.gov_affairs_cloud.databinding.ActivityLandInfoDetailBinding; +import com.tairui.gov_affairs_cloud.ui.land.entity.LandResourceEntity; +import com.tairui.gov_affairs_cloud.util.AppUtil; +import com.tairui.gov_affairs_cloud.util.IntentUtil; +import com.tairui.gov_affairs_cloud.util.SingleClickListener; +import com.tairui.gov_affairs_cloud.util.glide.GlideLoader; + +import android.graphics.Typeface; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; + +public class LandInfoDetailActivity extends BaseActivity { + + private LandResourceEntity.RecordsEntity mData; + + private int tabType = 0; //0:基本信息 1:产权信息 + + @Override + protected Class getBindingClass() { + return ActivityLandInfoDetailBinding.class; + } + + @Override + protected void onQueryArguments() { + mData = (LandResourceEntity.RecordsEntity) getIntent().getSerializableExtra("data"); + } + + @Override + protected void onFindView(Bundle savedInstanceState) { + setText(binding.tvTitle, mData.getLandName()); + setText(binding.inputLandName, mData.getLandName()); + setText(binding.inputLandArea, mData.getArea() + "亩"); + setText(binding.inputLandType, mData.getLandTypeName()); + setText(binding.inputLandRegion, mData.getFullRegionName()); + setText(binding.inputLandAddress, mData.getAddress()); + setText(binding.inputLandGrid, mData.getGridName()); + setText(binding.inputGroudType, mData.getSoilType()); + if (mData.getLandUrl().startsWith("http")) { + GlideLoader.loadOriginal(binding.imgLand, mData.getLandUrl()); + } else { + GlideLoader.loadOriginal(binding.imgLand, AppUtil.getImageUrl(mData.getLandUrl())); + } + if (!TextUtils.isEmpty(mData.getScopeImg())) { + GlideLoader.loadOriginal(binding.imgArea, AppUtil.getImageUrl(mData.getScopeImg())); + } + + setText(binding.inputPropertyName, mData.getPropertyName()); + setText(binding.inputPropertyPhone, mData.getPropertyPhone()); + setText(binding.inputLandCode, mData.getLandCode()); + if (mData.getLandUrl().startsWith("http")) { + GlideLoader.loadOriginal(binding.imgProduct, mData.getPropertyCertificateUrl()); + } else { + GlideLoader.loadOriginal(binding.imgProduct, AppUtil.getImageUrl(mData.getPropertyCertificateUrl())); + } + + } + + @Override + protected void onBindListener() { + binding.btnBack.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + finish(); + } + }); + binding.btnEdit.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + Bundle bundle = new Bundle(); + bundle.putSerializable("data", mData); + if (tabType == 0) { + IntentUtil.startActivity(mContext, EditLandBaseInfoActivity.class, bundle); + } else { + IntentUtil.startActivity(mContext, EditLandProductActivity.class, bundle); + } + finish(); + } + }); + binding.tabBaseInfo.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + binding.tvBaseInfo.setTextColor(getResColor(R.color.color_txt_black)); + binding.tvBaseInfo.setTypeface(null, Typeface.BOLD); + setGone(binding.dividerbaseInfo, true); + binding.tvProductInfo.setTextColor(getResColor(R.color.color_txt_label)); + binding.tvProductInfo.setTypeface(null, Typeface.NORMAL); + setGone(binding.dividerProductInfo, false); + setGone(binding.layoutBaseInfo, true); + setGone(binding.layoutProductInfo, false); + tabType = 0; + } + }); + binding.tabProductInfo.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + binding.tvBaseInfo.setTextColor(getResColor(R.color.color_txt_label)); + binding.tvBaseInfo.setTypeface(null, Typeface.NORMAL); + setGone(binding.dividerbaseInfo, false); + binding.tvProductInfo.setTextColor(getResColor(R.color.color_txt_black)); + binding.tvProductInfo.setTypeface(null, Typeface.BOLD); + setGone(binding.dividerProductInfo, true); + setGone(binding.layoutBaseInfo, false); + setGone(binding.layoutProductInfo, true); + tabType = 1; + } + }); + binding.imgLand.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + ArrayList imgs = new ArrayList<>(); + if (mData.getLandUrl().startsWith("http")) { + imgs.add(mData.getLandUrl()); + } else { + imgs.add(AppUtil.getImageUrl(mData.getLandUrl())); + } + AppUtil.startPhotoView(mContext, imgs); + } + }); + binding.imgArea.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + ArrayList imgs = new ArrayList<>(); + imgs.add(AppUtil.getImageUrl(mData.getScopeImg())); + AppUtil.startPhotoView(mContext, imgs); + } + }); + binding.imgProduct.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + ArrayList imgs = new ArrayList<>(); + if (mData.getLandUrl().startsWith("http")) { + imgs.add(mData.getPropertyCertificateUrl()); + } else { + imgs.add(AppUtil.getImageUrl(mData.getPropertyCertificateUrl())); + } + AppUtil.startPhotoView(mContext, imgs); + } + }); + } + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/LandResouceInfoActivity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/LandResouceInfoActivity.java new file mode 100644 index 0000000..9835552 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/LandResouceInfoActivity.java @@ -0,0 +1,145 @@ +package com.tairui.gov_affairs_cloud.ui.land; + +import java.util.ArrayList; +import java.util.List; + +import org.greenrobot.eventbus.EventBus; + +import com.bigkoo.pickerview.builder.OptionsPickerBuilder; +import com.bigkoo.pickerview.view.OptionsPickerView; +import com.rxjava.rxlife.RxLife; +import com.tairui.gov_affairs_cloud.base.BaseActivity; +import com.tairui.gov_affairs_cloud.base.BaseFragment; +import com.tairui.gov_affairs_cloud.base.adapter.TabFragmentPagerAdapter; +import com.tairui.gov_affairs_cloud.databinding.ActivityLandResourceInfoBinding; +import com.tairui.gov_affairs_cloud.entity.Api; +import com.tairui.gov_affairs_cloud.entity.EventConstant; +import com.tairui.gov_affairs_cloud.entity.EventMessage; +import com.tairui.gov_affairs_cloud.http.OnError; +import com.tairui.gov_affairs_cloud.ui.land.entity.LandAreaRegionEntity; +import com.tairui.gov_affairs_cloud.ui.land.entity.LandResourceTypeEntity; +import com.tairui.gov_affairs_cloud.ui.land.fragment.LandResourceInfoItemFragment; +import com.tairui.gov_affairs_cloud.util.ArrayUtil; +import com.tairui.gov_affairs_cloud.util.IntentUtil; +import com.tairui.gov_affairs_cloud.util.SingleClickListener; + +import android.graphics.Color; +import android.os.Bundle; +import android.view.View; +import rxhttp.RxHttp; + +public class LandResouceInfoActivity extends BaseActivity { + + private List fragments; + private ArrayList mTitles = new ArrayList<>(); + private TabFragmentPagerAdapter mPagerAdapter; + + private List landAreaRegionData = new ArrayList<>(); + private List landResourceTypeData = new ArrayList<>(); + private LandAreaRegionEntity selectRegion; + private OptionsPickerView landRegionPickerView; + + @Override + protected Class getBindingClass() { + return ActivityLandResourceInfoBinding.class; + } + + private void initFragment() { + fragments = new ArrayList<>(); + for (LandResourceTypeEntity itemEntity : landResourceTypeData) { + mTitles.add(itemEntity.getLandType()); + fragments.add(LandResourceInfoItemFragment.newInstance(itemEntity.getId())); + } + mPagerAdapter = new TabFragmentPagerAdapter(getSupportFragmentManager(), mTitles, fragments); + binding.viewPager.setAdapter(mPagerAdapter);//给ViewPager设置适配器 + binding.viewPager.setOffscreenPageLimit(landResourceTypeData.size()); + binding.tabBar.setViewPager(binding.viewPager); + binding.viewPager.setCurrentItem(0, false); + } + + @Override + protected void onFindView(Bundle savedInstanceState) { + binding.viewPager.setIsCanScroll(true); + } + + @Override + protected void onBindListener() { + binding.btnBack.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + finish(); + } + }); + binding.locationLayout.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + if (ArrayUtil.notNull(landAreaRegionData)) { + showRegionDialog(); + } + } + }); + binding.btnSearch.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + IntentUtil.startActivity(mContext, LandSearchActivity.class); + } + }); + binding.btnAdd.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + IntentUtil.startActivity(mContext, AddLandActivity.class); + } + }); + } + + private void showRegionDialog() { + if (landRegionPickerView == null) { + List> subLandData = new ArrayList<>(); + for (LandAreaRegionEntity itemData : landAreaRegionData.get(0).getAreaChildVOS()) { + subLandData.add(itemData.getAreaChildVOS()); + } + + landRegionPickerView = new OptionsPickerBuilder(this, (options1, options2, options3, v) -> { + selectRegion = landAreaRegionData.get(0).getAreaChildVOS().get(options1).getAreaChildVOS().get(options2); + setText(binding.tvLocation, + landAreaRegionData.get(0).getAreaChildVOS().get(options1).getAreaName() + selectRegion.getAreaName()); + EventBus.getDefault().post(new EventMessage(EventConstant.REFRESH_LIST, selectRegion.getAreaCode())); + }).setTitleText("土地区域选择").setContentTextSize(20)//设置滚轮文字大小 + .setSelectOptions(0, 0)//默认选中项 + .setTitleBgColor(Color.WHITE) + .isRestoreItem(true)//切换时是否还原,设置默认选中第一项。 + .isCenterLabel(false) //是否只显示中间选中项的label文字,false则每项item全部都带有label。 + .setOutSideColor(0x00000000) //设置外部遮罩颜色 + .build(); + + landRegionPickerView.setPicker(landAreaRegionData.get(0).getAreaChildVOS(), subLandData);//二级选择器 + } + landRegionPickerView.show(); + } + + @Override + protected void onApplyData() { + getRegionData(); + getTabData(); + } + + private void getRegionData() { + RxHttp.get(Api.LAND_AREA_REGION) + .add("areaCode", "530926") + .asResponseList(LandAreaRegionEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + landAreaRegionData = data; + }, (OnError) error -> showToast(error.getErrorMsg())); + } + + private void getTabData() { + RxHttp.get(Api.LAND_RESOURCE_TYPE_NO_CHILD) + .asResponseList(LandResourceTypeEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + landResourceTypeData = data; + initFragment(); + }, (OnError) error -> showToast(error.getErrorMsg())); + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/LandSearchActivity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/LandSearchActivity.java new file mode 100644 index 0000000..0391c07 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/LandSearchActivity.java @@ -0,0 +1,116 @@ +package com.tairui.gov_affairs_cloud.ui.land; + +import java.util.ArrayList; +import java.util.List; + +import org.greenrobot.eventbus.EventBus; + +import com.orhanobut.hawk.Hawk; +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.base.BaseActivity; +import com.tairui.gov_affairs_cloud.databinding.ActivityLandResouceInfoSearchBinding; +import com.tairui.gov_affairs_cloud.entity.EventConstant; +import com.tairui.gov_affairs_cloud.entity.EventMessage; +import com.tairui.gov_affairs_cloud.util.ArrayUtil; +import com.tairui.gov_affairs_cloud.util.NetUtil; +import com.tairui.gov_affairs_cloud.util.SingleClickListener; +import com.tairui.gov_affairs_cloud.util.ToastUtil; +import com.tairui.gov_affairs_cloud.widget.flowlayout.FlowLayout; +import com.tairui.gov_affairs_cloud.widget.flowlayout.TagAdapter; + +import android.os.Bundle; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; + +public class LandSearchActivity extends BaseActivity { + + private List historyTags; + + @Override + protected Class getBindingClass() { + return ActivityLandResouceInfoSearchBinding.class; + } + + @Override + protected void onQueryArguments() { + if (Hawk.contains("land_search_history")) { + historyTags = Hawk.get("land_search_history"); + } else { + historyTags = new ArrayList<>(); + } + } + + @Override + protected void onFindView(Bundle savedInstanceState) { + if (!ArrayUtil.isEmpty(historyTags)) { + TagAdapter tagAdapter = new TagAdapter(historyTags) { + @Override + public View getView(FlowLayout parent, int position, String str) { + View view = LayoutInflater.from(mContext).inflate(R.layout.item_tag_search, null); + TextView tv = view.findViewById(R.id.tv_tag_search); + if (null != tv) { + tv.setText(str); + return tv; + } + return null; + } + }; + binding.tagHistory.setAdapter(tagAdapter); + setGone(binding.keywordsLayout, true); + } else { + setGone(binding.keywordsLayout, false); + } + + } + + @Override + protected void onBindListener() { + binding.btnBack.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + finish(); + } + }); + binding.searchBtn.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + doSearch(); + } + }); + binding.inputSearch.setOnEditorActionListener((v, actionId, event) -> { + doSearch(); + return true; + }); + binding.tagHistory.setOnTagClickListener((view, position, parent) -> { + String searchContent = historyTags.get(position); + EventBus.getDefault().post(new EventMessage(EventConstant.SEARCH_LIST, searchContent)); + finish(); + return true; + }); + } + + private void doSearch() { + if (NetUtil.isNetworkConnected(mContext)) { + String searchContent = binding.inputSearch.getText().toString().trim(); + if (!TextUtils.isEmpty(searchContent)) { + if (!historyTags.contains(searchContent)) { + historyTags.add(0, searchContent); + } + } + EventBus.getDefault().post(new EventMessage(EventConstant.SEARCH_LIST, searchContent)); + finish(); + } else { + ToastUtil.showShortToast(getString(R.string.network_error)); + } + } + + @Override + protected void onDestroy() { + if (!ArrayUtil.isEmpty(historyTags)) { + Hawk.put("land_search_history", historyTags); + } + super.onDestroy(); + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/SelectLandAreaActivity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/SelectLandAreaActivity.java new file mode 100644 index 0000000..f372efb --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/SelectLandAreaActivity.java @@ -0,0 +1,1168 @@ +package com.tairui.gov_affairs_cloud.ui.land; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import com.amap.api.maps.AMap; +import com.amap.api.maps.AMapOptions; +import com.amap.api.maps.AMapUtils; +import com.amap.api.maps.CameraUpdateFactory; +import com.amap.api.maps.model.BitmapDescriptor; +import com.amap.api.maps.model.BitmapDescriptorFactory; +import com.amap.api.maps.model.LatLng; +import com.amap.api.maps.model.Marker; +import com.amap.api.maps.model.MarkerOptions; +import com.amap.api.maps.model.MyLocationStyle; +import com.amap.api.maps.model.Polygon; +import com.amap.api.maps.model.PolygonOptions; +import com.amap.api.maps.model.Polyline; +import com.amap.api.maps.model.PolylineOptions; +import com.amap.api.maps.model.TileOverlayOptions; +import com.kongzue.dialogx.dialogs.PopTip; +import com.orhanobut.hawk.Hawk; +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.base.BaseActivity; +import com.tairui.gov_affairs_cloud.databinding.ActivitySelectLandAreaBinding; +import com.tairui.gov_affairs_cloud.entity.EventConstant; +import com.tairui.gov_affairs_cloud.entity.EventMessage; +import com.tairui.gov_affairs_cloud.util.DensityUtils; +import com.tairui.gov_affairs_cloud.util.FolderUtil; +import com.tairui.gov_affairs_cloud.util.location.CommonUtil; +import com.tairui.gov_affairs_cloud.util.location.DrawMapUtil; +import com.tairui.gov_affairs_cloud.util.location.GoogleMapUtil; +import com.tairui.gov_affairs_cloud.util.location.GpsManager; +import com.tairui.gov_affairs_cloud.util.location.bean.DrawLatLng; +import com.tairui.gov_affairs_cloud.util.location.bean.LatlngBean; + +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.Point; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; + +public class SelectLandAreaActivity extends BaseActivity + implements AMap.OnMapClickListener, AMap.OnMarkerClickListener, + View.OnClickListener { + public double latitude = 39.90613850442552; //默认北京 + public double longitude = 116.40717000000001; //默认北京 + private TileOverlayOptions options; + private Boolean hasDrawFinish = false; //是否绘制完毕 + private List points = new ArrayList<>(); + private ArrayList circleList = new ArrayList<>(); + private int CIRCLE_DEFAULT; + private Polyline polyline; + private Polygon polygon; + private int movePosition = -1; + private int signMarkPosition = -1; + private Marker signMark; + private Boolean canClickMap = false; + private Boolean isDrawPress = false; + private Map distanceMap = new HashMap<>(); + private Boolean pressCircle_isBig = false; + private Boolean moveSign_center = false; + private Boolean moveSign_right = false; + private Boolean isFirstPoint = false; + private Boolean isLastPoint = false; + private int down_x = 0; + private int down_y = 0; + private int move_x = 0; + private int move_y = 0; + + private AMap aMap; + + @Override + protected Class getBindingClass() { + return ActivitySelectLandAreaBinding.class; + } + + @Override + protected void onFindView(Bundle savedInstanceState) { + + //在activity执行onCreate时执行mMapView.onCreate(savedInstanceState),创建地图 + binding.map.onCreate(savedInstanceState); + if (aMap == null) { + aMap = binding.map.getMap(); + } + aMap.getUiSettings().setLogoPosition(AMapOptions.LOGO_POSITION_BOTTOM_RIGHT);//Logo位置(地图右下角) + aMap.getUiSettings().setRotateGesturesEnabled(false);//关闭旋转手势 + aMap.getUiSettings().setTiltGesturesEnabled(false);//关闭倾斜手势 + aMap.getUiSettings().setMyLocationButtonEnabled(true);//设置默认定位按钮是否显示,非必需设置。 + //隐藏高德地图默认的放大缩小控件 + aMap.getUiSettings().setZoomControlsEnabled(false); + aMap.setMapType(AMap.MAP_TYPE_SATELLITE); + MyLocationStyle style = new MyLocationStyle(); + BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromResource(R.mipmap.map_positioning); + style.myLocationIcon(bitmapDescriptor); + style.strokeColor(Color.argb(0, 0, 0, 0));// 设置圆形的边框颜色 + style.radiusFillColor(Color.argb(0, 0, 0, 0));// 设置圆形的填充颜色 + style.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATE); + aMap.setMyLocationStyle(style); + // 设置为true表示显示定位层并可触发定位,false表示隐藏定位层并不可触发定位,默认是false + aMap.setMyLocationEnabled(true); + aMap.setOnMapClickListener(this);// 对amap添加单击地图事件监听器 + options = GoogleMapUtil.getGooleMapTileOverlayOptions(); //有的地区没有图层切片,可以调用谷歌接口获取切片数据(任意地方都有数据) + aMap.addTileOverlay(options); + aMap.setLoadOfflineData(true); + aMap.setOnMarkerClickListener(this); + + if (Hawk.get("latitude") != null && Hawk.get("longitude") != null) { + //说明没有定位过,定位到 + latitude = Hawk.get("latitude"); + longitude = Hawk.get("longitude"); + } + LatLng latLng = new LatLng(latitude, longitude); + aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 18)); + aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 18)); + } + + @Override + protected void onBindListener() { + binding.btnBack.setOnClickListener(this); + binding.btnSubmit.setOnClickListener(this); + binding.btnDelete.setOnClickListener(this); + binding.btnRedo.setOnClickListener(this); + } + + @Override + protected void onApplyData() { + canClickMap = true; + CIRCLE_DEFAULT = DensityUtils.dp2px(this, 20.0f); + try { + GpsManager.getInstance().init(this); + } catch (Exception e) { + e.printStackTrace(); + } + //通过 检查定位又没有打开 + if (GpsManager.getInstance().checkGps()) { + //开始定位 + GpsManager.getInstance().startLocation(); + } + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEventMainThread(EventMessage event) { + if (event.getLabel() == EventConstant.LOCATION_CODE && event.getData() instanceof LatlngBean) { + LatlngBean latLng = (LatlngBean) event.getData(); + try { + if (latLng == null) { + return; + } + if (Hawk.get("latitude") == null || Hawk.get("longitude") == null) { + //第一次 + latitude = latLng.getLatitude(); + longitude = latLng.getLongitude(); + } else { + //判断上次经纬度和这次的经纬度相差多少米 超过界限就移动视图 + double distance = (int) AMapUtils.calculateLineDistance( + new LatLng(Hawk.get("latitude", 0), Hawk.get("longitude", 0)), + new LatLng(latLng.getLatitude(), latLng.getLongitude())); + Log.e("xuezhy", "distance=" + distance); + if (distance < 1000) { + return; + } + } + + LatLng newLatlng = new LatLng(latitude, longitude); + aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(newLatlng, 18)); + aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(newLatlng, 18)); + + } catch (Exception e) { + e.printStackTrace(); + } + + } + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.btnRedo) { + if (hasDrawFinish) { + //已完成 + circleList.get(circleList.size() - 1).remove(); + circleList.remove(circleList.size() - 1); + points.remove(points.size() - 1); + hasDrawFinish = false; + } else { + //还没完成 + if (circleList.size() > 0) { + //删除最后一个 + circleList.get(circleList.size() - 1).remove(); + circleList.remove(circleList.size() - 1); + points.remove(points.size() - 1); + + if (circleList.size() > 1) { + //删除倒数第二个 + circleList.get(circleList.size() - 1).remove(); + circleList.remove(circleList.size() - 1); + points.remove(points.size() - 1); + } + } + + } + if (signMark != null) { + signMark.remove(); + signMarkPosition = -1; + } + drawLine(); + } else if (id == R.id.btnDelete) { + for (int i = 0; i < circleList.size(); i++) { + circleList.get(i).remove(); + } + circleList.clear(); + points.clear(); + if (polygon != null) { + polygon.remove(); + } + if (polyline != null) { + polyline.remove(); + } + + if (signMark != null) { + signMark.remove(); + movePosition = -1; + signMarkPosition = -1; + } + + hasDrawFinish = false; + } else if (id == R.id.btnBack) { + finish(); + } else if (id == R.id.btnSubmit) { + showLoading(); + aMap.getMapScreenShot(new AMap.OnMapScreenShotListener() { + @Override + public void onMapScreenShot(Bitmap bitmap) { + + } + + @Override + public void onMapScreenShot(Bitmap bitmap, int status) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); + if (null == bitmap) { + return; + } + try { + String path = FolderUtil.getPictureDir(mContext) + "/Area_" + sdf.format(new Date()) + ".png"; + FileOutputStream fos = new FileOutputStream(path); + boolean b = bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); + try { + fos.flush(); + } catch (IOException e) { + e.printStackTrace(); + } + try { + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + hideLoading(); + if (b) { + EventBus.getDefault().post(new EventMessage(EventConstant.SELECT_AREA, points, path)); + finish(); + } else { + PopTip.show("截屏失败").iconError(); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + } + }); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + //在activity执行onDestroy时执行binding.map.onDestroy(),销毁地图 + binding.map.onDestroy(); + } + + @Override + protected void onResume() { + super.onResume(); + //在activity执行onResume时执行binding.map.onResume (),重新绘制加载地图 + binding.map.onResume(); + } + + @Override + protected void onPause() { + super.onPause(); + //在activity执行onPause时执行binding.map.onPause (),暂停地图的绘制 + binding.map.onPause(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + //在activity执行onSaveInstanceState时执行binding.map.onSaveInstanceState (outState),保存地图当前的状态 + binding.map.onSaveInstanceState(outState); + } + + @Override + public void onMapClick(LatLng latLng) { + if (aMap == null || isDrawPress || !canClickMap) { + return; + } + + //如果没有 + if (!hasDrawFinish) { + if (points.size() == 0) { + //画个大圆圈 + DrawLatLng myLatlng = new DrawLatLng(latLng, true); + circleList.add(drawBigCircle(latLng, 0)); + points.add(myLatlng); + // upDateLandInfo(); + return; + } + //判断是否点击页面的点 + for (int i = 0; i < points.size(); i++) { + double distance = DrawMapUtil.getScreenDistance(aMap, points.get(i).getLatLng(), latLng); + // double distance = (int) AMapUtils.calculateLineDistance(points.get(i).getLatLng(), latLng); + if (distance < CIRCLE_DEFAULT) { + if (points.size() > 1) { + DrawLatLng drawLatLng = points.get(i); + //判断该点是不是小点 + + if (!drawLatLng.getBigCircle()) { + + drawOneBigAndTwoSmallCirclr(i, drawLatLng.getLatLng()); + return; + } + } + + return; + } + + } + + //先画小圈圈 + LatLng centerLatLng = getCenterLatlng(points.get(points.size() - 1).getLatLng(), latLng); + circleList.add(drawSmallCircle(centerLatLng, circleList.size())); + + //再画大圈圈 + + circleList.add(drawBigCircle(latLng, circleList.size())); + points.add(new DrawLatLng(centerLatLng, false)); + points.add(new DrawLatLng(latLng, true)); + + drawLine(); + return; + + } + + //判断是否点击页面的点 + for (int i = 0; i < points.size(); i++) { + double distance = DrawMapUtil.getScreenDistance(aMap, points.get(i).getLatLng(), latLng); + // double distance = (int) AMapUtils.calculateLineDistance(points.get(i).getLatLng(), latLng); + if (distance < CIRCLE_DEFAULT) { + DrawLatLng drawLatLng = points.get(i); + //选中了该点 + //判断是大圆圈还是小圆圈 + if (!points.get(i).getBigCircle()) { + drawOneBigAndTwoSmallCirclr(i, drawLatLng.getLatLng()); + return; + } + + /******选中标签****************/ + signMarkPosition = i; + drawSignMark(points.get(i).getLatLng()); + + return; + } + + } + + } + + @Override + public boolean onMarkerClick(Marker marker) { + if (!canClickMap) { + return false; + } + if (points.size() <= 2) { + return false; + } + if (!hasDrawFinish && marker.getPosition().latitude == points.get(0).getLatLng().latitude + && marker.getPosition().longitude == points.get(0).getLatLng().longitude) { + //画小圈圈 + LatLng centerLatLng_last = getCenterLatlng(points.get(points.size() - 1).getLatLng(), points.get(0).getLatLng()); + circleList.add(drawSmallCircle(centerLatLng_last, circleList.size())); + points.add(new DrawLatLng(centerLatLng_last, false)); + drawPolygon(); + hasDrawFinish = true; + } + String title = marker.getTitle(); + if (!TextUtils.isEmpty(title)) { + int position = Integer.valueOf(title); + signMarkPosition = position; + drawSignMark(points.get(position).getLatLng()); + } + + return true; + } + + /** + * 监听手势滑动 + * + * @param ev + * + * @return + */ + + @Override + public boolean dispatchTouchEvent(final MotionEvent ev) { + + if (points.size() <= 2 || !canClickMap) { + return super.dispatchTouchEvent(ev); + } + try { + if (MotionEvent.ACTION_DOWN == ev.getAction()) { + down_x = (int) ev.getX(); + down_y = (int) ev.getY(); + move_x = (int) ev.getX(); + move_y = (int) ev.getY(); + } else if (MotionEvent.ACTION_MOVE == ev.getAction()) { + if (isDrawPress) { + handlePressEvent(ev); + } else { + move_x = (int) ev.getX(); + move_y = (int) ev.getY(); + double distance = Math.sqrt(Math.pow(down_x - move_x, 2) + + Math.pow(down_y - move_y, 2)); + if (distance > DensityUtils.dp2px(mContext, 10.0f)) { + isDrawPress = true; + handleDownTouchEvent(ev); + } + } + + } else if (MotionEvent.ACTION_UP == ev.getAction()) { + handleMoveTouchEvent(); + } + } catch (Exception e) { + + } + + return super.dispatchTouchEvent(ev); + + } + + /**************************************************************绘制**************************************************************/ + + /** + * 画大圆圈 + */ + private Marker drawBigCircle(LatLng latLng, int position) { + return aMap.addMarker(new MarkerOptions() + .position(latLng) + .anchor(0.5f, 0.5f) + .title(String.valueOf(position)) + .icon(BitmapDescriptorFactory.fromView(getLayoutInflater().inflate(R.layout.map_draw_marker_big_white, null)))); + } + + /** + * 画小圆圈 + */ + private Marker drawSmallCircle(LatLng latLng, int position) { + return aMap.addMarker(new MarkerOptions() + .position(latLng) + .anchor(0.5f, 0.5f) + .title(String.valueOf(position)) + .icon(BitmapDescriptorFactory.fromView(getLayoutInflater().inflate(R.layout.map_draw_marker_small_white, null)))); + } + + /** + * 获取两个经纬度的中点经纬度 + * + * @param latLng1 + * @param latLng2 + * + * @return + */ + private LatLng getCenterLatlng(LatLng latLng1, LatLng latLng2) { + Point point1 = aMap.getProjection().toScreenLocation(latLng1); + Point point2 = aMap.getProjection().toScreenLocation(latLng2); + Point centerPoint = new Point(CommonUtil.avg(point1.x, point2.x), CommonUtil.avg(point1.y, point2.y)); + return aMap.getProjection().fromScreenLocation(centerPoint); + } + + /** + * 绘制线,把点连起来 + */ + protected void drawLine() { + + if (polyline != null) { + polyline.remove(); + } + + if (polygon != null) { + polygon.remove(); + } + + if (aMap != null && points.size() > 0) { + polyline = aMap.addPolyline(new PolylineOptions(). + addAll(DrawMapUtil.drawLatlngToLatlng(points)).width(2).color(getResources().getColor(R.color.color_blue)).zIndex(999)); + } + } + + private void drawOneBigAndTwoSmallCirclr(int i, LatLng latLng) { + //再判断该点是不是最后一个点 + if (i == points.size() - 1) { + /******左边圆圈****************/ + LatLng centerLatLng_left = getCenterLatlng(points.get(i - 1).getLatLng(), points.get(i).getLatLng()); + circleList.add(i, drawSmallCircle(centerLatLng_left, i)); + points.add(i, new DrawLatLng(centerLatLng_left, false)); + + /******大圆圈****************/ + circleList.get(i + 1).remove(); + circleList.remove(i + 1); + points.remove(i + 1); + circleList.add(i + 1, drawBigCircle(latLng, i + 1)); + points.add(i + 1, new DrawLatLng(latLng, true)); + + /******选中标签****************/ + signMarkPosition = movePosition; + drawSignMark(latLng); + + /******右边圆圈****************/ + LatLng centerLatLng_right = getCenterLatlng(points.get(i + 1).getLatLng(), points.get(0).getLatLng()); + circleList.add(drawSmallCircle(centerLatLng_right, circleList.size())); + points.add(new DrawLatLng(centerLatLng_right, false)); + return; + } + + /******左边圆圈****************/ + LatLng centerLatLng_left = getCenterLatlng(points.get(i - 1).getLatLng(), points.get(i).getLatLng()); + circleList.add(i, drawSmallCircle(centerLatLng_left, i)); + points.add(i, new DrawLatLng(centerLatLng_left, false)); + + /******大圆圈****************/ + circleList.get(i + 1).remove(); + circleList.remove(i + 1); + points.remove(i + 1); + circleList.add(i + 1, drawBigCircle(latLng, i + 1)); + points.add(i + 1, new DrawLatLng(latLng, true)); + + /******选中标签****************/ + signMarkPosition = movePosition; + drawSignMark(latLng); + + /******右边圆圈****************/ + LatLng centerLatLng_right = getCenterLatlng(points.get(i + 1).getLatLng(), points.get(i + 2).getLatLng()); + circleList.add(i + 2, drawSmallCircle(centerLatLng_right, i + 2)); + points.add(i + 2, new DrawLatLng(centerLatLng_right, false)); + } + + /** + * @param latLng + */ + private void drawSignMark(LatLng latLng) { + /* LatLng centerLatlng = CommonUtil.getCenterOfDrawPoint(points); + View view = getLayoutInflater().inflate(R.layout.map_draw_marker, null); + *//******选中标签****************//* + if (signMark != null) { + signMark.remove(); + } + + signMark = aMap.addMarker(new MarkerOptions() + .position(latLng).icon(BitmapDescriptorFactory.fromView(view))); + //判断方向 + if (latLng.latitude > centerLatlng.latitude && latLng.longitude < centerLatlng.longitude) { + //第一象限 + signMark.setRotateAngle(45); + + } else if (latLng.latitude < centerLatlng.latitude && latLng.longitude < centerLatlng.longitude) { + //第二象限 + signMark.setRotateAngle(135); + } else if (latLng.latitude < centerLatlng.latitude && latLng.longitude > centerLatlng.longitude) { + //第三象限 + signMark.setRotateAngle(225); + } else if (latLng.latitude > centerLatlng.latitude && latLng.longitude > centerLatlng.longitude) { + //第四象限 + signMark.setRotateAngle(-45); + }*/ + + } + + /** + * 绘制多边形 + */ + private void drawPolygon() { + + if (polyline != null) { + polyline.remove(); + } + + if (polygon != null) { + polygon.remove(); + } + + // 声明 多边形参数对象 + PolygonOptions polygonOptions = new PolygonOptions(); + // 添加 多边形的每个顶点(顺序添加) + for (int i = 0; i < points.size(); i++) { + polygonOptions.add(points.get(i).getLatLng()); + } + + Boolean hasOverlap = DrawMapUtil.checkDraw(points, aMap); + if (hasOverlap) { + //说明重合了 + polygonOptions.strokeWidth(2) // 多边形的边框 + .strokeColor(getResources().getColor(R.color.white)) // 边框颜色 + .fillColor(getResources().getColor(R.color.half_red)); // 多边形的填充色 + } else { + polygonOptions.strokeWidth(2) // 多边形的边框 + .strokeColor(getResources().getColor(R.color.white)) // 边框颜色 + .fillColor(getResources().getColor(R.color.black60)); // 多边形的填充色 + + } + + polygon = aMap.addPolygon(polygonOptions.zIndex(100)); + + // if (!hasOverlap) { + // upDateLandInfo(); + // } + + } + + /**************************************************************处理滑动事件**************************************************************/ + + /** + * 滑动事件 + * + * @param ev + */ + private void handlePressEvent(MotionEvent ev) { + if (movePosition == -1) { + return; + } + if (hasDrawFinish) { + handleFinishPress(ev); + } else { + handleCommonPress(ev); + + } + + } + + private void handleDownTouchEvent(MotionEvent ev) { + distanceMap.clear(); + for (int i = 0; i < points.size(); i++) { + Point point = aMap.getProjection().toScreenLocation(points.get(i).getLatLng()); + int distance = (int) Math.sqrt(Math.pow(ev.getX() - point.x, 2) + + Math.pow(ev.getY() - point.y, 2)); + distanceMap.put(i, distance); + } + + int[] arr = CommonUtil.getKeyOfMinValue(distanceMap); + if (arr != null && arr[1] < CIRCLE_DEFAULT) { + isDrawPress = true; + aMap.getUiSettings().setAllGesturesEnabled(false); + //说明选中该点 + if (signMark != null) { + signMark.remove(); + } + + movePosition = arr[0]; + pressCircle_isBig = points.get(movePosition).getBigCircle(); + } + + } + + /** + * 滑动结束 + */ + private void handleMoveTouchEvent() { + isDrawPress = false; + pressCircle_isBig = false; + movePosition = -1; + moveSign_center = false; + moveSign_right = false; + isFirstPoint = false; + isLastPoint = false; + aMap.getUiSettings().setAllGesturesEnabled(true); + aMap.getUiSettings().setRotateGesturesEnabled(false);//关闭旋转手势 + aMap.getUiSettings().setTiltGesturesEnabled(false);//关闭倾斜手势 + } + + /** + * 没有闭合 + * + * @param ev + */ + private void handleCommonPress(MotionEvent ev) { + LatLng latLng = aMap.getProjection().fromScreenLocation(new Point((int) ev.getX(), (int) ev.getY())); + + if (pressCircle_isBig) { + + if (movePosition == 0) { + + /******大圆圈****************/ + circleList.get(0).remove(); + circleList.remove(0); + points.remove(0); + circleList.add(0, drawBigCircle(latLng, 0)); + points.add(0, new DrawLatLng(latLng, true)); + + /*********画右边的小圆圈***********/ + LatLng latLng_right = getCenterLatlng(points.get(2).getLatLng(), latLng); + circleList.get(1).remove(); + circleList.remove(1); + points.remove(1); + circleList.add(1, drawSmallCircle(latLng_right, 1)); + + points.add(1, new DrawLatLng(latLng_right, false)); + + /******选中标签****************/ + signMarkPosition = movePosition; + drawSignMark(latLng); + drawLine(); + return; + } + + if (movePosition == points.size() - 1) { + /*********画左边的小圆圈***********/ + LatLng latLng_left = getCenterLatlng(points.get(movePosition - 2).getLatLng(), latLng); + circleList.get(movePosition - 1).remove(); + circleList.remove(movePosition - 1); + points.remove(movePosition - 1); + circleList.add(movePosition - 1, drawSmallCircle(latLng_left, movePosition - 1)); + + points.add(movePosition - 1, new DrawLatLng(latLng_left, false)); + + /******大圆圈****************/ + circleList.get(movePosition).remove(); + circleList.remove(movePosition); + points.remove(movePosition); + circleList.add(movePosition, drawBigCircle(latLng, movePosition)); + points.add(movePosition, new DrawLatLng(latLng, true)); + + /******选中标签****************/ + signMarkPosition = movePosition; + drawSignMark(latLng); + drawLine(); + return; + } + + //移动的是大圆圈 + //重新计算两边小圆圈的位置 + + /*********画左边的小圆圈***********/ + LatLng latLng_left = getCenterLatlng(points.get(movePosition - 2).getLatLng(), latLng); + circleList.get(movePosition - 1).remove(); + circleList.remove(movePosition - 1); + points.remove(movePosition - 1); + circleList.add(movePosition - 1, drawSmallCircle(latLng_left, movePosition - 1)); + + points.add(movePosition - 1, new DrawLatLng(latLng_left, false)); + + /******大圆圈****************/ + circleList.get(movePosition).remove(); + circleList.remove(movePosition); + points.remove(movePosition); + circleList.add(movePosition, drawBigCircle(latLng, movePosition)); + points.add(movePosition, new DrawLatLng(latLng, true)); + + /*********画右边的小圆圈***********/ + LatLng latLng_right = getCenterLatlng(points.get(movePosition + 2).getLatLng(), latLng); + circleList.get(movePosition + 1).remove(); + circleList.remove(movePosition + 1); + points.remove(movePosition + 1); + circleList.add(movePosition + 1, drawSmallCircle(latLng_right, movePosition + 1)); + + points.add(movePosition + 1, new DrawLatLng(latLng_right, false)); + + /******选中标签****************/ + signMarkPosition = movePosition; + drawSignMark(latLng); + drawLine(); + } else { + if (movePosition == points.size() - 1 || isLastPoint) { + handleSmallCircleIsLastPoint(ev, latLng); + isLastPoint = true; + return; + } + + //判断是否是位置1 + if (movePosition == 1 || isFirstPoint) { + handleSmallCircleIsFirstPoint(ev, latLng); + isFirstPoint = true; + return; + } + handleSmallCircleNotLastPoint(ev, latLng); + } + } + + /** + * 已经完成了 + * + * @param ev + */ + private void handleFinishPress(MotionEvent ev) { + LatLng latLng = aMap.getProjection().fromScreenLocation(new Point((int) ev.getX(), (int) ev.getY())); + if (pressCircle_isBig) { + // 完成,需要判断是否是第一个点 + if (movePosition == 0 || isFirstPoint) { + isFirstPoint = true; + handleBigCircleIsFirtPoint(ev, latLng); + return; + } + //判断是否是最后一个大圆圈 + if (movePosition == points.size() - 2 || isLastPoint) { + isLastPoint = true; + handleBigCircleIsLastPoint(ev, latLng); + return; + } + + handleBigCircleNotFirtPoint(ev, latLng); + + } else { + //移动的是小圆圈,小圆圈需要判断是否是最后一个 + + if (movePosition == points.size() - 1 || isLastPoint) { + isLastPoint = true; + handleSmallCircleIsLastPoint(ev, latLng); + return; + } + + //判断是否是位置1 + if (movePosition == 1 || isFirstPoint) { + isFirstPoint = true; + handleSmallCircleIsFirstPoint(ev, latLng); + return; + } + + handleSmallCircleNotLastPoint(ev, latLng); + } + + } + + private void handleSmallCircleIsLastPoint(MotionEvent ev, LatLng latLng) { + /*********画左边的小圆圈***********/ + LatLng latLng_left = getCenterLatlng(points.get(movePosition - 1).getLatLng(), latLng); + + //两边是小圆圈,清除上次的 + circleList.get(movePosition).remove(); + circleList.remove(movePosition); + points.remove(movePosition); + circleList.add(movePosition, drawSmallCircle(latLng_left, movePosition)); + points.add(movePosition, new DrawLatLng(latLng_left, false)); + + /******大圆圈****************/ + + if (moveSign_center) { + circleList.get(movePosition + 1).remove(); + circleList.remove(movePosition + 1); + points.remove(movePosition + 1); + circleList.add(movePosition + 1, drawBigCircle(latLng, movePosition + 1)); + points.add(movePosition + 1, new DrawLatLng(latLng, true)); + } else { + circleList.add(drawBigCircle(latLng, circleList.size())); + points.add(new DrawLatLng(latLng, true)); + moveSign_center = true; + } + + /******选中标签****************/ + signMarkPosition = movePosition; + drawSignMark(latLng); + + /*********画右边的小圆圈***********/ + LatLng latLng_right = getCenterLatlng(points.get(0).getLatLng(), latLng); + + if (moveSign_right) { + circleList.get(movePosition + 2).remove(); + circleList.remove(movePosition + 2); + points.remove(movePosition + 2); + circleList.add(movePosition + 2, drawSmallCircle(latLng_right, movePosition + 2)); + points.add(movePosition + 2, new DrawLatLng(latLng_right, false)); + } else { + circleList.add(drawSmallCircle(latLng_right, circleList.size())); + points.add(new DrawLatLng(latLng_right, false)); + moveSign_right = true; + } + + if (hasDrawFinish) { + drawPolygon(); + } else { + drawLine(); + } + + } + + private void handleBigCircleNotFirtPoint(MotionEvent ev, LatLng latLng) { + //移动的是大圆圈 + //重新计算两边小圆圈的位置 + + /*********画左边的小圆圈***********/ + LatLng latLng_left = getCenterLatlng(points.get(movePosition - 2).getLatLng(), latLng); + circleList.get(movePosition - 1).remove(); + circleList.remove(movePosition - 1); + points.remove(movePosition - 1); + circleList.add(movePosition - 1, drawSmallCircle(latLng_left, movePosition - 1)); + + points.add(movePosition - 1, new DrawLatLng(latLng_left, false)); + + /******大圆圈****************/ + + circleList.get(movePosition).remove(); + circleList.remove(movePosition); + points.remove(movePosition); + circleList.add(movePosition, drawBigCircle(latLng, movePosition)); + points.add(movePosition, new DrawLatLng(latLng, true)); + + /******选中标签****************/ + signMarkPosition = movePosition; + drawSignMark(latLng); + + /*********画右边的小圆圈***********/ + LatLng latLng_right = getCenterLatlng(points.get(movePosition + 2).getLatLng(), latLng); + + circleList.get(movePosition + 1).remove(); + circleList.remove(movePosition + 1); + points.remove(movePosition + 1); + circleList.add(movePosition + 1, drawSmallCircle(latLng_right, movePosition + 1)); + + points.add(movePosition + 1, new DrawLatLng(latLng_right, false)); + + drawPolygon(); + } + + private void handleBigCircleIsFirtPoint(MotionEvent ev, LatLng latLng) { + + /*********画左边的小圆圈***********/ + LatLng latLng_left = getCenterLatlng(points.get(points.size() - 2).getLatLng(), latLng); + + circleList.get(circleList.size() - 1).remove(); + circleList.remove(circleList.size() - 1); + circleList.add(drawSmallCircle(latLng_left, circleList.size())); + points.remove(points.size() - 1); + points.add(new DrawLatLng(latLng_left, false)); + + /******大圆圈****************/ + + circleList.get(0).remove(); + circleList.remove(0); + points.remove(0); + circleList.add(0, drawBigCircle(latLng, 0)); + points.add(0, new DrawLatLng(latLng, true)); + + /******选中标签****************/ + signMarkPosition = movePosition; + drawSignMark(latLng); + + /*********画右边的小圆圈***********/ + LatLng latLng_right = getCenterLatlng(points.get(2).getLatLng(), latLng); + + //清除上次的 + circleList.get(1).remove(); + circleList.remove(1); + points.remove(1); + + circleList.add(1, drawSmallCircle(latLng_right, 1)); + points.add(1, new DrawLatLng(latLng_right, false)); + drawPolygon(); + } + + private void handleSmallCircleIsFirstPoint(MotionEvent ev, LatLng latLng) { + /*********画左边的小圆圈***********/ + + Point point_left = aMap.getProjection().toScreenLocation(points.get(0).getLatLng()); + Point centerPoint_left = new Point(CommonUtil.avg(point_left.x, (int) ev.getX()), + CommonUtil.avg(point_left.y, (int) ev.getY())); + + LatLng latLng_left = aMap.getProjection().fromScreenLocation(centerPoint_left); + + //两边是小圆圈,清除上次的 + circleList.get(movePosition).remove(); + circleList.remove(movePosition); + points.remove(movePosition); + + circleList.add(movePosition, drawSmallCircle(latLng_left, movePosition)); + points.add(movePosition, new DrawLatLng(latLng_left, false)); + + /******大圆圈****************/ + + if (moveSign_center) { + circleList.get(movePosition + 1).remove(); + circleList.remove(movePosition + 1); + points.remove(movePosition + 1); + circleList.add(movePosition + 1, drawBigCircle(latLng, movePosition + 1)); + points.add(movePosition + 1, new DrawLatLng(latLng, true)); + } else { + circleList.add(movePosition + 1, drawBigCircle(latLng, movePosition + 1)); + points.add(movePosition + 1, new DrawLatLng(latLng, true)); + moveSign_center = true; + } + + /******选中标签****************/ + signMarkPosition = movePosition; + drawSignMark(latLng); + + /*********画右边的小圆圈***********/ + + LatLng newLatLng; + if (moveSign_right) { + newLatLng = points.get(movePosition + 3).getLatLng(); + } else { + newLatLng = points.get(movePosition + 2).getLatLng(); + } + + Point point_right = aMap.getProjection().toScreenLocation(newLatLng); + Point centerPoint_right = new Point(CommonUtil.avg(point_right.x, (int) ev.getX()), + CommonUtil.avg(point_right.y, (int) ev.getY())); + + LatLng latLng_right = aMap.getProjection().fromScreenLocation(centerPoint_right); + + if (moveSign_right) { + //两边是小圆圈,清除上次的 + circleList.get(movePosition + 2).remove(); + circleList.remove(movePosition + 2); + points.remove(movePosition + 2); + circleList.add(movePosition + 2, drawSmallCircle(latLng_right, movePosition + 2)); + points.add(movePosition + 2, new DrawLatLng(latLng_right, false)); + + } else { + circleList.add(movePosition + 2, drawSmallCircle(latLng_right, movePosition + 2)); + points.add(movePosition + 2, new DrawLatLng(latLng_right, false)); + moveSign_right = true; + } + if (hasDrawFinish) { + drawPolygon(); + } else { + drawLine(); + } + } + + private void handleSmallCircleNotLastPoint(MotionEvent ev, LatLng latLng) { + /*********画左边的小圆圈***********/ + + Point point_left = aMap.getProjection().toScreenLocation(points.get(movePosition - 1).getLatLng()); + Point centerPoint_left = new Point(CommonUtil.avg(point_left.x, (int) ev.getX()), + CommonUtil.avg(point_left.y, (int) ev.getY())); + + LatLng latLng_left = aMap.getProjection().fromScreenLocation(centerPoint_left); + + //两边是小圆圈,清除上次的 + circleList.get(movePosition).remove(); + circleList.remove(movePosition); + points.remove(movePosition); + circleList.add(movePosition, drawSmallCircle(latLng_left, movePosition)); + points.add(movePosition, new DrawLatLng(latLng_left, false)); + + /******大圆圈****************/ + + if (moveSign_center) { + circleList.get(movePosition + 1).remove(); + circleList.remove(movePosition + 1); + points.remove(movePosition + 1); + circleList.add(movePosition + 1, drawBigCircle(latLng, movePosition + 1)); + points.add(movePosition + 1, new DrawLatLng(latLng, true)); + + } else { + circleList.add(movePosition + 1, drawBigCircle(latLng, movePosition + 1)); + points.add(movePosition + 1, new DrawLatLng(latLng, true)); + moveSign_center = true; + } + + /******选中标签****************/ + signMarkPosition = movePosition; + drawSignMark(latLng); + + /*********画右边的小圆圈***********/ + LatLng newLatlng; + if (moveSign_right) { + newLatlng = points.get(movePosition + 3).getLatLng(); + } else { + newLatlng = points.get(movePosition + 2).getLatLng(); + } + + Point point_right = aMap.getProjection().toScreenLocation(newLatlng); + Point centerPoint_right = new Point(CommonUtil.avg(point_right.x, (int) ev.getX()), + CommonUtil.avg(point_right.y, (int) ev.getY())); + + LatLng latLng_right = aMap.getProjection().fromScreenLocation(centerPoint_right); + + if (moveSign_right) { + //两边是小圆圈,清除上次的 + circleList.get(movePosition + 2).remove(); + circleList.remove(movePosition + 2); + points.remove(movePosition + 2); + circleList.add(movePosition + 2, drawSmallCircle(latLng_right, movePosition + 2)); + points.add(movePosition + 2, new DrawLatLng(latLng_right, false)); + } else { + circleList.add(movePosition + 2, drawSmallCircle(latLng_right, movePosition + 2)); + points.add(movePosition + 2, new DrawLatLng(latLng_right, false)); + moveSign_right = true; + } + + if (hasDrawFinish) { + drawPolygon(); + } else { + drawLine(); + } + } + + private void handleBigCircleIsLastPoint(MotionEvent ev, LatLng latLng) { + //移动的是大圆圈 + //重新计算两边小圆圈的位置 + + /*********画左边的小圆圈***********/ + + Point point_left = aMap.getProjection().toScreenLocation(points.get(movePosition - 2).getLatLng()); + Point centerPoint_left = new Point(CommonUtil.avg(point_left.x, (int) ev.getX()), + CommonUtil.avg(point_left.y, (int) ev.getY())); + + LatLng latLng_left = aMap.getProjection().fromScreenLocation(centerPoint_left); + + circleList.get(movePosition - 1).remove(); + circleList.remove(movePosition - 1); + points.remove(movePosition - 1); + circleList.add(movePosition - 1, drawSmallCircle(latLng_left, movePosition - 1)); + + points.add(movePosition - 1, new DrawLatLng(latLng_left, false)); + + /******大圆圈****************/ + + circleList.get(movePosition).remove(); + circleList.remove(movePosition); + points.remove(movePosition); + circleList.add(movePosition, drawBigCircle(latLng, movePosition)); + points.add(movePosition, new DrawLatLng(latLng, true)); + + /******选中标签****************/ + signMarkPosition = movePosition; + drawSignMark(latLng); + + /*********画右边的小圆圈***********/ + + Point point_right = aMap.getProjection().toScreenLocation(points.get(0).getLatLng()); + Point centerPoint_right = new Point(CommonUtil.avg(point_right.x, (int) ev.getX()), + CommonUtil.avg(point_right.y, (int) ev.getY())); + + LatLng latLng_right = aMap.getProjection().fromScreenLocation(centerPoint_right); + + circleList.get(movePosition + 1).remove(); + circleList.remove(movePosition + 1); + points.remove(movePosition + 1); + circleList.add(movePosition + 1, drawSmallCircle(latLng_right, movePosition + 1)); + + points.add(movePosition + 1, new DrawLatLng(latLng_right, false)); + + drawPolygon(); + } + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/adapter/LandAdapter.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/adapter/LandAdapter.java new file mode 100644 index 0000000..a873e78 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/adapter/LandAdapter.java @@ -0,0 +1,37 @@ +package com.tairui.gov_affairs_cloud.ui.land.adapter; + +import java.util.List; + +import com.chad.library.adapter.base.BaseMultiItemQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.base.entity.BaseHolderEntity; + +import androidx.annotation.NonNull; + +public class LandAdapter extends BaseMultiItemQuickAdapter { + + public LandAdapter(List list) { + super(list); + addItemType(1, R.layout.item_land_overview); + addItemType(2, R.layout.item_land_overview); + // addItemType(2, R.layout.item_coupon_list_allow); + // addItemType(3, R.layout.item_coupon_list_not_allow); + } + + @Override + protected void convert(@NonNull BaseViewHolder holder, BaseHolderEntity entity) { + switch (holder.getItemViewType()) { + case 1: + break; + case 2: + break; + case 3: + break; + default: + break; + } + } + +} + diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/AddLandEntity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/AddLandEntity.java new file mode 100644 index 0000000..8b88985 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/AddLandEntity.java @@ -0,0 +1,347 @@ +package com.tairui.gov_affairs_cloud.ui.land.entity; + +import com.google.gson.annotations.SerializedName; + +public class AddLandEntity { + + @SerializedName("id") + private String id; + @SerializedName("landName") + private String landName; + @SerializedName("villageCode") + private String villageCode; + @SerializedName("gridId") + private String gridId; + @SerializedName("owner") + private Object owner; + @SerializedName("landType") + private String landType; + @SerializedName("coordinate") + private Object coordinate; + @SerializedName("landCode") + private Object landCode; + @SerializedName("soilTypeId") + private String soilTypeId; + @SerializedName("area") + private Integer area; + @SerializedName("landStatus") + private Integer landStatus; + @SerializedName("propertyName") + private Object propertyName; + @SerializedName("propertyPhone") + private Object propertyPhone; + @SerializedName("propertyCertificateUrl") + private Object propertyCertificateUrl; + @SerializedName("landUseName") + private Object landUseName; + @SerializedName("landUsePhone") + private Object landUsePhone; + @SerializedName("nature") + private Object nature; + @SerializedName("landCertificateUrl") + private Object landCertificateUrl; + @SerializedName("isDraftsSave") + private Object isDraftsSave; + @SerializedName("landTransfer") + private Object landTransfer; + @SerializedName("landTypeId") + private Object landTypeId; + @SerializedName("createTime") + private String createTime; + @SerializedName("createUser") + private String createUser; + @SerializedName("updateTime") + private Object updateTime; + @SerializedName("updateUser") + private Object updateUser; + @SerializedName("landUrl") + private String landUrl; + @SerializedName("landUnit") + private Object landUnit; + @SerializedName("provinceCode") + private Object provinceCode; + @SerializedName("cityCode") + private Object cityCode; + @SerializedName("gridAreacode") + private Object gridAreacode; + @SerializedName("townCode") + private Object townCode; + @SerializedName("scope") + private String scope; + @SerializedName("address") + private String address; + @SerializedName("scopeImg") + private String scopeImg; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getLandName() { + return landName; + } + + public void setLandName(String landName) { + this.landName = landName; + } + + public String getVillageCode() { + return villageCode; + } + + public void setVillageCode(String villageCode) { + this.villageCode = villageCode; + } + + public String getGridId() { + return gridId; + } + + public void setGridId(String gridId) { + this.gridId = gridId; + } + + public Object getOwner() { + return owner; + } + + public void setOwner(Object owner) { + this.owner = owner; + } + + public String getLandType() { + return landType; + } + + public void setLandType(String landType) { + this.landType = landType; + } + + public Object getCoordinate() { + return coordinate; + } + + public void setCoordinate(Object coordinate) { + this.coordinate = coordinate; + } + + public Object getLandCode() { + return landCode; + } + + public void setLandCode(Object landCode) { + this.landCode = landCode; + } + + public String getSoilTypeId() { + return soilTypeId; + } + + public void setSoilTypeId(String soilTypeId) { + this.soilTypeId = soilTypeId; + } + + public Integer getArea() { + return area; + } + + public void setArea(Integer area) { + this.area = area; + } + + public Integer getLandStatus() { + return landStatus; + } + + public void setLandStatus(Integer landStatus) { + this.landStatus = landStatus; + } + + public Object getPropertyName() { + return propertyName; + } + + public void setPropertyName(Object propertyName) { + this.propertyName = propertyName; + } + + public Object getPropertyPhone() { + return propertyPhone; + } + + public void setPropertyPhone(Object propertyPhone) { + this.propertyPhone = propertyPhone; + } + + public Object getPropertyCertificateUrl() { + return propertyCertificateUrl; + } + + public void setPropertyCertificateUrl(Object propertyCertificateUrl) { + this.propertyCertificateUrl = propertyCertificateUrl; + } + + public Object getLandUseName() { + return landUseName; + } + + public void setLandUseName(Object landUseName) { + this.landUseName = landUseName; + } + + public Object getLandUsePhone() { + return landUsePhone; + } + + public void setLandUsePhone(Object landUsePhone) { + this.landUsePhone = landUsePhone; + } + + public Object getNature() { + return nature; + } + + public void setNature(Object nature) { + this.nature = nature; + } + + public Object getLandCertificateUrl() { + return landCertificateUrl; + } + + public void setLandCertificateUrl(Object landCertificateUrl) { + this.landCertificateUrl = landCertificateUrl; + } + + public Object getIsDraftsSave() { + return isDraftsSave; + } + + public void setIsDraftsSave(Object isDraftsSave) { + this.isDraftsSave = isDraftsSave; + } + + public Object getLandTransfer() { + return landTransfer; + } + + public void setLandTransfer(Object landTransfer) { + this.landTransfer = landTransfer; + } + + public Object getLandTypeId() { + return landTypeId; + } + + public void setLandTypeId(Object landTypeId) { + this.landTypeId = landTypeId; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getCreateUser() { + return createUser; + } + + public void setCreateUser(String createUser) { + this.createUser = createUser; + } + + public Object getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Object updateTime) { + this.updateTime = updateTime; + } + + public Object getUpdateUser() { + return updateUser; + } + + public void setUpdateUser(Object updateUser) { + this.updateUser = updateUser; + } + + public String getLandUrl() { + return landUrl; + } + + public void setLandUrl(String landUrl) { + this.landUrl = landUrl; + } + + public Object getLandUnit() { + return landUnit; + } + + public void setLandUnit(Object landUnit) { + this.landUnit = landUnit; + } + + public Object getProvinceCode() { + return provinceCode; + } + + public void setProvinceCode(Object provinceCode) { + this.provinceCode = provinceCode; + } + + public Object getCityCode() { + return cityCode; + } + + public void setCityCode(Object cityCode) { + this.cityCode = cityCode; + } + + public Object getGridAreacode() { + return gridAreacode; + } + + public void setGridAreacode(Object gridAreacode) { + this.gridAreacode = gridAreacode; + } + + public Object getTownCode() { + return townCode; + } + + public void setTownCode(Object townCode) { + this.townCode = townCode; + } + + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getScopeImg() { + return scopeImg; + } + + public void setScopeImg(String scopeImg) { + this.scopeImg = scopeImg; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandAreaRegionEntity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandAreaRegionEntity.java new file mode 100644 index 0000000..8686840 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandAreaRegionEntity.java @@ -0,0 +1,75 @@ +package com.tairui.gov_affairs_cloud.ui.land.entity; + +import java.util.List; + +import com.contrarywind.interfaces.IPickerViewData; +import com.google.gson.annotations.SerializedName; + +public class LandAreaRegionEntity implements IPickerViewData { + + @SerializedName("id") + private String id; + @SerializedName("areaName") + private String areaName; + @SerializedName("parentId") + private Object parentId; + @SerializedName("areaCode") + private String areaCode; + @SerializedName("level") + private Integer level; + @SerializedName("areaChildVOS") + private List areaChildVOS; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getAreaName() { + return areaName; + } + + public void setAreaName(String areaName) { + this.areaName = areaName; + } + + public Object getParentId() { + return parentId; + } + + public void setParentId(Object parentId) { + this.parentId = parentId; + } + + public String getAreaCode() { + return areaCode; + } + + public void setAreaCode(String areaCode) { + this.areaCode = areaCode; + } + + public Integer getLevel() { + return level; + } + + public void setLevel(Integer level) { + this.level = level; + } + + public List getAreaChildVOS() { + return areaChildVOS; + } + + public void setAreaChildVOS(List areaChildVOS) { + this.areaChildVOS = areaChildVOS; + } + + @Override + public String getPickerViewText() { + return areaName; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandGridEntity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandGridEntity.java new file mode 100644 index 0000000..3e5e40d --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandGridEntity.java @@ -0,0 +1,75 @@ +package com.tairui.gov_affairs_cloud.ui.land.entity; + +import java.util.List; + +import com.contrarywind.interfaces.IPickerViewData; +import com.google.gson.annotations.SerializedName; + +public class LandGridEntity implements IPickerViewData { + + @SerializedName("regionCode") + private String regionCode; + @SerializedName("regionName") + private String regionName; + @SerializedName("total") + private Integer total; + @SerializedName("cooperativeCount") + private Integer cooperativeCount; + @SerializedName("farmerCount") + private Integer farmerCount; + @SerializedName("children") + private List children; + + public String getRegionCode() { + return regionCode; + } + + public void setRegionCode(String regionCode) { + this.regionCode = regionCode; + } + + public String getRegionName() { + return regionName; + } + + public void setRegionName(String regionName) { + this.regionName = regionName; + } + + public Integer getTotal() { + return total; + } + + public void setTotal(Integer total) { + this.total = total; + } + + public Integer getCooperativeCount() { + return cooperativeCount; + } + + public void setCooperativeCount(Integer cooperativeCount) { + this.cooperativeCount = cooperativeCount; + } + + public Integer getFarmerCount() { + return farmerCount; + } + + public void setFarmerCount(Integer farmerCount) { + this.farmerCount = farmerCount; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } + + @Override + public String getPickerViewText() { + return regionName; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandGroudTypeEntity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandGroudTypeEntity.java new file mode 100644 index 0000000..fde3e73 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandGroudTypeEntity.java @@ -0,0 +1,188 @@ +package com.tairui.gov_affairs_cloud.ui.land.entity; + +import java.util.List; + +import com.contrarywind.interfaces.IPickerViewData; +import com.google.gson.annotations.SerializedName; + +public class LandGroudTypeEntity { + + @SerializedName("total") + private Integer total; + @SerializedName("size") + private Integer size; + @SerializedName("current") + private Integer current; + @SerializedName("optimizeCountSql") + private Boolean optimizeCountSql; + @SerializedName("searchCount") + private Boolean searchCount; + @SerializedName("maxLimit") + private Object maxLimit; + @SerializedName("countId") + private Object countId; + @SerializedName("pages") + private Integer pages; + @SerializedName("records") + private List records; + @SerializedName("orders") + private List orders; + + public Integer getTotal() { + return total; + } + + public void setTotal(Integer total) { + this.total = total; + } + + public Integer getSize() { + return size; + } + + public void setSize(Integer size) { + this.size = size; + } + + public Integer getCurrent() { + return current; + } + + public void setCurrent(Integer current) { + this.current = current; + } + + public Boolean isOptimizeCountSql() { + return optimizeCountSql; + } + + public void setOptimizeCountSql(Boolean optimizeCountSql) { + this.optimizeCountSql = optimizeCountSql; + } + + public Boolean isSearchCount() { + return searchCount; + } + + public void setSearchCount(Boolean searchCount) { + this.searchCount = searchCount; + } + + public Object getMaxLimit() { + return maxLimit; + } + + public void setMaxLimit(Object maxLimit) { + this.maxLimit = maxLimit; + } + + public Object getCountId() { + return countId; + } + + public void setCountId(Object countId) { + this.countId = countId; + } + + public Integer getPages() { + return pages; + } + + public void setPages(Integer pages) { + this.pages = pages; + } + + public List getRecords() { + return records; + } + + public void setRecords(List records) { + this.records = records; + } + + public List getOrders() { + return orders; + } + + public void setOrders(List orders) { + this.orders = orders; + } + + public static class RecordsEntity implements IPickerViewData { + @SerializedName("id") + private String id; + @SerializedName("soilType") + private String soilType; + @SerializedName("status") + private String status; + @SerializedName("createTime") + private String createTime; + @SerializedName("createUser") + private String createUser; + @SerializedName("updateTime") + private String updateTime; + @SerializedName("updateUser") + private String updateUser; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getSoilType() { + return soilType; + } + + public void setSoilType(String soilType) { + this.soilType = soilType; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getCreateUser() { + return createUser; + } + + public void setCreateUser(String createUser) { + this.createUser = createUser; + } + + public String getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(String updateTime) { + this.updateTime = updateTime; + } + + public String getUpdateUser() { + return updateUser; + } + + public void setUpdateUser(String updateUser) { + this.updateUser = updateUser; + } + + @Override + public String getPickerViewText() { + return soilType; + } + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandOverviewEntity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandOverviewEntity.java new file mode 100644 index 0000000..59c49e3 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandOverviewEntity.java @@ -0,0 +1,62 @@ +package com.tairui.gov_affairs_cloud.ui.land.entity; + +import java.util.List; + +import com.google.gson.annotations.SerializedName; + +public class LandOverviewEntity { + + @SerializedName("total") + private float total; + @SerializedName("list") + private List list; + + public float getTotal() { + return total; + } + + public void setTotal(float total) { + this.total = total; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public static class ListEntity { + @SerializedName("landTypeId") + private String landTypeId; + @SerializedName("landTypeName") + private String landTypeName; + @SerializedName("area") + private float area; + + public String getLandTypeId() { + return landTypeId; + } + + public void setLandTypeId(String landTypeId) { + this.landTypeId = landTypeId; + } + + public String getLandTypeName() { + return landTypeName; + } + + public void setLandTypeName(String landTypeName) { + this.landTypeName = landTypeName; + } + + public float getArea() { + return area; + } + + public void setArea(float area) { + this.area = area; + } + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandPlateAnalysisEntity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandPlateAnalysisEntity.java new file mode 100644 index 0000000..cf1a110 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandPlateAnalysisEntity.java @@ -0,0 +1,52 @@ +package com.tairui.gov_affairs_cloud.ui.land.entity; + +import java.util.List; + +import com.google.gson.annotations.SerializedName; + +public class LandPlateAnalysisEntity { + + @SerializedName("total") + private Double total; + @SerializedName("list") + private List list; + + public Double getTotal() { + return total; + } + + public void setTotal(Double total) { + this.total = total; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public static class ListEntity { + @SerializedName("name") + private String name; + @SerializedName("count") + private Double count; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Double getCount() { + return count; + } + + public void setCount(Double count) { + this.count = count; + } + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandPurposeAnalysisEntity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandPurposeAnalysisEntity.java new file mode 100644 index 0000000..07b3dcb --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandPurposeAnalysisEntity.java @@ -0,0 +1,52 @@ +package com.tairui.gov_affairs_cloud.ui.land.entity; + +import java.util.List; + +import com.google.gson.annotations.SerializedName; + +public class LandPurposeAnalysisEntity { + + @SerializedName("total") + private Double total; + @SerializedName("list") + private List list; + + public Double getTotal() { + return total; + } + + public void setTotal(Double total) { + this.total = total; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public static class ListEntity { + @SerializedName("name") + private String name; + @SerializedName("count") + private Double count; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Double getCount() { + return count; + } + + public void setCount(Double count) { + this.count = count; + } + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandResourceEntity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandResourceEntity.java new file mode 100644 index 0000000..787634e --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandResourceEntity.java @@ -0,0 +1,483 @@ +package com.tairui.gov_affairs_cloud.ui.land.entity; + +import java.io.Serializable; +import java.util.List; + +import com.google.gson.annotations.SerializedName; + +public class LandResourceEntity { + + @SerializedName("total") + private Integer total; + @SerializedName("size") + private Integer size; + @SerializedName("current") + private Integer current; + @SerializedName("optimizeCountSql") + private Boolean optimizeCountSql; + @SerializedName("searchCount") + private Boolean searchCount; + @SerializedName("maxLimit") + private Object maxLimit; + @SerializedName("countId") + private Object countId; + @SerializedName("pages") + private Integer pages; + @SerializedName("records") + private List records; + @SerializedName("orders") + private List orders; + + public Integer getTotal() { + return total; + } + + public void setTotal(Integer total) { + this.total = total; + } + + public Integer getSize() { + return size; + } + + public void setSize(Integer size) { + this.size = size; + } + + public Integer getCurrent() { + return current; + } + + public void setCurrent(Integer current) { + this.current = current; + } + + public Boolean isOptimizeCountSql() { + return optimizeCountSql; + } + + public void setOptimizeCountSql(Boolean optimizeCountSql) { + this.optimizeCountSql = optimizeCountSql; + } + + public Boolean isSearchCount() { + return searchCount; + } + + public void setSearchCount(Boolean searchCount) { + this.searchCount = searchCount; + } + + public Object getMaxLimit() { + return maxLimit; + } + + public void setMaxLimit(Object maxLimit) { + this.maxLimit = maxLimit; + } + + public Object getCountId() { + return countId; + } + + public void setCountId(Object countId) { + this.countId = countId; + } + + public Integer getPages() { + return pages; + } + + public void setPages(Integer pages) { + this.pages = pages; + } + + public List getRecords() { + return records; + } + + public void setRecords(List records) { + this.records = records; + } + + public List getOrders() { + return orders; + } + + public void setOrders(List orders) { + this.orders = orders; + } + + public static class RecordsEntity implements Serializable { + @SerializedName("id") + private String id; + @SerializedName("landName") + private String landName; + @SerializedName("gridId") + private String gridId; + @SerializedName("provinceCode") + private String provinceCode; + @SerializedName("cityCode") + private String cityCode; + @SerializedName("county") + private String county; + @SerializedName("townCode") + private String townCode; + @SerializedName("villageCode") + private String villageCode; + @SerializedName("owner") + private String owner; + @SerializedName("landClassificationType") + private String landClassificationType; + @SerializedName("area") + private Double area; + @SerializedName("landTransfer") + private Object landTransfer; + @SerializedName("landCode") + private String landCode; + @SerializedName("soilType") + private String soilType; + @SerializedName("isUpload") + private Integer isUpload; + @SerializedName("landStatus") + private Integer landStatus; + @SerializedName("address") + private String address; + @SerializedName("landCertificateUrl") + private String landCertificateUrl; + @SerializedName("propertyCertificateUrl") + private String propertyCertificateUrl; + @SerializedName("coordinate") + private String coordinate; + @SerializedName("landType") + private String landType; + @SerializedName("landTypeName") + private String landTypeName; + @SerializedName("landUrl") + private String landUrl; + @SerializedName("scopeImg") + private String scopeImg; + @SerializedName("soilId") + private String soilId; + @SerializedName("landTypeId") + private String landTypeId; + @SerializedName("landUnit") + private String landUnit; + @SerializedName("pid") + private String pid; + @SerializedName("propertyName") + private String propertyName; + @SerializedName("propertyPhone") + private String propertyPhone; + @SerializedName("landUserName") + private String landUserName; + @SerializedName("nature") + private String nature; + @SerializedName("landUserPhone") + private Object landUserPhone; + @SerializedName("scope") + private Object scope; + @SerializedName("detailAddress") + private String detailAddress; + @SerializedName("gridName") + private String gridName; + @SerializedName("fullRegionName") + private String fullRegionName; + + public String getFullRegionName() { + return fullRegionName; + } + + public void setFullRegionName(String fullRegionName) { + this.fullRegionName = fullRegionName; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getLandName() { + return landName; + } + + public void setLandName(String landName) { + this.landName = landName; + } + + public String getGridId() { + return gridId; + } + + public void setGridId(String gridId) { + this.gridId = gridId; + } + + public String getProvinceCode() { + return provinceCode; + } + + public void setProvinceCode(String provinceCode) { + this.provinceCode = provinceCode; + } + + public String getCityCode() { + return cityCode; + } + + public void setCityCode(String cityCode) { + this.cityCode = cityCode; + } + + public String getCounty() { + return county; + } + + public void setCounty(String county) { + this.county = county; + } + + public String getTownCode() { + return townCode; + } + + public void setTownCode(String townCode) { + this.townCode = townCode; + } + + public String getVillageCode() { + return villageCode; + } + + public void setVillageCode(String villageCode) { + this.villageCode = villageCode; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } + + public String getGridName() { + return gridName; + } + + public void setGridName(String gridName) { + this.gridName = gridName; + } + + public String getLandClassificationType() { + return landClassificationType; + } + + public void setLandClassificationType(String landClassificationType) { + this.landClassificationType = landClassificationType; + } + + public Double getArea() { + return area; + } + + public void setArea(Double area) { + this.area = area; + } + + public Object getLandTransfer() { + return landTransfer; + } + + public void setLandTransfer(Object landTransfer) { + this.landTransfer = landTransfer; + } + + public String getLandCode() { + return landCode; + } + + public void setLandCode(String landCode) { + this.landCode = landCode; + } + + public String getSoilType() { + return soilType; + } + + public void setSoilType(String soilType) { + this.soilType = soilType; + } + + public Integer getIsUpload() { + return isUpload; + } + + public void setIsUpload(Integer isUpload) { + this.isUpload = isUpload; + } + + public Integer getLandStatus() { + return landStatus; + } + + public void setLandStatus(Integer landStatus) { + this.landStatus = landStatus; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getLandCertificateUrl() { + return landCertificateUrl; + } + + public void setLandCertificateUrl(String landCertificateUrl) { + this.landCertificateUrl = landCertificateUrl; + } + + public String getPropertyCertificateUrl() { + return propertyCertificateUrl; + } + + public void setPropertyCertificateUrl(String propertyCertificateUrl) { + this.propertyCertificateUrl = propertyCertificateUrl; + } + + public String getCoordinate() { + return coordinate; + } + + public void setCoordinate(String coordinate) { + this.coordinate = coordinate; + } + + public String getLandType() { + return landType; + } + + public void setLandType(String landType) { + this.landType = landType; + } + + public String getLandUrl() { + return landUrl; + } + + public void setLandUrl(String landUrl) { + this.landUrl = landUrl; + } + + public String getSoilId() { + return soilId; + } + + public void setSoilId(String soilId) { + this.soilId = soilId; + } + + public String getLandTypeId() { + return landTypeId; + } + + public void setLandTypeId(String landTypeId) { + this.landTypeId = landTypeId; + } + + public String getLandUnit() { + return landUnit; + } + + public void setLandUnit(String landUnit) { + this.landUnit = landUnit; + } + + public String getPid() { + return pid; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public String getPropertyName() { + return propertyName; + } + + public void setPropertyName(String propertyName) { + this.propertyName = propertyName; + } + + public String getPropertyPhone() { + return propertyPhone; + } + + public void setPropertyPhone(String propertyPhone) { + this.propertyPhone = propertyPhone; + } + + public String getLandUserName() { + return landUserName; + } + + public void setLandUserName(String landUserName) { + this.landUserName = landUserName; + } + + public String getNature() { + return nature; + } + + public void setNature(String nature) { + this.nature = nature; + } + + public Object getLandUserPhone() { + return landUserPhone; + } + + public void setLandUserPhone(Object landUserPhone) { + this.landUserPhone = landUserPhone; + } + + public Object getScope() { + return scope; + } + + public void setScope(Object scope) { + this.scope = scope; + } + + public String getDetailAddress() { + return detailAddress; + } + + public void setDetailAddress(String detailAddress) { + this.detailAddress = detailAddress; + } + + public String getLandTypeName() { + return landTypeName; + } + + public void setLandTypeName(String landTypeName) { + this.landTypeName = landTypeName; + } + + public String getScopeImg() { + return scopeImg; + } + + public void setScopeImg(String scopeImg) { + this.scopeImg = scopeImg; + } + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandResourceTypeEntity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandResourceTypeEntity.java new file mode 100644 index 0000000..9c361d7 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandResourceTypeEntity.java @@ -0,0 +1,87 @@ +package com.tairui.gov_affairs_cloud.ui.land.entity; + +import com.google.gson.annotations.SerializedName; + +public class LandResourceTypeEntity { + + @SerializedName("id") + private String id; + @SerializedName("pid") + private String pid; + @SerializedName("landType") + private String landType; + @SerializedName("status") + private String status; + @SerializedName("createTime") + private Object createTime; + @SerializedName("createUser") + private String createUser; + @SerializedName("updateTime") + private String updateTime; + @SerializedName("updateUser") + private String updateUser; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getPid() { + return pid; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public String getLandType() { + return landType; + } + + public void setLandType(String landType) { + this.landType = landType; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Object getCreateTime() { + return createTime; + } + + public void setCreateTime(Object createTime) { + this.createTime = createTime; + } + + public String getCreateUser() { + return createUser; + } + + public void setCreateUser(String createUser) { + this.createUser = createUser; + } + + public String getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(String updateTime) { + this.updateTime = updateTime; + } + + public String getUpdateUser() { + return updateUser; + } + + public void setUpdateUser(String updateUser) { + this.updateUser = updateUser; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandTypeEntity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandTypeEntity.java new file mode 100644 index 0000000..51ed258 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/LandTypeEntity.java @@ -0,0 +1,65 @@ +package com.tairui.gov_affairs_cloud.ui.land.entity; + +import java.util.ArrayList; +import java.util.List; + +import com.contrarywind.interfaces.IPickerViewData; +import com.google.gson.annotations.SerializedName; + +public class LandTypeEntity implements IPickerViewData { + + @SerializedName("id") + private String id; + @SerializedName("pid") + private String pid; + @SerializedName("landType") + private String landType; + @SerializedName("children") + private List children; + + public LandTypeEntity() { + } + + public LandTypeEntity(String name) { + this.id = ""; + this.landType = name; + this.children = new ArrayList<>(); + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getPid() { + return pid; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public String getLandType() { + return landType; + } + + public void setLandType(String landType) { + this.landType = landType; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } + + @Override + public String getPickerViewText() { + return landType; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/ProductionTrendAnalysisEntity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/ProductionTrendAnalysisEntity.java new file mode 100644 index 0000000..0ea5bd9 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/entity/ProductionTrendAnalysisEntity.java @@ -0,0 +1,62 @@ +package com.tairui.gov_affairs_cloud.ui.land.entity; + +import java.util.List; + +import com.google.gson.annotations.SerializedName; + +public class ProductionTrendAnalysisEntity { + + @SerializedName("cropId") + private String cropId; + @SerializedName("cropName") + private String cropName; + @SerializedName("yearTrends") + private List yearTrends; + + public String getCropId() { + return cropId; + } + + public void setCropId(String cropId) { + this.cropId = cropId; + } + + public String getCropName() { + return cropName; + } + + public void setCropName(String cropName) { + this.cropName = cropName; + } + + public List getYearTrends() { + return yearTrends; + } + + public void setYearTrends(List yearTrends) { + this.yearTrends = yearTrends; + } + + public static class YearTrendsEntity { + @SerializedName("year") + private String year; + @SerializedName("value") + private Double value; + + public String getYear() { + return year; + } + + public void setYear(String year) { + this.year = year; + } + + public Double getValue() { + return value; + } + + public void setValue(Double value) { + this.value = value; + } + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/fragment/LandResourceInfoItemFragment.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/fragment/LandResourceInfoItemFragment.java new file mode 100644 index 0000000..e3cee34 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/land/fragment/LandResourceInfoItemFragment.java @@ -0,0 +1,196 @@ +package com.tairui.gov_affairs_cloud.ui.land.fragment; + +import java.io.Serializable; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.rxjava.rxlife.RxLife; +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.base.BaseFragment; +import com.tairui.gov_affairs_cloud.databinding.FragmentLandResourceInfoBinding; +import com.tairui.gov_affairs_cloud.entity.Api; +import com.tairui.gov_affairs_cloud.entity.EventConstant; +import com.tairui.gov_affairs_cloud.entity.EventMessage; +import com.tairui.gov_affairs_cloud.http.OnError; +import com.tairui.gov_affairs_cloud.ui.land.LandInfoDetailActivity; +import com.tairui.gov_affairs_cloud.ui.land.entity.LandResourceEntity; +import com.tairui.gov_affairs_cloud.util.AppUtil; +import com.tairui.gov_affairs_cloud.util.ArrayUtil; +import com.tairui.gov_affairs_cloud.util.IntentUtil; +import com.tairui.gov_affairs_cloud.util.ToastUtil; +import com.tairui.gov_affairs_cloud.util.glide.GlideLoader; +import com.tairui.gov_affairs_cloud.widget.RefreshRecyclerView; + +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; +import rxhttp.RxHttp; +import rxhttp.RxHttpNoBodyParam; + +public class LandResourceInfoItemFragment extends BaseFragment { + + private LandResourceInfoAdapter adapter; + private int currentPageIndex = 1; + + private String landTypeId = ""; + private String regionCode = ""; + private String searchWord = ""; + + public static LandResourceInfoItemFragment newInstance(String _landTypeId) { + LandResourceInfoItemFragment fragment = new LandResourceInfoItemFragment(); + Bundle args = new Bundle(); + args.putString("landTypeId", _landTypeId); + fragment.setArguments(args); + return fragment; + } + + @Override + protected Class getBindingClass() { + return FragmentLandResourceInfoBinding.class; + } + + @Override + public void onDestroyView() { + EventBus.getDefault().unregister(this); + super.onDestroyView(); + } + + @Override + protected void onQueryArguments() { + landTypeId = getArguments().getString("landTypeId"); + EventBus.getDefault().register(this); + } + + @Subscribe(threadMode = ThreadMode.MAIN) + public void onMessageReceive(EventMessage message) { + if (null != message && !TextUtils.isEmpty(message.getLabel())) { + if (EventConstant.REFRESH_LIST.equals(message.getLabel())) { + regionCode = (String) message.getData(); + binding.refreshRecycler.showLoading(); + currentPageIndex = 1; + requestData(false); + } else if (EventConstant.SEARCH_LIST.equals(message.getLabel())) { + searchWord = (String) message.getData(); + binding.refreshRecycler.showLoading(); + currentPageIndex = 1; + requestData(false); + } + } + } + + @Override + protected void onFindView(View rootView) { + binding.refreshRecycler.setLayoutManager(new LinearLayoutManager(mContext)); + adapter = new LandResourceInfoAdapter(); + binding.refreshRecycler.setAdapter(adapter); + } + + @Override + protected void onBindListener() { + binding.refreshRecycler.setRefreshRecyclerListener(new RefreshRecyclerView.RefreshRecyclerListener() { + @Override + public void onRefresh() { + currentPageIndex = 1; + requestData(false); + } + + @Override + public void onLoadmore() { + requestData(true); + } + + @Override + public void onBlankClick() { + binding.refreshRecycler.showLoading(); + currentPageIndex = 1; + requestData(false); + } + }); + adapter.setOnItemClickListener((baseQuickAdapter, view, i) -> { + Bundle bundle = new Bundle(); + bundle.putSerializable("data", (Serializable) adapter.getItem(i)); + IntentUtil.startActivity(mContext, LandInfoDetailActivity.class, bundle); + }); + } + + @Override + protected void onApplyData() { + binding.refreshRecycler.showLoading(); + currentPageIndex = 1; + requestData(false); + } + + private void requestData(boolean loadmore) { + RxHttpNoBodyParam http = RxHttp.get(Api.LAND_RESOURCE_LIST); + if (!TextUtils.isEmpty(regionCode)) { + http.add("regionCode", regionCode); + } + if (!TextUtils.isEmpty(searchWord)) { + http.add("landName", searchWord); + } + http.add("landType", landTypeId) + .add("current", currentPageIndex) + .add("size", Api.SIZE_PAGE) + .asResponse(LandResourceEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + if (loadmore) { + binding.refreshRecycler.finishLoadMore(); + } + if (!ArrayUtil.isEmpty(data.getRecords())) { + if (loadmore) { + adapter.addData(data.getRecords()); + } else { + adapter.setNewData(data.getRecords()); + } + currentPageIndex += 1; + if (ArrayUtil.size(data.getRecords()) < Api.SIZE_PAGE) { + binding.refreshRecycler.setNoMoreData(true); + } else { + binding.refreshRecycler.setNoMoreData(false); + } + binding.refreshRecycler.showContent(); + } else { + binding.refreshRecycler.showError(); + binding.refreshRecycler.setNoMoreData(true); + } + }, (OnError) error -> { + binding.refreshRecycler.showError(); + binding.refreshRecycler.setNoMoreData(true); + ToastUtil.showLongToast(error.getErrorMsg()); + }); + } + + private class LandResourceInfoAdapter extends BaseQuickAdapter { + + public LandResourceInfoAdapter() { + super(R.layout.item_land_resource_info); + } + + @Override + protected void convert(@NonNull BaseViewHolder holder, LandResourceEntity.RecordsEntity entity) { + holder.setText(R.id.tvName, entity.getLandName()); + if (!TextUtils.isEmpty(entity.getLandUrl())) { + ImageView img = holder.getView(R.id.img); + if (entity.getLandUrl().startsWith("http")) { + GlideLoader.loadOriginal(img, entity.getLandUrl()); + } else { + GlideLoader.loadOriginal(img, AppUtil.getImageUrl(entity.getLandUrl())); + } + } + holder.setText(R.id.tvType, entity.getLandTypeName()); + holder.setText(R.id.tvAddress, entity.getDetailAddress()); + holder.setText(R.id.tvArea, entity.getArea().toString() + "亩"); + holder.setText(R.id.copyrightOwner, entity.getPropertyName() + " " + entity.getPropertyPhone()); + holder.setText(R.id.copyrightCode, entity.getLandCode()); + + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/login/LoginActivity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/login/LoginActivity.java new file mode 100644 index 0000000..3ea648f --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/login/LoginActivity.java @@ -0,0 +1,111 @@ +package com.tairui.gov_affairs_cloud.ui.login; + +import com.google.gson.JsonObject; +import com.orhanobut.hawk.Hawk; +import com.rxjava.rxlife.RxLife; +import com.tairui.gov_affairs_cloud.base.BaseActivity; +import com.tairui.gov_affairs_cloud.databinding.ActivityLoginBinding; +import com.tairui.gov_affairs_cloud.entity.Api; +import com.tairui.gov_affairs_cloud.entity.Constant; +import com.tairui.gov_affairs_cloud.http.OnError; +import com.tairui.gov_affairs_cloud.ui.MainActivity; +import com.tairui.gov_affairs_cloud.util.IntentUtil; +import com.tairui.gov_affairs_cloud.util.SingleClickListener; + +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import rxhttp.RxHttp; + +public class LoginActivity extends BaseActivity { + + @Override + protected Class getBindingClass() { + return ActivityLoginBinding.class; + } + + @Override + protected void onFindView(Bundle savedInstanceState) { + // GlideLoader.loadOriginal(binding.ivVerifyCode, Api.CAPTCHA, -1); + if (Hawk.contains(Constant.LOGIN_USER_NAME)) { + setText(binding.inputUserName, Hawk.get(Constant.LOGIN_USER_NAME)); + } + } + + @Override + protected void onBindListener() { + binding.ivVerifyCode.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + getCaptcha(); + } + }); + binding.btnLogin.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + checkLogin(); + } + }); + } + + @Override + protected void onApplyData() { +// getCaptcha(); + } + + private void getCaptcha() { + RxHttp.get(Api.CAPTCHA) + .asBitmap() + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + binding.ivVerifyCode.setImageBitmap(data); + }, (OnError) error -> { + }); + } + + private void checkLogin() { + boolean agree = binding.agree.isChecked(); + String username = binding.inputUserName.getText().toString().trim(); + if (TextUtils.isEmpty(username)) { + showToast("用户名不能为空"); + return; + } + String userpass = binding.inputUserPass.getText().toString().trim(); + if (TextUtils.isEmpty(userpass)) { + showToast("密码不能为空"); + return; + } + String verifyCode = binding.inputVerifyCode.getText().toString().trim(); + // if (TextUtils.isEmpty(verifyCode)) { + // showToast("验证码不能为空"); + // return; + // } + if (!agree) { + showToast("请先阅读并同意《用户协议》和《隐私条款》"); + return; + } + showLoading(); + doLogin(username, userpass, verifyCode); + } + + private void doLogin(final String username, String userpass, String verifyCode) { + RxHttp.postJson(Api.LOGIN) + .add("username", username) + .add("password", userpass) + .add("platform", 1) + // .add("code", verifyCode) + .asResponse(JsonObject.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + hideLoading(); + String access_token = data.get("access_token").getAsString(); + Hawk.put(Constant.TOKEN, access_token); + Hawk.put(Constant.LOGIN_USER_NAME, username); + IntentUtil.startActivity(mContext, MainActivity.class, null); + finish(); + }, (OnError) error -> { + hideLoading(); + showToast(error.getErrorMsg()); + }); + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/my/MyFragment.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/my/MyFragment.java new file mode 100644 index 0000000..ffa1cb8 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/my/MyFragment.java @@ -0,0 +1,69 @@ +package com.tairui.gov_affairs_cloud.ui.my; + +import com.kongzue.dialogx.dialogs.MessageDialog; +import com.orhanobut.hawk.Hawk; +import com.rxjava.rxlife.RxLife; +import com.tairui.gov_affairs_cloud.base.BaseFragment; +import com.tairui.gov_affairs_cloud.databinding.FragmentMyBinding; +import com.tairui.gov_affairs_cloud.entity.Api; +import com.tairui.gov_affairs_cloud.http.OnError; +import com.tairui.gov_affairs_cloud.ui.login.LoginActivity; +import com.tairui.gov_affairs_cloud.ui.my.entity.UserInfoEntity; +import com.tairui.gov_affairs_cloud.util.IntentUtil; +import com.tairui.gov_affairs_cloud.util.SingleClickListener; +import com.tairui.gov_affairs_cloud.util.glide.GlideLoader; + +import android.os.Bundle; +import android.view.View; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import rxhttp.RxHttp; + +public class MyFragment extends BaseFragment { + + @Override + protected Class getBindingClass() { + return FragmentMyBinding.class; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + } + + @Override + protected void onBindListener() { + binding.btnLogout.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + MessageDialog.show("安全退出", "确定要退出登录吗?", "确定", "取消") + .setOkButton((baseDialog, v1) -> { + Hawk.put("token",""); + IntentUtil.startActivity(mContext, LoginActivity.class, null); + getActivity().finish(); + return false; + }); + } + }); + } + + @Override + protected void onApplyData() { + RxHttp.get(Api.USER_INFO) + .asResponse(UserInfoEntity.class) + .as(RxLife.asOnMain(this)) + .subscribe(data -> { + initView(data); + }, (OnError) error -> { + showToast(error.getErrorMsg()); + }); + } + + private void initView(UserInfoEntity data) { + setText(binding.tvTodoCount, data.getTodoCount().toString()); + setText(binding.userNameTv, data.getUsername()); + setText(binding.userDepartmentTv, data.getOrganization() + " - " + data.getDepartmental()); + setText(binding.userTelTv, data.getPhone() + " " + data.getNo()); + GlideLoader.loadCircle(binding.userHeadIv, data.getHeadPic()); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/my/entity/UserInfoEntity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/my/entity/UserInfoEntity.java new file mode 100644 index 0000000..1878ed1 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/my/entity/UserInfoEntity.java @@ -0,0 +1,99 @@ +package com.tairui.gov_affairs_cloud.ui.my.entity; + +import java.io.Serializable; + +import com.google.gson.annotations.SerializedName; + +public class UserInfoEntity implements Serializable { + + @SerializedName("username") + private String username; + @SerializedName("organization") + private Object organization; + @SerializedName("departmental") + private String departmental; + @SerializedName("phone") + private String phone; + @SerializedName("headPic") + private String headPic; + @SerializedName("no") + private String no; + @SerializedName("sex") + private String sex; + @SerializedName("email") + private String email; + @SerializedName("todoCount") + private Integer todoCount; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public Object getOrganization() { + return organization; + } + + public void setOrganization(Object organization) { + this.organization = organization; + } + + public String getDepartmental() { + return departmental; + } + + public void setDepartmental(String departmental) { + this.departmental = departmental; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getHeadPic() { + return headPic; + } + + public void setHeadPic(String headPic) { + this.headPic = headPic; + } + + public String getNo() { + return no; + } + + public void setNo(String no) { + this.no = no; + } + + public String getSex() { + return sex; + } + + public void setSex(String sex) { + this.sex = sex; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Integer getTodoCount() { + return todoCount; + } + + public void setTodoCount(Integer todoCount) { + this.todoCount = todoCount; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/photoview/PhotoViewActivty.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/photoview/PhotoViewActivty.java new file mode 100644 index 0000000..394bbd4 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/photoview/PhotoViewActivty.java @@ -0,0 +1,106 @@ +package com.tairui.gov_affairs_cloud.ui.photoview; + +import java.util.List; + +import com.bumptech.glide.Glide; +import com.gyf.immersionbar.ImmersionBar; +import com.lxj.xpopup.photoview.PhotoView; +import com.tairui.gov_affairs_cloud.base.BaseActivity; +import com.tairui.gov_affairs_cloud.databinding.ActivityPhotoViewBinding; +import com.tairui.gov_affairs_cloud.util.SingleClickListener; + +import android.os.Bundle; +import android.view.View; +import android.view.ViewGroup; +import androidx.viewpager.widget.PagerAdapter; +import androidx.viewpager.widget.ViewPager; + +public class PhotoViewActivty extends BaseActivity { + + private List imgs; + private int index = -1; + + @Override + protected Class getBindingClass() { + return ActivityPhotoViewBinding.class; + } + + + @Override + protected void initStatusBar() { + ImmersionBar.with(this).fitsSystemWindows(false).transparentStatusBar() + .statusBarDarkFont(false).init(); + } + + @Override + protected void onQueryArguments() { + index = getIntent().getIntExtra("index", -1); + imgs = getIntent().getStringArrayListExtra("imgs"); + } + + @Override + protected void onFindView(Bundle savedInstanceState) { + binding.viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + + } + + @Override + public void onPageSelected(int position) { + binding.page.setText((position + 1) + "/" + imgs.size()); + } + + @Override + public void onPageScrollStateChanged(int state) { + + } + }); + binding.viewPager.setIsCanScroll(true); + binding.viewPager.setAdapter(new SamplePagerAdapter()); + if (index != -1) { + binding.viewPager.setCurrentItem(index); + binding.page.setText((index + 1) + "/" + imgs.size()); + } + } + + @Override + protected void onBindListener() { + binding.back.setOnClickListener(new SingleClickListener() { + @Override + protected void onSingleClick(View v) { + onBackPressed(); + } + }); + } + + private class SamplePagerAdapter extends PagerAdapter { + + @Override + public int getCount() { + return imgs.size(); + } + + @Override + public View instantiateItem(ViewGroup container, int position) { + PhotoView photoView = new PhotoView(container.getContext()); + String url = imgs.get(position); + Glide.with(PhotoViewActivty.this).load(url).into(photoView); + photoView.setOnClickListener(view -> finish()); + // Now just add PhotoView to ViewPager and return it + container.addView(photoView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + return photoView; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + container.removeView((View) object); + } + + @Override + public boolean isViewFromObject(View view, Object object) { + return view == object; + } + + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/todo/TodoFragment.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/todo/TodoFragment.java new file mode 100644 index 0000000..50a8b4a --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/todo/TodoFragment.java @@ -0,0 +1,23 @@ +package com.tairui.gov_affairs_cloud.ui.todo; + +import com.tairui.gov_affairs_cloud.base.BaseFragment; +import com.tairui.gov_affairs_cloud.databinding.FragmentTodoBinding; + +import android.os.Bundle; +import android.view.View; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +public class TodoFragment extends BaseFragment { + + @Override + protected Class getBindingClass() { + return FragmentTodoBinding.class; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/workspace/WorkSpaceFragment.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/workspace/WorkSpaceFragment.java new file mode 100644 index 0000000..1e83143 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/workspace/WorkSpaceFragment.java @@ -0,0 +1,287 @@ +package com.tairui.gov_affairs_cloud.ui.workspace; + +import java.util.ArrayList; +import java.util.List; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.BaseViewHolder; +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.base.BaseFragment; +import com.tairui.gov_affairs_cloud.databinding.FragmentWorkspaceBinding; +import com.tairui.gov_affairs_cloud.ui.grid.GridInfoActivity; +import com.tairui.gov_affairs_cloud.ui.land.LandActivity; +import com.tairui.gov_affairs_cloud.ui.land.LandResouceInfoActivity; +import com.tairui.gov_affairs_cloud.ui.workspace.entity.WorkSpaceEntity; +import com.tairui.gov_affairs_cloud.util.IntentUtil; + +import android.view.View; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +public class WorkSpaceFragment extends BaseFragment { + + private WorkSpaceAdapter workSpaceAdapter; + + @Override + protected Class getBindingClass() { + return FragmentWorkspaceBinding.class; + } + + @Override + protected void onFindView(View rootView) { + binding.recycleView.setLayoutManager(new LinearLayoutManager(mContext)); + workSpaceAdapter = new WorkSpaceAdapter(); + binding.recycleView.setAdapter(workSpaceAdapter); + } + + @Override + protected void onApplyData() { + List data = mockData(); + workSpaceAdapter.setNewData(data); + } + + private class WorkSpaceAdapter extends BaseQuickAdapter { + + public WorkSpaceAdapter() { + super(R.layout.item_workspace_layout); + } + + @Override + protected void convert(@NonNull BaseViewHolder holder, WorkSpaceEntity entity) { + holder.setText(R.id.tvTitle, entity.getName()); + RecyclerView itemRecycler = holder.getView(R.id.itemRecycleView); + itemRecycler.setLayoutManager(new GridLayoutManager(mContext, 4)); + FuncAdapter funcAdapter = new FuncAdapter(); + funcAdapter.setNewData(entity.getFuncs()); + itemRecycler.setAdapter(funcAdapter); + + funcAdapter.setOnItemClickListener((baseQuickAdapter, view, i) -> { + WorkSpaceEntity.FuncsEntity itemEntity = entity.getFuncs().get(i); + int _id = itemEntity.getId(); + if (_id == 1) { + IntentUtil.startActivity(mContext, LandActivity.class); + }else if (_id == 2) { + IntentUtil.startActivity(mContext, GridInfoActivity.class); + }else if (_id == 6) { + IntentUtil.startActivity(mContext, LandResouceInfoActivity.class); + } + }); + } + } + + private class FuncAdapter extends BaseQuickAdapter { + + public FuncAdapter() { + super(R.layout.item_workspace_item_layout); + } + + @Override + protected void convert(@NonNull BaseViewHolder holder, WorkSpaceEntity.FuncsEntity entity) { + holder.setText(R.id.funcTv, entity.getName()); + holder.setImageResource(R.id.funcIv, entity.getIcon()); + } + } + + private List mockData() { + List workSpaceEntities = new ArrayList<>(); + WorkSpaceEntity item = new WorkSpaceEntity(); + item.setName("土地资源管理"); + List funcs = new ArrayList<>(); + WorkSpaceEntity.FuncsEntity itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(1); + itemFunc.setName("土地概况"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_1); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(2); + itemFunc.setName("网格信息"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_2); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(3); + itemFunc.setName("种植计划"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_3); + funcs.add(itemFunc); + +// itemFunc = new WorkSpaceEntity.FuncsEntity(); +// itemFunc.setId(4); +// itemFunc.setName("农事作业"); +// itemFunc.setIcon(R.mipmap.ic_workspace_func_4); +// funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(5); + itemFunc.setName("土地违规"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_5); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(6); + itemFunc.setName("土地信息"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_6); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(7); + itemFunc.setName("土地巡查"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_7); + funcs.add(itemFunc); + + item.setFuncs(funcs); + workSpaceEntities.add(item); + + item = new WorkSpaceEntity(); + item.setName("投入品管理"); + funcs = new ArrayList<>(); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(9); + itemFunc.setName("信息管理"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_9); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(10); + itemFunc.setName("生产抽检"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_10); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(11); + itemFunc.setName("使用监管"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_11); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(12); + itemFunc.setName("农机租赁"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_12); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(13); + itemFunc.setName("排行榜"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_13); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(14); + itemFunc.setName("知识库"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_14); + funcs.add(itemFunc); + + item.setFuncs(funcs); + workSpaceEntities.add(item); + + item = new WorkSpaceEntity(); + item.setName("生产经营主体管理"); + funcs = new ArrayList<>(); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(15); + itemFunc.setName("农企合作社"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_15); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(16); + itemFunc.setName("农资企业"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_16); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(17); + itemFunc.setName("生产加工"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_17); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(18); + itemFunc.setName("种源企业"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_18); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(19); + itemFunc.setName("农户管理"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_19); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(20); + itemFunc.setName("金融监管"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_20); + funcs.add(itemFunc); + + item.setFuncs(funcs); + workSpaceEntities.add(item); + + item = new WorkSpaceEntity(); + item.setName("农产品全程追溯管理"); + funcs = new ArrayList<>(); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(21); + itemFunc.setName("运营监督"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_21); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(22); + itemFunc.setName("溯源管理"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_22); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(23); + itemFunc.setName("溯源查询"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_23); + funcs.add(itemFunc); + + item.setFuncs(funcs); + workSpaceEntities.add(item); + + item = new WorkSpaceEntity(); + item.setName("农业产品检测"); + funcs = new ArrayList<>(); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(24); + itemFunc.setName("田间监测"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_24); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(25); + itemFunc.setName("水质监测"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_25); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(26); + itemFunc.setName("病虫害检测"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_26); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(27); + itemFunc.setName("环境监测"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_27); + funcs.add(itemFunc); + + itemFunc = new WorkSpaceEntity.FuncsEntity(); + itemFunc.setId(28); + itemFunc.setName("产量预测"); + itemFunc.setIcon(R.mipmap.ic_workspace_func_28); + funcs.add(itemFunc); + + item.setFuncs(funcs); + workSpaceEntities.add(item); + + return workSpaceEntities; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/ui/workspace/entity/WorkSpaceEntity.java b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/workspace/entity/WorkSpaceEntity.java new file mode 100644 index 0000000..5960b11 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/ui/workspace/entity/WorkSpaceEntity.java @@ -0,0 +1,62 @@ +package com.tairui.gov_affairs_cloud.ui.workspace.entity; + +import java.util.List; + +import com.google.gson.annotations.SerializedName; + +public class WorkSpaceEntity { + + @SerializedName("name") + private String name; + @SerializedName("funcs") + private List funcs; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getFuncs() { + return funcs; + } + + public void setFuncs(List funcs) { + this.funcs = funcs; + } + + public static class FuncsEntity { + @SerializedName("id") + private Integer id; + @SerializedName("name") + private String name; + @SerializedName("icon") + private int icon; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getIcon() { + return icon; + } + + public void setIcon(int icon) { + this.icon = icon; + } + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/AppUtil.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/AppUtil.java new file mode 100644 index 0000000..add6297 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/AppUtil.java @@ -0,0 +1,40 @@ +package com.tairui.gov_affairs_cloud.util; + +import java.util.ArrayList; + +import com.tairui.gov_affairs_cloud.entity.Api; +import com.tairui.gov_affairs_cloud.ui.photoview.PhotoViewActivty; +import com.tairui.gov_affairs_cloud.widget.loading.LoadingDialog; + +import android.content.Context; +import android.os.Bundle; + +public class AppUtil { + + public static LoadingDialog getLoading(Context context) { + return getLoading(context, 1); + } + + public static LoadingDialog getLoading(Context context, int style) { + if (null != context) { + LoadingDialog loading = new LoadingDialog(context); + loading.setLoadStyle(style); //STYLE_RING = 0; STYLE_LINE = 1; + loading.setLoadingText(null); + loading.setInterceptBack(false); + return loading; + } else { + return null; + } + } + + public static String getImageUrl(String url) { + return Api.OSS_HOST.concat(url); + } + + public static void startPhotoView(Context context, ArrayList imgs){ + Bundle bundle = new Bundle(); + bundle.putInt("index", 0); + bundle.putStringArrayList("imgs", imgs); + IntentUtil.startActivity(context, PhotoViewActivty.class, bundle); + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/ArrayUtil.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/ArrayUtil.java new file mode 100644 index 0000000..b4b1d79 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/ArrayUtil.java @@ -0,0 +1,33 @@ +package com.tairui.gov_affairs_cloud.util; + +import java.util.Collection; +import java.util.Map; + +public class ArrayUtil { + + public static int size(Collection data) { + return data == null ? 0 : data.size(); + } + + public static boolean isEmpty(Collection data) { + return data == null || data.isEmpty(); + } + + public static boolean notNull(Collection data) { + return !isEmpty(data); + } + + + public static int size(Map data) { + return data == null ? 0 : data.size(); + } + + public static boolean isEmpty(Map data) { + return data == null || data.isEmpty(); + } + + public static boolean notNull(Map data) { + return !isEmpty(data); + } + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/Base64CoderUtils.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/Base64CoderUtils.java new file mode 100644 index 0000000..c58c7f2 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/Base64CoderUtils.java @@ -0,0 +1,282 @@ +package com.tairui.gov_affairs_cloud.util; + +/** + * A Base64 encoder/decoder. + * Base64 的工具类 + */ + +public class Base64CoderUtils { + + // The line separator string of the operating system. + private static final String systemLineSeparator = System + .getProperty("line.separator"); + + // Mapping table from 6-bit nibbles to Base64 characters. + private static char[] map1 = new char[64]; + static { + int i = 0; + for (char c = 'A'; c <= 'Z'; c++) + map1[i++] = c; + for (char c = 'a'; c <= 'z'; c++) + map1[i++] = c; + for (char c = '0'; c <= '9'; c++) + map1[i++] = c; + map1[i++] = '+'; + map1[i++] = '/'; + } + + // Mapping table from Base64 characters to 6-bit nibbles. + private static byte[] map2 = new byte[128]; + static { + for (int i = 0; i < map2.length; i++) + map2[i] = -1; + for (int i = 0; i < 64; i++) + map2[map1[i]] = (byte) i; + } + + /** + * 将一个字符串转为Base64 + */ + public static String encodeString(String s) { + return new String(encode(s.getBytes())); + } + + /** + * Encodes a byte array into Base 64 format and breaks the output into lines + * of 76 characters. This method is compatible with + * sun.misc.BASE64Encoder.encodeBuffer(byte[]). + * + * @param in + * An array containing the data bytes to be encoded. + * @return A String containing the Base64 encoded data, broken into lines. + */ + public static String encodeLines(byte[] in) { + return encodeLines(in, 0, in.length, 76, systemLineSeparator); + } + + /** + * Encodes a byte array into Base 64 format and breaks the output into + * lines. + * + * @param in + * An array containing the data bytes to be encoded. + * @param iOff + * Offset of the first byte in in to be processed. + * @param iLen + * Number of bytes to be processed in in, starting + * at iOff. + * @param lineLen + * Line length for the output data. Should be a multiple of 4. + * @param lineSeparator + * The line separator to be used to separate the output lines. + * @return A String containing the Base64 encoded data, broken into lines. + */ + public static String encodeLines(byte[] in, int iOff, int iLen, + int lineLen, String lineSeparator) { + int blockLen = (lineLen * 3) / 4; + if (blockLen <= 0) + throw new IllegalArgumentException(); + int lines = (iLen + blockLen - 1) / blockLen; + int bufLen = ((iLen + 2) / 3) * 4 + lines * lineSeparator.length(); + StringBuilder buf = new StringBuilder(bufLen); + int ip = 0; + while (ip < iLen) { + int l = Math.min(iLen - ip, blockLen); + buf.append(encode(in, iOff + ip, l)); + buf.append(lineSeparator); + ip += l; + } + return buf.toString(); + } + + /** + * Encodes a byte array into Base64 format. No blanks or line breaks are + * inserted in the output. + * + * @param in + * An array containing the data bytes to be encoded. + * @return A character array containing the Base64 encoded data. + */ + public static char[] encode(byte[] in) { + return encode(in, 0, in.length); + } + + /** + * Encodes a byte array into Base64 format. No blanks or line breaks are + * inserted in the output. + * + * @param in + * An array containing the data bytes to be encoded. + * @param iLen + * Number of bytes to process in in. + * @return A character array containing the Base64 encoded data. + */ + public static char[] encode(byte[] in, int iLen) { + return encode(in, 0, iLen); + } + + /** + * Encodes a byte array into Base64 format. No blanks or line breaks are + * inserted in the output. + * + * @param in + * An array containing the data bytes to be encoded. + * @param iOff + * Offset of the first byte in in to be processed. + * @param iLen + * Number of bytes to process in in, starting at + * iOff. + * @return A character array containing the Base64 encoded data. + */ + public static char[] encode(byte[] in, int iOff, int iLen) { + int oDataLen = (iLen * 4 + 2) / 3; // output length without padding + int oLen = ((iLen + 2) / 3) * 4; // output length including padding + char[] out = new char[oLen]; + int ip = iOff; + int iEnd = iOff + iLen; + int op = 0; + while (ip < iEnd) { + int i0 = in[ip++] & 0xff; + int i1 = ip < iEnd ? in[ip++] & 0xff : 0; + int i2 = ip < iEnd ? in[ip++] & 0xff : 0; + int o0 = i0 >>> 2; + int o1 = ((i0 & 3) << 4) | (i1 >>> 4); + int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6); + int o3 = i2 & 0x3F; + out[op++] = map1[o0]; + out[op++] = map1[o1]; + out[op] = op < oDataLen ? map1[o2] : '='; + op++; + out[op] = op < oDataLen ? map1[o3] : '='; + op++; + } + return out; + } + + /** + * Decodes a string from Base64 format. No blanks or line breaks are allowed + * within the Base64 encoded input data. + * + * @param s + * A Base64 String to be decoded. + * @return A String containing the decoded data. + * @throws IllegalArgumentException + * If the input is not valid Base64 encoded data. + */ + public static String decodeString(String s) { + return new String(decode(s)); + } + + /** + * Decodes a byte array from Base64 format and ignores line separators, tabs + * and blanks. CR, LF, Tab and Space characters are ignored in the input + * data. This method is compatible with + * sun.misc.BASE64Decoder.decodeBuffer(String). + * + * @param s + * A Base64 String to be decoded. + * @return An array containing the decoded data bytes. + * @throws IllegalArgumentException + * If the input is not valid Base64 encoded data. + */ + public static byte[] decodeLines(String s) { + char[] buf = new char[s.length() + 3]; + int p = 0; + for (int ip = 0; ip < s.length(); ip++) { + char c = s.charAt(ip); + if (c != ' ' && c != '\r' && c != '\n' && c != '\t') + buf[p++] = c; + } + while ((p % 4) != 0) + buf[p++] = '0'; + + return decode(buf, 0, p); + } + + /** + * Decodes a byte array from Base64 format. No blanks or line breaks are + * allowed within the Base64 encoded input data. + * + * @param s + * A Base64 String to be decoded. + * @return An array containing the decoded data bytes. + * @throws IllegalArgumentException + * If the input is not valid Base64 encoded data. + */ + public static byte[] decode(String s) { + return decode(s.toCharArray()); + } + + /** + * Decodes a byte array from Base64 format. No blanks or line breaks are + * allowed within the Base64 encoded input data. + * + * @param in + * A character array containing the Base64 encoded data. + * @return An array containing the decoded data bytes. + * @throws IllegalArgumentException + * If the input is not valid Base64 encoded data. + */ + public static byte[] decode(char[] in) { + return decode(in, 0, in.length); + } + + /** + * Decodes a byte array from Base64 format. No blanks or line breaks are + * allowed within the Base64 encoded input data. + * + * @param in + * A character array containing the Base64 encoded data. + * @param iOff + * Offset of the first character in in to be + * processed. + * @param iLen + * Number of characters to process in in, starting + * at iOff. + * @return An array containing the decoded data bytes. + * @throws IllegalArgumentException + * If the input is not valid Base64 encoded data. + */ + public static byte[] decode(char[] in, int iOff, int iLen) { + if (iLen % 4 != 0) + throw new IllegalArgumentException( + "Length of Base64 encoded input string is not a multiple of 4."); + while (iLen > 0 && in[iOff + iLen - 1] == '=') + iLen--; + int oLen = (iLen * 3) / 4; + byte[] out = new byte[oLen]; + int ip = iOff; + int iEnd = iOff + iLen; + int op = 0; + while (ip < iEnd) { + int i0 = in[ip++]; + int i1 = in[ip++]; + int i2 = ip < iEnd ? in[ip++] : 'A'; + int i3 = ip < iEnd ? in[ip++] : 'A'; + if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127) + throw new IllegalArgumentException( + "Illegal character in Base64 encoded data."); + int b0 = map2[i0]; + int b1 = map2[i1]; + int b2 = map2[i2]; + int b3 = map2[i3]; + if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) + throw new IllegalArgumentException( + "Illegal character in Base64 encoded data."); + int o0 = (b0 << 2) | (b1 >>> 4); + int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2); + int o2 = ((b2 & 3) << 6) | b3; + out[op++] = (byte) o0; + if (op < oLen) + out[op++] = (byte) o1; + if (op < oLen) + out[op++] = (byte) o2; + } + return out; + } + + // Dummy constructor. + private Base64CoderUtils() { + } + +} // end class Base64Coder \ No newline at end of file diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/CrashHandler.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/CrashHandler.java new file mode 100644 index 0000000..1c52f6a --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/CrashHandler.java @@ -0,0 +1,178 @@ +package com.tairui.gov_affairs_cloud.util; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Field; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Looper; +import android.util.Log; + +public class CrashHandler implements Thread.UncaughtExceptionHandler { + private static CrashHandler crashHandler; + private static SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmmss"); + private static Date curDate = new Date(System.currentTimeMillis());//获取当前时间 + private static String str = formatter.format(curDate); + private static String TAG = "MyCrashHandler"; + //系统默认的UncaughtException处理类 + private Thread.UncaughtExceptionHandler mDefaultHandler; + //程序的Context对象 + private Context mContext; + //用来存储设备信息和异常信息 + private Map infos = new HashMap(); + + @Override + public void uncaughtException(Thread thread, Throwable ex) { + + if (!handleException(ex) && mDefaultHandler != null) { + //如果用户没有处理则让系统默认的异常处理器来处理 + mDefaultHandler.uncaughtException(thread, ex); + } else { + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + Log.e(TAG, "error : ", e); + } + //退出程序 + android.os.Process.killProcess(android.os.Process.myPid()); + System.exit(1); + } + } + + /** + * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. + * + * @param ex + * @return true:如果处理了该异常信息;否则返回false. + */ + private boolean handleException(Throwable ex) { + if (ex == null) { + return false; + } + //使用Toast来显示异常信息 + new Thread() { + @Override + public void run() { + Looper.prepare();//准备发消息的MessageQueue + ToastUtil.showLongToast("很抱歉,程序出现异常,即将退出."); + Looper.loop(); + } + }.start(); + //收集设备参数信息 + collectDeviceInfo(mContext); + //保存日志文件 + saveCrashInfo2File(ex); + return true; + } + + /** + * 保存错误信息到文件中 + * + * @param ex + * @return 返回文件名称, 便于将文件传送到服务器 + */ + private String saveCrashInfo2File(Throwable ex) { + + StringBuffer sb = new StringBuffer(); + for (Map.Entry entry : infos.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + sb.append(key + "=" + value + "\n"); + } + + Writer writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + ex.printStackTrace(printWriter); + Throwable cause = ex.getCause(); + while (cause != null) { + cause.printStackTrace(printWriter); + cause = cause.getCause(); + } + printWriter.close(); + String result = writer.toString(); + sb.append(result); + //KpLog.getInstance().onAppCrashed(mContext, sb.toString()); + try { + long timestamp = System.currentTimeMillis(); + String fileName = "crash-" + str + "-" + timestamp + ".txt"; + String path = mContext.getFilesDir() + "/crash"; + File dir = new File(path); + if (!dir.exists()) { + dir.mkdirs(); + } + FileOutputStream fos = new FileOutputStream(path + "/" + fileName); + fos.write(sb.toString().getBytes()); + System.out.println(sb.toString()); + fos.close(); + return fileName; + } catch (Exception e) { + Log.e(TAG, "an error occured while wr iting file...", e); + } + return null; + } + + /** + * 初始化 + * + * @param context + */ + public void init(Context context) { + mContext = context; + //获取系统默认的UncaughtException处理器 + mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); + //设置该CrashHandler为程序的默认处理器 + Thread.setDefaultUncaughtExceptionHandler(this); + } + + /** + * 收集设备参数信息 + * + * @param ctx + */ + public void collectDeviceInfo(Context ctx) { + try { + PackageManager pm = ctx.getPackageManager(); + PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES); + if (pi != null) { + String versionName = pi.versionName == null ? "null" : pi.versionName; + String versionCode = pi.versionCode + ""; + infos.put("versionName", versionName); + infos.put("versionCode", versionCode); + } + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "an error occured when collect package info", e); + } + Field[] fields = Build.class.getDeclaredFields(); + for (Field field : fields) { + try { + field.setAccessible(true); + infos.put(field.getName(), field.get(null).toString()); + Log.d(TAG, field.getName() + " : " + field.get(null)); + } catch (Exception e) { + Log.e(TAG, "an error occured when collect crash info", e); + } + } + } + + private CrashHandler() { + } + + //单例 + public static CrashHandler instance() { + if (crashHandler == null) { + crashHandler = new CrashHandler(); + } + return crashHandler; + } + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/DensityUtils.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/DensityUtils.java new file mode 100644 index 0000000..be28f83 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/DensityUtils.java @@ -0,0 +1,89 @@ +package com.tairui.gov_affairs_cloud.util; + +import android.content.Context; +import android.util.TypedValue; + +/** + * Created by tongchao on 17/5/22. + */ + +public class DensityUtils { + + private DensityUtils() { + /* cannot be instantiated */ + throw new UnsupportedOperationException("cannot be instantiated"); + } + + private static int _SCREEN_WIDTH = 0; + + /** + * 屏幕的宽,像素 + */ + public static int SCREEN_WIDTH(Context context) { + if (_SCREEN_WIDTH == 0) { + _SCREEN_WIDTH = context.getResources().getDisplayMetrics().widthPixels; + } + return _SCREEN_WIDTH; + } + + private static int _SCREEN_HEIGHT = 0; + + /** + * 屏幕的高,像素 + */ + public static int SCREEN_HEIGHT(Context context) { + if (_SCREEN_HEIGHT == 0) { + _SCREEN_HEIGHT = context.getResources().getDisplayMetrics().heightPixels; + } + return _SCREEN_HEIGHT; + } + + /** + * dp转px + * + * @param context + * @return + */ + public static int dp2px(Context context, float dpVal) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, + dpVal, context.getResources().getDisplayMetrics()); + } + + /** + * sp转px + * + * @param context + * @return + */ + public static int sp2px(Context context, float spVal) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, + spVal, context.getResources().getDisplayMetrics()); + } + + /** + * px转dp + * + * @param context + * @param pxVal + * @return + */ + public static float px2dp(Context context, float pxVal) { + final float scale = context.getResources().getDisplayMetrics().density; + return (pxVal / scale); + } + + /** + * px转sp + * + * @return + */ + public static float px2sp(Context context, float pxVal) { + return (pxVal / context.getResources().getDisplayMetrics().scaledDensity); + } + + public static int dp2sp(Context context, float dpVal) { + return (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, + context.getResources().getDisplayMetrics())); + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/FolderUtil.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/FolderUtil.java new file mode 100644 index 0000000..136f4d7 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/FolderUtil.java @@ -0,0 +1,36 @@ +package com.tairui.gov_affairs_cloud.util; + +import android.content.Context; +import android.os.Environment; + +public class FolderUtil { + + public static String getPictureDir(Context context) { + return context.getExternalFilesDir(Environment.DIRECTORY_PICTURES).getAbsolutePath(); + } + + public static String getMovieDir(Context context) { + return context.getExternalFilesDir(Environment.DIRECTORY_MOVIES).getAbsolutePath(); + } + + public static String getMusicDir(Context context) { + return context.getExternalFilesDir(Environment.DIRECTORY_MUSIC).getAbsolutePath(); + } + + public static String getDcimDir(Context context) { + return context.getExternalFilesDir(Environment.DIRECTORY_DCIM).getAbsolutePath(); + } + + public static String getDownloadDir(Context context) { + return context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(); + } + + public static String getDocumentsDir(Context context) { + return context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath(); + } + + public static String getDbDir(Context context) { + return context.getExternalFilesDir("Databases").getAbsolutePath(); + } + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/FontUtil.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/FontUtil.java new file mode 100644 index 0000000..1aa9ebe --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/FontUtil.java @@ -0,0 +1,37 @@ +package com.tairui.gov_affairs_cloud.util; + +import android.graphics.Paint; + +/** + * autour : openXu + * date : 2016/7/24 14:12 + * className : FontUtil + * version : 1.0 + * description : 文字相关处理帮助类(自定义控件专用) + */ +public class FontUtil { + /** + * @param paint + * @param str + * @return 返回指定笔和指定字符串的长度 + */ + public static float getFontlength(Paint paint, String str) { + return paint.measureText(str); + } + /** + * @return 返回指定笔的文字高度 + */ + public static float getFontHeight(Paint paint) { + Paint.FontMetrics fm = paint.getFontMetrics(); + return fm.descent - fm.ascent; + } + /** + * @return 返回指定笔离文字顶部的基准距离 + */ + public static float getFontLeading(Paint paint) { + Paint.FontMetrics fm = paint.getFontMetrics(); + return fm.leading- fm.ascent; + } + + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/IntentUtil.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/IntentUtil.java new file mode 100644 index 0000000..19a0268 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/IntentUtil.java @@ -0,0 +1,72 @@ +package com.tairui.gov_affairs_cloud.util; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +/** + * Intent 跳转的 工具类 + */ + +public class IntentUtil { + + /** + * 跳转到对于的 页面 + * + * @param context 上下午对象 + * @param cls 跳转的 目标Activity + * @param bundle 带的数据 + */ + + public static void startActivity(Context context, Class cls, Bundle bundle) { + if (null != context) { + Intent intent = new Intent(); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setClass(context, cls); + if (null != bundle) { + intent.putExtras(bundle); + } + context.startActivity(intent); + } + + } + + /** + * 跳转到对于的 页面 + * + * @param context 上下午对象 + * @param cls 跳转的 目标Activity + * @param bundle 带的数据 + */ + + public static void gotoActivity(Context context, Class cls, Bundle bundle) { + if (null != context) { + Intent intent = new Intent(); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setClass(context, cls); + if (null != bundle) { + intent.putExtras(bundle); + } + context.startActivity(intent); + } + + } + + /** + * 跳转到对于的 页面 + * + * @param context 上下午对象 + * @param cls 跳转的 目标Activity + */ + + public static void startActivity(Context context, Class cls) { + if (null != context) { + Intent intent = new Intent(); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setClass(context, cls); + context.startActivity(intent); + } + + } + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/KeybordUtil.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/KeybordUtil.java new file mode 100644 index 0000000..356c252 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/KeybordUtil.java @@ -0,0 +1,145 @@ +package com.tairui.gov_affairs_cloud.util; + +import com.tairui.gov_affairs_cloud.GacApplication; + +import android.app.Activity; +import android.content.Context; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.Fragment; + +/** + * 输入法管理类 + */ + +public class KeybordUtil { + + /** + * 获取输入法是否 打开 + * + * @return 输入法的打开状态 + */ + public static boolean isInputMethodActive() { + + Context context = GacApplication.getContext(); + if (null != context) { + InputMethodManager manager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + return manager.isActive(); + } + + return false; + } + + /** + * 关闭 输入法 + */ + public static void closeInputMethod(AppCompatActivity context) { + // + // if (isInputMethodActive()) { + // LogUtil.printD("活跃"); + // InputMethodManager manager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + // if (null != manager) { + // LogUtil.printD("manager 不为空 " + " currentFocus == null ? " + context.getCurrentFocus()); + // if (null != context.getCurrentFocus() && null != context.getCurrentFocus().getWindowToken()) { + // manager.hideSoftInputFromWindow(context.getCurrentFocus().getWindowToken(), InputMethodManager + // .HIDE_NOT_ALWAYS); + // } else { + // LogUtil.printD("不聚焦"); + // } + // } else { + // LogUtil.printD("manager 为空"); + // } + // } else { + // LogUtil.printD("不活跃"); + // } + if (isInputMethodActive()) { + InputMethodManager manager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + if (null != manager) { + if (null != context.getCurrentFocus() && null != context.getCurrentFocus().getWindowToken()) { + manager.hideSoftInputFromWindow(context.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); + } + } + } + } + + public static void hideSoftInput(Fragment fragment) { + View v = fragment.getActivity().getCurrentFocus(); + if (v != null && v.getWindowToken() != null) { + InputMethodManager manager = (InputMethodManager) GacApplication.getContext() + .getSystemService(Context.INPUT_METHOD_SERVICE); + boolean isOpen = manager.isActive(); + if (isOpen) { + manager.hideSoftInputFromWindow(v.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); + } + } + } + + /** + * 弹出软键盘 + * + * @param context + * @param view + */ + public static void showSoftInput(Context context, View view) { + try { + view.requestFocus(); + InputMethodManager imm = (InputMethodManager) context.getApplicationContext() + .getSystemService(Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT); + // imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 隐藏软键盘 + * + * @param context + */ + public static void hideSoftInput(Context context) { + try { + if (context instanceof Activity) { + hideSoftInput(context, (Activity) context); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 隐藏软键盘 + * + * @param context + * @param activity + */ + public static void hideSoftInput(Context context, Activity activity) { + try { + InputMethodManager imm = (InputMethodManager) context.getApplicationContext() + .getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), + InputMethodManager.HIDE_NOT_ALWAYS); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 隐藏软键盘 + * + * @param view + */ + public static void hideSoftInput(Context context, View view) { + if (view == null || context == null) { + return; + } + try { + InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/LogUtil.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/LogUtil.java new file mode 100644 index 0000000..33f38b1 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/LogUtil.java @@ -0,0 +1,76 @@ +package com.tairui.gov_affairs_cloud.util; + +import com.tairui.gov_affairs_cloud.BuildConfig; + +import android.util.Log; + +/** + * autour : openXu + * date : 2017/11/6 11:36 + * className : LogUtil + * version : 1.0 + * description : log日志 + */ +public class LogUtil { + + public static void i(String TAG, Object msg) { + logLong("i", TAG, msg); + } + public static void d(String TAG, Object msg) { + logLong("d", TAG, msg); + } + public static void v(String TAG, Object msg) { + logLong("v", TAG, msg); + } + public static void w(String TAG, Object msg) { + logLong("w", TAG, msg); + } + public static void e(String TAG, Object msg) { + logLong("e", TAG, msg); + } + + /** + * 日志太长打印不全时,分段打印 + * @param type + * @param tag + * @param msg + */ + private static void logLong(String type, String tag, Object msg) { + String content = (null==msg)?"":msg.toString(); + int maxLength = 1000; + long length = content.length(); + if (length <= maxLength) { + logByType(type, tag, content); + }else { + while (content.length() > maxLength) { + String logContent = content.substring(0, maxLength); + content = content.replace(logContent, ""); + logByType(type, tag, logContent); + } + logByType(type, tag, content); + } + } + /**打印不同颜色日志*/ + private static void logByType(String type, String tag, String content){ + if(BuildConfig.DEBUG) { + switch (type){ + case "i": + Log.i(tag, ""+(null==content?"":content)); + break; + case "d": + Log.d(tag, ""+(null==content?"":content)); + break; + case "v": + Log.v(tag, ""+(null==content?"":content)); + break; + case "w": + Log.w(tag, ""+(null==content?"":content)); + break; + case "e": + Log.e(tag, ""+(null==content?"":content)); + break; + } + } + } + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/MyCountDownTimer.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/MyCountDownTimer.java new file mode 100644 index 0000000..095b93e --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/MyCountDownTimer.java @@ -0,0 +1,110 @@ +package com.tairui.gov_affairs_cloud.util; + +import android.annotation.SuppressLint; +import android.os.Handler; +import android.os.Message; +import android.os.SystemClock; + +/** + * 倒计时 + */ + +public abstract class MyCountDownTimer { + + /** + * Millis since epoch when alarm should stop. + */ + private final long mMillisInFuture; + + /** + * The interval in millis that the user receives callbacks + */ + private final long mCountdownInterval; + + private long mStopTimeInFuture; + + /** + * boolean representing if the timer was cancelled + */ + private boolean mCancelled = false; + + /** + * @param millisInFuture The number of millis in the future from the call + * to {@link #start()} until the countdown is done and {@link #onFinish()} + * is called. + * @param countDownInterval The interval along the way to receive + * {@link #onTick(long)} callbacks. + */ + public MyCountDownTimer(long millisInFuture, long countDownInterval) { + mMillisInFuture = millisInFuture; + mCountdownInterval = countDownInterval; + } + + /** + * Cancel the countdown. + */ + public synchronized final void cancel() { + mCancelled = true; + mHandler.removeMessages(MSG); + } + + /** + * Start the countdown. + */ + public synchronized final MyCountDownTimer start() { + mCancelled = false; + if (mMillisInFuture <= 0) { + onFinish(); + return this; + } + mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture; + mHandler.sendMessage(mHandler.obtainMessage(MSG)); + return this; + } + + + /** + * Callback fired on regular interval. + * + * @param millisUntilFinished The amount of time until finished. + */ + public abstract void onTick(long millisUntilFinished); + + /** + * Callback fired when the time is up. + */ + public abstract void onFinish(); + + + private static final int MSG = 1; + + + // handles counting down + @SuppressLint("HandlerLeak") + private Handler mHandler = new Handler() { + + @Override + public void handleMessage(Message msg) { + + synchronized (MyCountDownTimer.this) { + if (mCancelled) { + return; + } + final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime(); +// LogUtil.e("millisLeft = " + millisLeft); + if (millisLeft <= 0) { + onFinish(); + } else { + long lastTickStart = SystemClock.elapsedRealtime(); + onTick(millisLeft); + // take into account user's onTick taking time to execute + long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime(); + // special case: user's onTick took more than interval to + // complete, skip to next interval + while (delay < 0) delay += mCountdownInterval; + sendMessageDelayed(obtainMessage(MSG), delay); + } + } + } + }; +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/NetUtil.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/NetUtil.java new file mode 100644 index 0000000..6f35063 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/NetUtil.java @@ -0,0 +1,89 @@ +package com.tairui.gov_affairs_cloud.util; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +/** + * 网络工具类 + * 判断是否有网络 + * 网络的状态 + */ + +public class NetUtil { + /** + * 判断网络连接状态 + * + * @param context 上下文对象 + * @return 网络是否连接 + */ + public static boolean isNetworkConnected(Context context) { + if (context != null) { + ConnectivityManager connectivityManager = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = connectivityManager + .getActiveNetworkInfo(); + if (networkInfo != null) { + return networkInfo.isAvailable(); + } + } + return false; + } + + /** + * 网络状态是否为 WIFI + * + * @param context 上下文对象 + * @return 是否 WIFI 网络 + */ + public static boolean isWifiConnected(Context context) { + if (context != null) { + ConnectivityManager mConnectivityManager = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo mWiFiNetworkInfo = mConnectivityManager + .getNetworkInfo(ConnectivityManager.TYPE_WIFI); + if (mWiFiNetworkInfo != null) { + return mWiFiNetworkInfo.isAvailable(); + } + } + return false; + } + + /** + * 网络状态是否为数据流量 + * + * @param context 上下文对象 + * @return 是否为数据流量 + */ + public static boolean isMobileConnected(Context context) { + if (context != null) { + ConnectivityManager mConnectivityManager = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo mMobileNetworkInfo = mConnectivityManager + .getNetworkInfo(ConnectivityManager.TYPE_MOBILE); + if (mMobileNetworkInfo != null) { + return mMobileNetworkInfo.isAvailable(); + } + } + return false; + } + + /** + * 获取网络连接类型 + * + * @param context 上下文对象 + * @return 网络连接状态 + */ + public static int getConnectedType(Context context) { + if (context != null) { + ConnectivityManager mConnectivityManager = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo mNetworkInfo = mConnectivityManager + .getActiveNetworkInfo(); + if (mNetworkInfo != null && mNetworkInfo.isAvailable()) { + return mNetworkInfo.getType(); + } + } + return -1; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/PopWindowUtil.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/PopWindowUtil.java new file mode 100644 index 0000000..1e26c66 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/PopWindowUtil.java @@ -0,0 +1,81 @@ +package com.tairui.gov_affairs_cloud.util; + +import com.tairui.gov_affairs_cloud.R; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.os.Build; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.WindowManager; +import android.widget.TextView; + +/** + * 类功能描述: + * 作者: zhongyangxue + * 创建时间: 2020-01-12 17:05 + * 邮箱 1366411749@qq.com + * 版本: 1.0 + */ +public class PopWindowUtil { + + public static final AlertDialog buildNoTitleEnsureDialog(Context context, String content, String cancel, String sure, final EnsureListener listener) { + if (context instanceof Activity) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + if (((Activity) context).isDestroyed()) + return null; + } + } + + final AlertDialog dialog; + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setCancelable(false); + dialog = builder.create(); + + dialog.show(); + View baseView = LayoutInflater.from(context).inflate(R.layout.layout_ensure_notitle_dialog, null); + ((TextView) baseView.findViewById(R.id.dialog_cancel_btn)).setText(cancel); + ((TextView) baseView.findViewById(R.id.dialog_sure_btn)).setText(sure); + if (!TextUtils.isEmpty(content)) { + ((TextView) baseView.findViewById(R.id.dialog_content)).setText(content); + } else { + baseView.findViewById(R.id.dialog_content).setVisibility(View.GONE); + } + baseView.findViewById(R.id.dialog_sure_btn).setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + if (listener != null) + listener.sure(null); + dialog.dismiss(); + } + }); + + baseView.findViewById(R.id.dialog_cancel_btn).setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + if (listener != null) + listener.cancel(); + dialog.dismiss(); + } + }); + WindowManager.LayoutParams lp = dialog.getWindow().getAttributes(); + lp.width = DensityUtils.dp2px(context,320);//定义宽度 + lp.height = WindowManager.LayoutParams.WRAP_CONTENT;//定义高度 + dialog.getWindow().setAttributes(lp); + dialog.setContentView(baseView); + dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + return dialog; + } + + public interface EnsureListener { + void sure(Object obj); + + void cancel(); + } + + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/SingleClickListener.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/SingleClickListener.java new file mode 100644 index 0000000..a1bdec5 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/SingleClickListener.java @@ -0,0 +1,33 @@ +package com.tairui.gov_affairs_cloud.util; + +import android.view.View; + +public abstract class SingleClickListener implements View.OnClickListener { + private long mLastClickTime; + private long timeInterval = 1000L; + + public SingleClickListener() { + + } + + public SingleClickListener(long interval) { + this.timeInterval = interval; + } + + @Override + public void onClick(View v) { + long nowTime = System.currentTimeMillis(); + if (nowTime - mLastClickTime > timeInterval) { + // 单次点击事件 + onSingleClick(v); + mLastClickTime = nowTime; + } else { + // 快速点击事件 + //onFastClick(); + } + } + + protected abstract void onSingleClick(View v); + + //protected abstract void onFastClick(); +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/ToastUtil.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/ToastUtil.java new file mode 100644 index 0000000..8d77bb6 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/ToastUtil.java @@ -0,0 +1,93 @@ +package com.tairui.gov_affairs_cloud.util; + +import com.tairui.gov_affairs_cloud.GacApplication; +import com.tairui.gov_affairs_cloud.R; + +import android.content.Context; +import android.graphics.Color; +import android.text.TextUtils; +import android.view.Gravity; +import android.widget.TextView; +import android.widget.Toast; + + +/** + *

+ * Toast 弹窗工具类 + */ + +public class ToastUtil { + + /** + * 显示时常较短的弹窗 + * + * @param strId 弹窗的信息 + */ + public static void showShortToast(int strId) { + String msg = GacApplication.getContext().getResources().getString(strId); + showShortToast(msg); + } + + /** + * 显示时常较短的弹窗 + * + * @param msg 弹窗的信息 + */ + public static void showShortToast(String msg) { + + Context context = GacApplication.getContext(); + if (null != context && !TextUtils.isEmpty(msg)) { + + TextView tv = new TextView(context); + tv.setBackgroundColor(Color.parseColor("#000000")); + tv.setTextColor(Color.WHITE); + tv.setTextSize(16); + tv.setPadding(DensityUtils.dp2px(context, 20), DensityUtils.dp2px(context, 8), DensityUtils.dp2px(context, 20), DensityUtils.dp2px(context, 8)); + + tv.setBackgroundResource(R.drawable.bg_container_toast); + tv.setText(msg); + Toast toast = new Toast(context); + toast.setGravity(Gravity.CENTER, 0, 0); + toast.setDuration(Toast.LENGTH_SHORT); + toast.setView(tv); + toast.show(); + } + } + + /** + * 显示时常较长的弹窗 + * + * @param strId 弹窗的信息 + */ + public static void showLongToast(int strId) { + String msg = GacApplication.getContext().getResources().getString(strId); + showLongToast(msg); + } + + /** + * 显示时常较长的弹窗 + * + * @param msg 弹窗的信息 + */ + public static void showLongToast(String msg) { + + Context context = GacApplication.getContext(); + if (null != context && !TextUtils.isEmpty(msg)) { + + TextView tv = new TextView(context); + tv.setBackgroundColor(Color.parseColor("#000000")); + tv.setTextColor(Color.WHITE); + tv.setTextSize(16); + tv.setPadding(DensityUtils.dp2px(context, 20), DensityUtils.dp2px(context, 8), DensityUtils.dp2px(context, 20), DensityUtils.dp2px(context, 8)); + tv.setBackgroundResource(R.drawable.bg_container_toast); + tv.setText(msg); + + Toast toast = new Toast(context); + toast.setGravity(Gravity.CENTER, 0, 0); + toast.setDuration(Toast.LENGTH_LONG); + toast.setView(tv); + toast.show(); + } + } + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/ext/ClickExt.kt b/app/src/main/java/com/tairui/gov_affairs_cloud/util/ext/ClickExt.kt new file mode 100644 index 0000000..a820ddc --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/ext/ClickExt.kt @@ -0,0 +1,53 @@ +package com.tairui.gov_affairs_cloud.util.ext + +import android.view.View + +/** + * 作者 : hegaojian + * 时间 : 2020/11/18 + * 描述 : + */ + +/** + * 设置防止重复点击事件 + * @param views 需要设置点击事件的view + * @param interval 时间间隔 默认0.5秒 + * @param onClick 点击触发的方法 + */ +fun setOnclickNoRepeat(vararg views: View?, interval: Long = 500, onClick: (View) -> Unit) { + views.forEach { + it?.clickNoRepeat(interval = interval) { view -> + onClick.invoke(view) + } + } +} + +/** + * 防止重复点击事件 默认0.5秒内不可重复点击 + * @param interval 时间间隔 默认0.5秒 + * @param action 执行方法 + */ +var lastClickTime = 0L +fun View.clickNoRepeat(interval: Long = 500, action: (view: View) -> Unit) { + setOnClickListener { + val currentTime = System.currentTimeMillis() + if (lastClickTime != 0L && (currentTime - lastClickTime < interval)) { + return@setOnClickListener + } + lastClickTime = currentTime + action.invoke(it) + } +} + +/** + * 设置点击事件 + * @param views 需要设置点击事件的view + * @param onClick 点击触发的方法 + */ +fun setOnclick(vararg views: View?, onClick: (View) -> Unit) { + views.forEach { + it?.setOnClickListener { view -> + onClick.invoke(view) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/glide/GlideLoader.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/glide/GlideLoader.java new file mode 100644 index 0000000..bc3a6bc --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/glide/GlideLoader.java @@ -0,0 +1,140 @@ +package com.tairui.gov_affairs_cloud.util.glide; + +import java.io.File; + +import com.bumptech.glide.GenericTransitionOptions; +import com.bumptech.glide.Glide; +import com.bumptech.glide.RequestBuilder; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.resource.bitmap.CenterCrop; +import com.bumptech.glide.load.resource.bitmap.CircleCrop; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; +import com.bumptech.glide.request.RequestListener; +import com.bumptech.glide.request.RequestOptions; +import com.tairui.gov_affairs_cloud.GacApplication; +import com.tairui.gov_affairs_cloud.util.DensityUtils; + +import android.content.Context; +import android.widget.ImageView; +import androidx.annotation.AnimRes; + +/** + * @author LYH + * @date 2019-08-20 + **/ +public class GlideLoader { + private static Context context() { + return GacApplication.getContext().getApplicationContext(); + } + + public static void loadRound(ImageView imageView, String url) { + loadRound(imageView, url, -1); + } + + public static void loadRound(ImageView imageView, String url, int placeHolder) { + if (placeHolder > 0) { + RequestOptions options = new RequestOptions() + .placeholder(placeHolder) + .error(placeHolder) + .diskCacheStrategy(DiskCacheStrategy.DATA) + .transforms(new CenterCrop(), new RoundedCorners(DensityUtils.dp2px(context(), 4))); + load(options, imageView, url, -1, null); + } else { + RequestOptions options = new RequestOptions() + .diskCacheStrategy(DiskCacheStrategy.DATA) + .transforms(new CenterCrop(), new RoundedCorners(DensityUtils.dp2px(context(), 4))); + load(options, imageView, url, -1, null); + } + + } + + public static void loadCircle(ImageView imageView, String url) { + loadCircle(imageView, url, -1); + } + + public static void loadCircle(ImageView imageView, String url, int placeHolder) { + if (placeHolder > 0) { + RequestOptions options = new RequestOptions() + .placeholder(placeHolder) + .error(placeHolder) + .diskCacheStrategy(DiskCacheStrategy.DATA) + .transforms(new CenterCrop(), new CircleCrop()); + load(options, imageView, url, -1, null); + } else { + RequestOptions options = new RequestOptions() + .diskCacheStrategy(DiskCacheStrategy.DATA) + .transforms(new CenterCrop(), new CircleCrop()); + load(options, imageView, url, -1, null); + } + + } + + public static void loadFile(ImageView imageView, File file, int placeHolder) { + RequestOptions options = new RequestOptions() + .placeholder(placeHolder) + .error(placeHolder) + .diskCacheStrategy(DiskCacheStrategy.DATA) + .transforms(new CenterCrop()); + RequestBuilder builder = Glide.with(imageView) + .setDefaultRequestOptions(options) + .load(file); + builder.into(imageView); + } + + public static void loadRes(ImageView imageView, int resId) { + RequestOptions options = new RequestOptions() + .diskCacheStrategy(DiskCacheStrategy.DATA) + .transforms(new CenterCrop()); + loadRes(options, imageView, resId, -1, null); + } + + public static void loadOriginal(ImageView imageView, String url) { + loadOriginal(imageView, url, -1); + } + + public static void loadOriginal(ImageView imageView, String url, int placeHolder) { + if (placeHolder > 0) { + RequestOptions options = new RequestOptions() + .placeholder(placeHolder) + .error(placeHolder) + .diskCacheStrategy(DiskCacheStrategy.DATA) + .transforms(new CenterCrop()); + load(options, imageView, url, -1, null); + } else { + RequestOptions options = new RequestOptions() + .diskCacheStrategy(DiskCacheStrategy.DATA) + .transforms(new CenterCrop()); + load(options, imageView, url, -1, null); + } + } + + + private static void loadRes(RequestOptions option, ImageView imageView, int redId, @AnimRes int anim, RequestListener listener) { + RequestBuilder builder = Glide.with(imageView) + .setDefaultRequestOptions(option) + .load(redId); + if (anim != -1) { + builder.transition(GenericTransitionOptions.with(anim)); + } + + if (listener != null) { + builder.listener(listener); + } + builder.into(imageView); + } + + + private static void load(RequestOptions option, ImageView imageView, String url, @AnimRes int anim, RequestListener listener) { + RequestBuilder builder = Glide.with(imageView) + .setDefaultRequestOptions(option) + .load(url); + if (anim != -1) { + builder.transition(GenericTransitionOptions.with(anim)); + } + + if (listener != null) { + builder.listener(listener); + } + builder.into(imageView); + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/CommonUtil.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/CommonUtil.java new file mode 100644 index 0000000..2733c40 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/CommonUtil.java @@ -0,0 +1,73 @@ +package com.tairui.gov_affairs_cloud.util.location; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +import com.amap.api.maps.model.LatLng; +import com.tairui.gov_affairs_cloud.util.location.bean.DrawLatLng; + +public class CommonUtil { + /** + * 计算平均值 + * + * @param a + * @param b + * @return + */ + public static int avg(int a, int b) { + + return ((a & b) + ((a ^ b) >> 1)); + + } + + /** + * 获取不规则多边形重心点 + * + * @param mPoints + * @return + */ + public static LatLng getCenterOfDrawPoint(List mPoints) { + double area = 0.0;//多边形面积 + double Gx = 0.0, Gy = 0.0;// 重心的x、y + for (int i = 1; i <= mPoints.size(); i++) { + double iLat = mPoints.get(i % mPoints.size()).getLatLng().latitude; + double iLng = mPoints.get(i % mPoints.size()).getLatLng().longitude; + double nextLat = mPoints.get(i - 1).getLatLng().latitude; + double nextLng = mPoints.get(i - 1).getLatLng().longitude; + double temp = (iLat * nextLng - iLng * nextLat) / 2.0; + area += temp; + Gx += temp * (iLat + nextLat) / 3.0; + Gy += temp * (iLng + nextLng) / 3.0; + } + Gx = Gx / area; + Gy = Gy / area; + return new LatLng(Gx, Gy); + } + + + + public static int[] getKeyOfMinValue(Map map) { + int[] arr = new int[2];//设置一个 长度为2的数组 用作记录 规定第一个元素存储角标 第二个元素存储值 + + + List> list = new ArrayList>(map.entrySet()); + Collections.sort(list, new Comparator>() { + public int compare(Map.Entry o1, Map.Entry o2) { + //升序排列 + return (o1.getValue() - o2.getValue()); + + //降序排列 + + //return (o1.getValue() - o2.getValue()); + + } + }); + + arr[0] = list.get(0).getKey(); + arr[1] = list.get(0).getValue(); + return arr; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/DrawMapUtil.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/DrawMapUtil.java new file mode 100644 index 0000000..ac1db4c --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/DrawMapUtil.java @@ -0,0 +1,177 @@ +package com.tairui.gov_affairs_cloud.util.location; + +import java.util.ArrayList; +import java.util.List; + +import com.amap.api.maps.AMap; +import com.amap.api.maps.model.Circle; +import com.amap.api.maps.model.CircleOptions; +import com.amap.api.maps.model.LatLng; +import com.amap.api.maps.model.Polyline; +import com.amap.api.maps.model.PolylineOptions; +import com.tairui.gov_affairs_cloud.util.location.bean.DrawCircle; +import com.tairui.gov_affairs_cloud.util.location.bean.DrawLatLng; + +import android.graphics.Color; +import android.graphics.Point; + +/** + * 类功能描述: + * 作者: zhongyangxue + * 创建时间: 2019/11/10 下午2:42 + * 邮箱 1366411749@qq.com + * 版本: 1.0 + */ +public class DrawMapUtil { + + public static float getScreenDistance(AMap aMap, LatLng latLng1, LatLng latLng2) { + Point point1 = aMap.getProjection().toScreenLocation(latLng1); + Point point2 = aMap.getProjection().toScreenLocation(latLng2); + float fLen = (float) Math.sqrt(Math.pow(point1.x - point2.x, 2) + + Math.pow(point1.y - point2.y, 2)); + return fLen; + } + + public static void drawBigCircle(AMap aMap, DrawLatLng latLng) { + Circle circle = aMap.addCircle(new CircleOptions() + .center(latLng.getLatLng()) + .radius(5) + .fillColor(Color.argb(255, 255, 255, 255)) + .strokeColor(Color.argb(255, 255, 255, 255)) + .strokeWidth(0).zIndex(999)); + } + + public static void drawSmallCircle(AMap aMap, LatLng latLng1, LatLng latLng2) { + Point point1 = aMap.getProjection().toScreenLocation(latLng1); + Point point2 = aMap.getProjection().toScreenLocation(latLng2); + Point centerPoint = new Point(avg(point1.x, point2.x), + avg(point1.y, point2.y)); + + LatLng centerLatLng = aMap.getProjection().fromScreenLocation(centerPoint); + Circle circle = aMap.addCircle(new CircleOptions() + .center(centerLatLng) + .radius(3) + .fillColor(Color.argb(255, 255, 255, 255)) + .strokeColor(Color.argb(255, 255, 255, 255)) + .strokeWidth(0).zIndex(999)); + } + + public static void drawBigCircle2(AMap aMap, ArrayList circleList, DrawLatLng latLng, int position) { + Circle circle = aMap.addCircle(new CircleOptions() + .center(latLng.getLatLng()) + .radius(5) + .fillColor(Color.argb(255, 255, 255, 255)) + .strokeColor(Color.argb(255, 255, 255, 255)) + .strokeWidth(0).zIndex(999)); + circleList.add(position, new DrawCircle(circle, true)); + } + + + public static void drawSmallCircle2(AMap aMap, ArrayList circleList, DrawLatLng drawLatLng, ArrayList points, int position) { + Circle circle = aMap.addCircle(new CircleOptions() + .center(drawLatLng.getLatLng()) + .radius(3) + .fillColor(Color.argb(255, 255, 255, 255)) + .strokeColor(Color.argb(255, 255, 255, 255)) + .strokeWidth(0).zIndex(999)); + circleList.add(position, new DrawCircle(circle, false)); + points.add(position, new DrawLatLng(drawLatLng.getLatLng(), false)); + } + + public static void drawLine(AMap aMap, LatLng latLng1, LatLng latLng2, List polylineList) { + Polyline polyline = aMap.addPolyline(new PolylineOptions(). + add(latLng1, latLng2).width(5).color(Color.argb(255, 255, 255, 255)).zIndex(999)); + polylineList.add(polyline); + } + + public static ArrayList drawLatlngToLatlng(List drawLatLngs) { + ArrayList latLngs = new ArrayList<>(); + for (int i = 0; i < drawLatLngs.size(); i++) { + latLngs.add(drawLatLngs.get(i).getLatLng()); + } + return latLngs; + } + + + + public static Boolean checkDraw(List latLngs, AMap aMap) { + Boolean flag = false; + try { + + for (int i = 0; i < latLngs.size() - 2; i++) { + Point point1, point2, point3, point4; + + point1 = aMap.getProjection().toScreenLocation(latLngs.get(i).getLatLng()); + point2 = aMap.getProjection().toScreenLocation(latLngs.get(i + 1).getLatLng()); + + for (int j = i + 2; j < latLngs.size(); j++) { + + if (i == 0 && j == latLngs.size() - 1) { + break; + + } else if (j == latLngs.size() - 1) { + point3 = aMap.getProjection().toScreenLocation(latLngs.get(j).getLatLng()); + point4 = aMap.getProjection().toScreenLocation(latLngs.get(0).getLatLng()); + flag = intersection(point1, point2, point3, point4); + + } else { + point3 = aMap.getProjection().toScreenLocation(latLngs.get(j).getLatLng()); + point4 = aMap.getProjection().toScreenLocation(latLngs.get(j + 1).getLatLng()); + flag = intersection(point1, point2, point3, point4); + } + + if (flag) { + return flag; + } + } + } + + } catch (Exception e) { + } + + + return flag; + } + + + public static boolean intersection(Point point1, Point point2, Point point3, Point point4) { + double l1x1 = point1.x; + double l1y1 = point1.y; + double l1x2 = point2.x; + double l1y2 = point2.y; + double l2x1 = point3.x; + double l2y1 = point3.y; + double l2x2 = point4.x; + double l2y2 = point4.y; + + + // 快速排斥实验 首先判断两条线段在 x 以及 y 坐标的投影是否有重合。 有一个为真,则代表两线段必不可交。 + if (Math.max(l1x1, l1x2) < Math.min(l2x1, l2x2) + || Math.max(l1y1, l1y2) < Math.min(l2y1, l2y2) + || Math.max(l2x1, l2x2) < Math.min(l1x1, l1x2) + || Math.max(l2y1, l2y2) < Math.min(l1y1, l1y2)) { + return false; + } + // 跨立实验 如果相交则矢量叉积异号或为零,大于零则不相交 + if ((((l1x1 - l2x1) * (l2y2 - l2y1) - (l1y1 - l2y1) * (l2x2 - l2x1)) + * ((l1x2 - l2x1) * (l2y2 - l2y1) - (l1y2 - l2y1) * (l2x2 - l2x1))) > 0 + || (((l2x1 - l1x1) * (l1y2 - l1y1) - (l2y1 - l1y1) * (l1x2 - l1x1)) + * ((l2x2 - l1x1) * (l1y2 - l1y1) - (l2y2 - l1y1) * (l1x2 - l1x1))) > 0) { + return false; + } + return true; + } + + /** + * 计算平均值 + * + * @param a + * @param b + * @return + */ + public static int avg(int a, int b) { + + return ((a & b) + ((a ^ b) >> 1)); + + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/GoogleMapUtil.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/GoogleMapUtil.java new file mode 100644 index 0000000..9ffdd22 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/GoogleMapUtil.java @@ -0,0 +1,46 @@ +package com.tairui.gov_affairs_cloud.util.location; + +import java.net.MalformedURLException; +import java.net.URL; + +import com.amap.api.maps.model.TileOverlayOptions; +import com.amap.api.maps.model.TileProvider; +import com.amap.api.maps.model.UrlTileProvider; + +/** + * 类功能描述: 高德地图切换到有的地方没有卫星图片,此处使用谷歌地图的卫星切片替换 + * 作者: zhongyangxue + * 创建时间: 2019/10/16 上午12:40 + * 邮箱 1366411749@qq.com + * 版本: 1.0 + */ +public class GoogleMapUtil { +// final static String url = "http://mt2.google.cn/vt/lyrs=y@167000000&hl=zh-CN&gl=cn&x=%d&y=%d&z=%d&s=Galil"; +// final static String url = "http://mt0.google.cn/vt/lyrs=y@198&hl=zh-CN&gl=cn&src=app&x=%d&y=%d&z=%d&s="; + final static String url = "http://mt3.google.cn/maps/vt?lyrs=y@194&hl=zh-CN&gl=cn&x=%d&y=%d&z=%d"; + + + public static TileOverlayOptions getGooleMapTileOverlayOptions() { + + TileProvider tileProvider = new UrlTileProvider(256, 256) { + public URL getTileUrl(int x, int y, int zoom) { + try { + return new URL(String.format(url, x, y, zoom)); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + return null; + } + }; + + return new TileOverlayOptions() + .tileProvider(tileProvider) + .diskCacheEnabled(true) + .diskCacheSize(50000) + .diskCacheDir("/storage/emulated/0/amap/OMCcache") + .memoryCacheEnabled(false) + .memCacheSize(10000) + .zIndex(-9999); + } + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/GpsManager.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/GpsManager.java new file mode 100644 index 0000000..1eb997b --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/GpsManager.java @@ -0,0 +1,142 @@ +package com.tairui.gov_affairs_cloud.util.location; + +import static android.content.Context.LOCATION_SERVICE; + +import org.greenrobot.eventbus.EventBus; + +import com.amap.api.location.AMapLocation; +import com.amap.api.location.AMapLocationClient; +import com.amap.api.location.AMapLocationClientOption; +import com.amap.api.location.AMapLocationListener; +import com.tairui.gov_affairs_cloud.entity.EventConstant; +import com.tairui.gov_affairs_cloud.entity.EventMessage; +import com.tairui.gov_affairs_cloud.util.PopWindowUtil; +import com.tairui.gov_affairs_cloud.util.location.bean.LatlngBean; + +import android.app.Activity; +import android.content.Intent; +import android.location.LocationManager; +import android.provider.Settings; + +/** + * 类功能描述: + * 作者: zhongyangxue + * 创建时间: 2020-03-30 14:18 + * 邮箱 1366411749@qq.com + * 版本: 1.0 + */ +public class GpsManager { + private AMapLocationClient locationClient = null; + private LocationManager mLocationManager; + private static final GpsManager checkGpsManager = new GpsManager(); + + private GpsManager() { + } + + + public static GpsManager getInstance() { + return checkGpsManager; + } + + public void init(Activity context) throws Exception { + if (mLocationManager == null) { + mLocationManager = (LocationManager) context.getSystemService(LOCATION_SERVICE); + } + if (locationClient == null) { + //初始化client + locationClient = new AMapLocationClient(context); + //设置定位参数 + locationClient.setLocationOption(getDefaultOption()); + // 设置定位监听 + locationClient.setLocationListener(locationListener); + // 启动定位 +// locationClient.startLocation(); + } + } + + public void startLocation() { + if (locationClient != null) { + //先暂停 + locationClient.stopLocation(); + // 启动定位 + locationClient.startLocation(); + } + } + + /** + * 默认的定位参数 + * + * @author hongming.wang + * @since 2.8.0 + */ + private AMapLocationClientOption getDefaultOption() { + AMapLocationClientOption mOption = new AMapLocationClientOption(); + mOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);//可选,设置定位模式,可选的模式有高精度、仅设备、仅网络。默认为高精度模式 + mOption.setGpsFirst(true);//可选,设置是否gps优先,只在高精度模式下有效。默认关闭 + mOption.setHttpTimeOut(30 * 000);//可选,设置网络请求超时时间。默认为30秒。在仅设备模式下无效 + mOption.setInterval(50 * 1000);//可选,设置定位间隔。 + mOption.setNeedAddress(true);//可选,设置是否返回逆地理地址信息。默认是true + mOption.setOnceLocation(false);//可选,设置是否单次定位。默认是false + mOption.setWifiScan(true); //可选,设置是否开启wifi扫描。默认为true,如果设置为false会同时停止主动刷新,停止以后完全依赖于系统刷新,定位位置可能存在误差 + mOption.setLocationCacheEnable(true); //可选,设置是否使用缓存定位,默认为true + mOption.setMockEnable(false); ////设置是否允许模拟位置,默认为false,不允许模拟位置 + return mOption; + } + + /** + * 判断是否打开定位 + * + * @return + */ + public Boolean checkGps() { + //判断gps是否打开 + return mLocationManager + .isProviderEnabled(LocationManager.GPS_PROVIDER); + } + + /** + * 跳转到设置页面 + * + * @param context + * @param GPS_REQUEST_CODE + */ + public void goToSetting(Activity context, int GPS_REQUEST_CODE) { + PopWindowUtil.buildNoTitleEnsureDialog(context, "请在设置中打开定位", "取消", "去设置", new PopWindowUtil.EnsureListener() { + @Override + public void sure(Object obj) { + Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); + context.startActivityForResult(intent, GPS_REQUEST_CODE); + } + + @Override + public void cancel() { + + } + }); + + } + + + /** + * 定位监听 + */ + AMapLocationListener locationListener = new AMapLocationListener() { + @Override + public void onLocationChanged(AMapLocation loc) { + if (null == loc) { + return; + } + try { + if (loc.getLatitude() != 0 &&loc.getLongitude() != 0) { + EventBus.getDefault().post(new EventMessage(EventConstant.LOCATION_CODE,new LatlngBean(loc.getLatitude(),loc.getLongitude()))); + } + + } catch (Exception e) { + + } + + } + }; + + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/bean/DrawCircle.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/bean/DrawCircle.java new file mode 100644 index 0000000..1374044 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/bean/DrawCircle.java @@ -0,0 +1,36 @@ +package com.tairui.gov_affairs_cloud.util.location.bean; + +import com.amap.api.maps.model.Circle; + +/** + * 类功能描述: + * 作者: zhongyangxue + * 创建时间: 2019/11/10 下午6:11 + * 邮箱 1366411749@qq.com + * 版本: 1.0 + */ +public class DrawCircle { + private Circle circle; + private Boolean isBigCircle; + + public DrawCircle(Circle circle, Boolean isBigCircle) { + this.circle = circle; + this.isBigCircle = isBigCircle; + } + + public Circle getCircle() { + return circle; + } + + public void setCircle(Circle circle) { + this.circle = circle; + } + + public Boolean getBigCircle() { + return isBigCircle; + } + + public void setBigCircle(Boolean bigCircle) { + isBigCircle = bigCircle; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/bean/DrawLatLng.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/bean/DrawLatLng.java new file mode 100644 index 0000000..7807636 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/bean/DrawLatLng.java @@ -0,0 +1,38 @@ +package com.tairui.gov_affairs_cloud.util.location.bean; + + +import com.amap.api.maps.model.LatLng; + +/** + * 类功能描述: + * 作者: zhongyangxue + * 创建时间: 2019/10/5 下午1:33 + * 邮箱 1366411749@qq.com + * 版本: 1.0 + */ +public class DrawLatLng { + private LatLng latLng; //经纬度 + private Boolean isBigCircle; //是否是原始采集点 + + public DrawLatLng(LatLng latLng, Boolean isBigCircle) { + this.latLng = latLng; + this.isBigCircle = isBigCircle; + } + + public LatLng getLatLng() { + return latLng; + } + + public void setLatLng(LatLng latLng) { + this.latLng = latLng; + } + + public Boolean getBigCircle() { + return isBigCircle; + } + + public void setBigCircle(Boolean bigCircle) { + isBigCircle = bigCircle; + } + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/bean/LatlngBean.java b/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/bean/LatlngBean.java new file mode 100644 index 0000000..de9f8dc --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/util/location/bean/LatlngBean.java @@ -0,0 +1,29 @@ +package com.tairui.gov_affairs_cloud.util.location.bean; + +import java.io.Serializable; + +public class LatlngBean implements Serializable { + private double latitude; + private double longitude; + + public LatlngBean(double latitude, double longitude) { + this.latitude = latitude; + this.longitude = longitude; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/CustomViewPager.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/CustomViewPager.java new file mode 100644 index 0000000..b1e17e5 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/CustomViewPager.java @@ -0,0 +1,58 @@ +package com.tairui.gov_affairs_cloud.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import androidx.viewpager.widget.ViewPager; + +/** + * @author kpinfo + */ +public class CustomViewPager extends ViewPager { + + private boolean isCanScroll; + + public CustomViewPager(Context context) { + super(context); + } + + public CustomViewPager(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + if (isCanScroll) { + //允许滑动则应该调用父类的方法 + try { + return super.onTouchEvent(ev); + } catch (Exception e) { + return false; + } + } else { + //禁止滑动则不做任何操作,直接返回true即可 + return true; + } + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + try { + if (isCanScroll) { + return super.onInterceptTouchEvent(ev); + } + } catch (Exception e) { + return false; + } + return false; + } + + /** + * 设置是否允许滑动,true是可以滑动,false是禁止滑动 + * + * @param isCanScroll 是否可以滚动 + */ + public void setIsCanScroll(boolean isCanScroll) { + this.isCanScroll = isCanScroll; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/GridSpacingItemDecoration.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/GridSpacingItemDecoration.java new file mode 100644 index 0000000..fc8eee2 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/GridSpacingItemDecoration.java @@ -0,0 +1,46 @@ +package com.tairui.gov_affairs_cloud.widget; + +import android.graphics.Rect; +import android.view.View; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration { + + private final int spacing; + private final int spanCount; + private final boolean includeEdge; + + public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) { + this.spanCount = spanCount; + this.spacing = spacing; + this.includeEdge = includeEdge; + } + + @Override + public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, + @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { + int position = parent.getChildAdapterPosition(view); + if (position == RecyclerView.NO_POSITION) { + return; + } + + int column = position % spanCount; + + if (includeEdge) { + outRect.left = spacing - column * spacing / spanCount; + outRect.right = (column + 1) * spacing / spanCount; + + if (position < spanCount) { + outRect.top = spacing; + } + outRect.bottom = spacing; + } else { + outRect.left = column * spacing / spanCount; + outRect.right = spacing - (column + 1) * spacing / spanCount; + if (position >= spanCount) { + outRect.top = spacing; + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/RefreshRecyclerView.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/RefreshRecyclerView.java new file mode 100644 index 0000000..86e88a8 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/RefreshRecyclerView.java @@ -0,0 +1,144 @@ +package com.tairui.gov_affairs_cloud.widget; + +import com.scwang.smart.refresh.layout.SmartRefreshLayout; +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.widget.blankview.BlankView; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.FrameLayout; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; + +/** + * 封装了带刷新的recyclerview, 支持loading和error + */ +public class RefreshRecyclerView extends FrameLayout { + + private Context mContext; + private SmartRefreshLayout refreshLayout; + private RecyclerView recyclerView; + private View loadingView; + private BlankView blankView; + + private RefreshRecyclerListener listener; + + public RefreshRecyclerView(@NonNull Context context) { + super(context); + init(context); + } + + public RefreshRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(context); + } + + public RefreshRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + private void init(Context context) { + mContext = context; + View view = LayoutInflater.from(context).inflate(R.layout.view_refresh_recycler, this, true); + if (null != view) { + refreshLayout = view.findViewById(R.id.refreshLayout); + recyclerView = view.findViewById(R.id.recycle_view); + loadingView = view.findViewById(R.id.loading_view); + blankView = view.findViewById(R.id.blank_view); + blankView.setBlankView(R.mipmap.img_no_content, mContext.getResources().getString(R.string.str_no_content)); + + refreshLayout.setOnLoadMoreListener(refreshLayout -> { + if (listener != null) { + listener.onLoadmore(); + } + }); + + refreshLayout.setOnRefreshListener(refreshLayout -> { + if (listener != null) { + listener.onRefresh(); + } + }); + + blankView.setOnBlankViewClickListener(view1 -> { + if (listener != null) { + listener.onBlankClick(); + } + }); + } + } + + public void autoRefresh() { + refreshLayout.autoRefresh(); + } + + public void setEnableLoadMore(boolean loadMore) { + refreshLayout.setEnableLoadMore(loadMore); + } + + public void setEnableRefresh(boolean refresh) { + refreshLayout.setEnableRefresh(refresh); + } + + public void setNoMoreData(boolean noMoreData) { + refreshLayout.setNoMoreData(noMoreData); + } + + public RecyclerView getRecyclerView() { + return recyclerView; + } + + public void finishRefresh() { + refreshLayout.finishRefresh(); + } + + public void finishLoadMore() { + refreshLayout.finishLoadMore(); + } + + public void showContent() { + refreshLayout.setVisibility(View.VISIBLE); + loadingView.setVisibility(View.GONE); + blankView.setVisibility(View.GONE); + } + + public void showError() { + refreshLayout.setVisibility(View.GONE); + loadingView.setVisibility(View.GONE); + blankView.setVisibility(View.VISIBLE); + } + + public void showLoading() { + refreshLayout.setVisibility(View.GONE); + loadingView.setVisibility(View.VISIBLE); + blankView.setVisibility(View.GONE); + } + + public void setLayoutManager(RecyclerView.LayoutManager layoutManager) { + recyclerView.setLayoutManager(layoutManager); + } + + public void setAdapter(RecyclerView.Adapter adapter) { + recyclerView.setAdapter(adapter); + } + + public void setRefreshRecyclerListener(RefreshRecyclerListener _listener) { + listener = _listener; + } + + public void setBlankView(int imageRes, String content) { + blankView.setBlankView(imageRes, content); + } + + public interface RefreshRecyclerListener { + void onRefresh(); + + void onLoadmore(); + + void onBlankClick(); + + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/blankview/BlankView.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/blankview/BlankView.java new file mode 100644 index 0000000..866d38d --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/blankview/BlankView.java @@ -0,0 +1,230 @@ +package com.tairui.gov_affairs_cloud.widget.blankview; + +import com.bumptech.glide.Glide; +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.widget.blankview.interfaces.BlankViewClickListener; + +import android.content.Context; +import android.graphics.Color; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.style.ForegroundColorSpan; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +public class BlankView extends LinearLayout { + + private ImageView img; + private TextView txt; + + private TextView infoTv; + private Context context; + + private BlankViewClickListener listener; + private boolean isLoading = false;// 是否正在加载 + + + /** + * 设置监听 + * + * @param listener 监听器 + */ + public void setOnBlankViewClickListener(BlankViewClickListener listener) { + this.listener = listener; + } + + + public BlankView(Context context) { + super(context); + this.context = context; + init(context); + } + + public BlankView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + this.context = context; + init(context); + } + + public BlankView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + this.context = context; + init(context); + } + + + /** + * 设置 空白页信息 + * + * @param postAvatarUrl 显示的图片 + * @param describe 显示的文字 + * @param highLightStr 高亮的文字 + */ + public void setBlankView(String postAvatarUrl, @NonNull String describe, @NonNull String highLightStr) { + if (null != img && null != txt) { + Glide.with(context).load(postAvatarUrl).into(img); + if (describe.contains(highLightStr)) { + int startPos = describe.indexOf(highLightStr); + int endPos = startPos + (highLightStr.length()); + if (endPos <= startPos) { + txt.setText(describe); + } else { + txt.setText(renderColorfulStr(describe, startPos, endPos)); + } + } else { + txt.setText(describe); + } +// txt.setText(renderColorfulStr(describe, startPos, endPos)); + } + } + + /** + * 设置 空白页信息 + * + * @param resId 显示的图片 + * @param describe 显示的文字 + * @param highLightStr 高亮的文字 + */ + public void setBlankView(int resId, @NonNull String describe, @NonNull String highLightStr) { + + if (null != img && null != txt) { + Glide.with(context).load(resId).into(img); + if (describe.contains(highLightStr)) { + int startPos = describe.indexOf(highLightStr); + int endPos = startPos + (highLightStr.length()); + if (endPos <= startPos) { + txt.setText(describe); + } else { + txt.setText(renderColorfulStr(describe, startPos, endPos)); + } + } else { + txt.setText(describe); + } + } + } + + + /** + * 设置 空白页信息 + * + * @param resId 显示的图片 + * @param describe 显示的文字 + */ + public void setBlankView(int resId, @NonNull String describe) { + + if (null != img && null != txt) { + Glide.with(context).load(resId).into(img); + txt.setText(describe); + } + } + + /** + * 设置 空白页信息 + * + * @param resId 显示的图片 + * @param describe 显示的文字 + * @param info 提示的内容 + */ + public void setBlankViewWithHint(int resId, @NonNull String describe, @NonNull String info) { + + if (null != img && null != txt && null != infoTv) { + Glide.with(context).load(resId).into(img); + txt.setText(describe); + infoTv.setText(info); + infoTv.setVisibility(VISIBLE); + } + } + + /** + * 设置 空白页信息 + * + * @param resId 默认的图片 + */ + public void setBlankView(int resId) { + if (null != txt && null != img) { + txt.setText(GONE); + Glide.with(context).load(resId).into(img); + } + } + + + /** + * 设置 空白页信息 + * + * @param describe 显示的文字 + * @param highLightStr 高亮的文字 + */ + public void setBlankView(@NonNull String describe, @NonNull String highLightStr) { + + if (null != img && null != txt) { + + if (describe.contains(highLightStr)) { + int startPos = describe.indexOf(highLightStr); + int endPos = startPos + (highLightStr.length()); + if (endPos <= startPos) { + txt.setText(describe); + } else { + txt.setText(renderColorfulStr(describe, startPos, endPos)); + } + } else { + txt.setText(describe); + } +// txt.setText(renderColorfulStr(describe, startPos, endPos)); + } + } + + + /** + * 禁止 可以点击 + */ + public void forbidClick() { + isLoading = false; + } + + /** + * 允许点击 + */ + public void permitClick() { + isLoading = true; + } + + + /** + * 初始化 + * + * @param context 上下文对象 + */ + private void init(Context context) { + View view = LayoutInflater.from(context).inflate(R.layout.layout_blank, this, true); + if (null != view) { + img = view.findViewById(R.id.img_blank); + txt = view.findViewById(R.id.txt_describe_blank); + infoTv = view.findViewById(R.id.txt_info_blank); + view.setOnClickListener(v -> { + if (null != listener && !isLoading) { + listener.onBlankViewClickListener(v); + } + }); + } + } + + /** + * render 带有颜色的 spannableStringBuilder + * + * @param targetStr 对应的文字 + * @param endPos 结束位置 + */ + private SpannableStringBuilder renderColorfulStr(String targetStr, int startPos, int endPos) { + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(targetStr); + spannableStringBuilder.setSpan(new ForegroundColorSpan(Color.RED), startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + return spannableStringBuilder; + } + + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/blankview/interfaces/BlankViewClickListener.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/blankview/interfaces/BlankViewClickListener.java new file mode 100644 index 0000000..2b5672c --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/blankview/interfaces/BlankViewClickListener.java @@ -0,0 +1,11 @@ +package com.tairui.gov_affairs_cloud.widget.blankview.interfaces; + +import android.view.View; + + +public interface BlankViewClickListener { + + + void onBlankViewClickListener(View view); + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/BaseChart.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/BaseChart.java new file mode 100644 index 0000000..715f8f6 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/BaseChart.java @@ -0,0 +1,354 @@ +package com.tairui.gov_affairs_cloud.widget.charts; + +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.util.FontUtil; +import com.tairui.gov_affairs_cloud.util.LogUtil; +import com.tairui.gov_affairs_cloud.widget.charts.anim.AngleEvaluator; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PointF; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.DecelerateInterpolator; + +/** + * autour : openXu + * date : 2017/7/24 10:46 + * className : BaseChart + * version : 1.0 + * description : 图表基类 + */ +public abstract class BaseChart extends View { + + protected String TAG = "BaseChart"; + protected int ScrWidth,ScrHeight; //屏幕宽高 + protected RectF rectChart; //图表矩形 + + protected PointF centerPoint; //chart中心点坐标 + + protected int total; //总数量 + + /**可设置属性*/ + protected int startAngle = -90; //开始的角度 + protected int backColor = Color.parseColor("#F8F8F8"); + protected int lineWidth = 1; //辅助线宽度 + protected String loadingStr = "loading..."; + protected int defColor = Color.parseColor("#00000000"); //底色 + + + protected Paint paint; + protected Paint paintEffect; + protected Paint paintLabel; + + /**动画相关统一属性,也可以设置,需要写set方法*/ + protected long animDuration = 1000; + protected ValueAnimator anim; + protected boolean startDraw = false; + + /**正在加载*/ + protected boolean isLoading = true; + protected boolean drawLine = true; + protected boolean drawBottomLine = true; + protected boolean debug = false; + + + /**手指抬起后,动画*/ + protected ValueAnimator touchAnim; + protected GestureDetector mGestureDetector; + + + public void setLoading(boolean loading) { + isLoading = loading; + invalidate(); + } + + public void setLineWidth(int lineWidth) { + this.lineWidth = lineWidth; + } + + public BaseChart(Context context) { + this(context, null); + } + + public BaseChart(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public BaseChart(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + init(context, attrs, defStyle); + } + + public void setBackColor(int backColor) { + this.backColor = backColor; + } + + public void init() { + TAG = getClass().getSimpleName(); + + DisplayMetrics dm = getResources().getDisplayMetrics(); + ScrHeight = dm.heightPixels; + ScrWidth = dm.widthPixels; + + //画笔初始化 + paint = new Paint(); + paint.setAntiAlias(true); + + paintLabel = new Paint(); + paintLabel.setAntiAlias(true); + + paintEffect = new Paint(); + paintEffect.setAntiAlias(true); + paintEffect.setStyle(Paint.Style.FILL); + paintEffect.setStrokeWidth(lineWidth); + paintEffect.setColor(Color.RED); + + mGestureDetector = new GestureDetector(getContext(), new MyOnGestureListener()); + + } + + public abstract void init(Context context, AttributeSet attrs, int defStyleAttr); + public int getTotal() { + return total; + } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + centerPoint = new PointF(getMeasuredWidth()/2, getMeasuredHeight()/2); + rectChart = new RectF(getPaddingLeft(),getPaddingTop(),getMeasuredWidth()-getPaddingRight(), + getMeasuredHeight()-getPaddingBottom()); + } + + protected TOUCH_EVENT_TYPE touchEventType = TOUCH_EVENT_TYPE.EVENT_NULL; + /**需要拦截的事件方向*/ + public enum TOUCH_EVENT_TYPE{ + EVENT_NULL, /*不处理事件*/ + EVENT_X, /*拦截X轴方向的事件*/ + EVENT_Y, /*拦截Y轴方向的事件*/ + EVENT_XY /*拦截XY轴方向的事件*/ + } + /**设置事件方向*/ + public void setTouchEventType(TOUCH_EVENT_TYPE touchEventType) { + this.touchEventType = touchEventType; + } + + protected boolean touchEnable = false; //是否超界,控件的大小是否足以显示内容,是否需要滑动来展示。子控件根据计算赋值 + protected float mDownX, mDownY; + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + LogUtil.d(TAG, "dispatchTouchEvent "+touchEventType); + if(!touchEnable){ + LogUtil.w(TAG, "没超界"); + }else if(TOUCH_EVENT_TYPE.EVENT_NULL == touchEventType){ + LogUtil.w(TAG, "不需要处理事件"); + }else if(TOUCH_EVENT_TYPE.EVENT_XY == touchEventType){ + LogUtil.w(TAG, "需要拦截XY方向的事件"); + getParent().requestDisallowInterceptTouchEvent(true); + }else{ + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + mDownX = event.getX(); + mDownY = event.getY(); + if(null!=touchAnim && touchAnim.isRunning()) + touchAnim.cancel(); + getParent().requestDisallowInterceptTouchEvent(true);//ACTION_DOWN的时候,赶紧把事件hold住 + break; + case MotionEvent.ACTION_MOVE: + if(TOUCH_EVENT_TYPE.EVENT_X == touchEventType){ + if(Math.abs(event.getY()-mDownY)> Math.abs(event.getX() - mDownX)) { + getParent().requestDisallowInterceptTouchEvent(false); + LogUtil.i(TAG, "竖直滑动的距离大于水平的时候,将事件还给父控件"); + }else { + getParent().requestDisallowInterceptTouchEvent(true); + LogUtil.i(TAG, "正常请求事件"); + dispatchTouchEvent1(event); + } + }else if(TOUCH_EVENT_TYPE.EVENT_Y == touchEventType){ + if(Math.abs(event.getX() - mDownX)> Math.abs(event.getY()-mDownY)) { + getParent().requestDisallowInterceptTouchEvent(false); + LogUtil.i(TAG, "水平滑动的距离大于竖直的时候,将事件还给父控件"); + }else { + getParent().requestDisallowInterceptTouchEvent(true); + dispatchTouchEvent1(event); + LogUtil.i(TAG, "正常请求事件"); + } + } + break; + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + break; + } + } + return super.dispatchTouchEvent(event); + } + + protected void dispatchTouchEvent1(MotionEvent event){ + + } + + protected PointF lastTouchPoint; + @Override + public boolean onTouchEvent(MotionEvent event) { + if(!touchEnable) + return false; + boolean result = mGestureDetector.onTouchEvent(event); + switch (event.getActionMasked()) { + case MotionEvent.ACTION_DOWN: + lastTouchPoint = new PointF(event.getX(), event.getY()); + onTouchMoved(lastTouchPoint); + return true; + case MotionEvent.ACTION_MOVE: + int move = 0; + if(TOUCH_EVENT_TYPE.EVENT_X == touchEventType){ + move = (int)(event.getX() - lastTouchPoint.x); + }else if(TOUCH_EVENT_TYPE.EVENT_Y == touchEventType){ + move = (int)(event.getY() - lastTouchPoint.y); + } + LogUtil.i(TAG, "MotionEvent.ACTION_MOVE"+move); + lastTouchPoint.x = (int)event.getX(); + lastTouchPoint.y = (int)event.getY(); + onTouchMoved(lastTouchPoint); + evaluatorFling(move); + invalidate(); + return true; + case MotionEvent.ACTION_UP: + lastTouchPoint.x = 0; + lastTouchPoint.y = 0; + onTouchMoved(null); + return true; + } + return result; + } + + protected void onTouchMoved(PointF point){ + } + + + public void onDraw(Canvas canvas){ + //画布背景 +// canvas.drawColor(backColor); + if(debug) { + drawDebug(canvas); + } + drawDefult(canvas); + if(isLoading){ + drawLoading(canvas); + return; + } +// drawChart(canvas); + if(!startDraw){ + startDraw = true; + startAnimation(canvas); + }else{ + drawChart(canvas); + } + } + + + + public void drawLoading(Canvas canvas) { + paintLabel.setTextSize(35); + float NullTextLead = FontUtil.getFontLeading(paintLabel); + float NullTextHeight = FontUtil.getFontHeight(paintLabel); + float textY = centerPoint.y-NullTextHeight/2+NullTextLead; + paintLabel.setColor(getContext().getResources().getColor(R.color.text_color_def)); + canvas.drawText(loadingStr, centerPoint.x- FontUtil.getFontlength(paintLabel, loadingStr)/2, textY, paintLabel); + } + + /**绘制图表基本框架*/ + public abstract void drawDefult(Canvas canvas); + /**绘制debug辅助线*/ + public void drawDebug(Canvas canvas){ + paint.setStyle(Paint.Style.STROKE);//设置空心 + paint.setStrokeWidth(lineWidth); + //绘制边界--chart区域 + paint.setColor(Color.BLUE); + RectF r = new RectF(0,0,getMeasuredWidth(), getMeasuredHeight()); + canvas.drawRect(r, paint); + paint.setColor(Color.RED); + canvas.drawRect(rectChart, paint); + } + /**绘制图表*/ + public abstract void drawChart(Canvas canvas); + /**创建动画*/ + protected abstract ValueAnimator initAnim(); + /**动画值变化之后计算数据*/ + protected abstract void evaluatorData(ValueAnimator animation); + + + public void setAnimDuration(long duration){ + this.animDuration = duration; + } + protected void startAnimation(Canvas canvas) { + if(anim!=null){ + anim.cancel(); + } + LogUtil.w(TAG, "开始绘制动画"); + anim = initAnim(); + if(anim==null){ + drawChart(canvas); + }else{ + anim.setInterpolator(new AccelerateDecelerateInterpolator()); + anim.addUpdateListener((ValueAnimator animation)->{ + evaluatorData(animation); + invalidate(); + }); + anim.setDuration(animDuration); + anim.start(); + } + } + + + /**动画值变化之后计算数据*/ + protected void evaluatorFling(float velocityAnim){} + protected int mMoveLen = 0; //滚动距离 + protected boolean moveOver = false; //是否滚动到头了 + /**手指松开后滑动动画效果*/ + protected void startFlingAnimation(float velocity) { + if(touchAnim!=null){ + touchAnim.cancel(); + } + touchAnim = ValueAnimator.ofObject(new AngleEvaluator(), 1f, 0f); + touchAnim.setInterpolator(new DecelerateInterpolator()); //越来越慢 + touchAnim.addUpdateListener((ValueAnimator animation)->{ + float velocityAnim = (float)animation.getAnimatedValue(); + evaluatorFling(velocity /100 * velocityAnim); + invalidate(); + }); + touchAnim.setDuration(1000+(int)+Math.abs(velocity)/4); + touchAnim.start(); + } + + + class MyOnGestureListener extends GestureDetector.SimpleOnGestureListener { + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + LogUtil.e(TAG,"onFling------------>velocityX="+velocityX+" velocityY="+velocityY); + if(TOUCH_EVENT_TYPE.EVENT_X == touchEventType){ + startFlingAnimation(velocityX); + }else if(TOUCH_EVENT_TYPE.EVENT_Y == touchEventType){ + startFlingAnimation(velocityY); + } + return false; + } + } + + + + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/ProgressPieChart.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/ProgressPieChart.java new file mode 100644 index 0000000..29a642d --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/ProgressPieChart.java @@ -0,0 +1,164 @@ +package com.tairui.gov_affairs_cloud.widget.charts; + +import java.util.List; + +import com.tairui.gov_affairs_cloud.util.DensityUtils; +import com.tairui.gov_affairs_cloud.util.FontUtil; +import com.tairui.gov_affairs_cloud.widget.charts.anim.AngleEvaluator; +import com.tairui.gov_affairs_cloud.widget.charts.bean.ChartLable; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.animation.AccelerateDecelerateInterpolator; + + +/** + * autour : openXu + * date : 2017/7/24 10:46 + * className : ProgressPieChart + * version : 1.0 + * description : 进度图表 + */ +public class ProgressPieChart extends BaseChart { + + private int total; //总数量 + private int progress; //占比数量 + private float animPro; //动画计算的占比数量 + private List lableList; //需要绘制的lable集合 + private int textSpace = DensityUtils.dp2px(getContext(), 3); //文字间距 + + private int raidus; //圆环半径 + private int proSize = DensityUtils.dp2px(getContext(), 8); //圈宽度 + private int proColor = Color.rgb(0, 255, 0); //进度环颜色 + + + public ProgressPieChart(Context context) { + super(context, null); + } + public ProgressPieChart(Context context, AttributeSet attrs) { + super(context, attrs, 0); + } + public ProgressPieChart(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + public void init(Context context, AttributeSet attrs, int defStyleAttr) { + startAngle = -90; //开始的角度 + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int width = getMeasuredWidth(); + int height = getMeasuredHeight(); + + if(width lableList){ + this.total = total; + this.progress = progress; + this.lableList = lableList; + startDraw = false; + invalidate(); + } + + /**绘制图表基本框架*/ + @Override + public void drawDefult(Canvas canvas) { + paint.setStyle(Paint.Style.STROKE);//设置空心 + paint.setStrokeWidth(proSize); + paint.setColor(defColor); + canvas.drawCircle(centerPoint.x,centerPoint.y,raidus-proSize/2, paint); + } + + /**绘制图表*/ + @Override + public void drawChart(Canvas canvas) { + if(progress>0) { + paint.setStrokeWidth(proSize); + paint.setColor(proColor); + //1绘制开始圆点 +// paint.setStyle(Paint.Style.FILL); +// canvas.drawCircle(centerPoint.x, centerPoint.y - raidus + proSize / 2, proSize / 2, paint); + //2绘制进度圆弧 + paint.setStyle(Paint.Style.STROKE);//设置空心 + int r = raidus - proSize / 2; + float arcLeft = centerPoint.x - r; + float arcTop = centerPoint.y - r; + float arcRight = centerPoint.x + r; + float arcBottom = centerPoint.y + r; + canvas.drawArc(new RectF(arcLeft, arcTop, arcRight, arcBottom), startAngle, animPro, false, paint); + //3绘制结束圆点 +// paint.setStyle(Paint.Style.FILL); +// float endX = centerPoint.x + (float) (r * Math.cos(Math.toRadians(startAngle + animPro))); +// float endY = centerPoint.y + (float) (r * Math.sin(Math.toRadians(startAngle + animPro))); +// canvas.drawCircle(endX, endY, proSize / 2, paint); + } + //4绘制文字 + if(lableList!=null &&lableList.size()>0){ + float textAllHeight = 0; + float textW, textH, textL; + for(ChartLable lable : lableList){ + paintLabel.setTextSize(lable.getTextSize()); + textH = FontUtil.getFontHeight(paintLabel); + textAllHeight += (textH+textSpace); + } + textAllHeight -= textSpace; + int top = (int)(centerPoint.y-textAllHeight/2); + for(ChartLable lable : lableList){ + paintLabel.setColor(lable.getTextColor()); + paintLabel.setTextSize(lable.getTextSize()); + textW = FontUtil.getFontlength(paintLabel, lable.getText()); + textH = FontUtil.getFontHeight(paintLabel); + textL = FontUtil.getFontLeading(paintLabel); + canvas.drawText(lable.getText(), centerPoint.x-textW/2, top + textL, paintLabel); + top += (textH+textSpace); + } + } + + } + /**创建动画*/ + @Override + protected ValueAnimator initAnim() { + if(progress>0) { + float angle = (float) progress / (float) total * 360; + ValueAnimator anim = ValueAnimator.ofObject(new AngleEvaluator(), 0f, angle); + anim.setInterpolator(new AccelerateDecelerateInterpolator()); + return anim; + } + return null; + } + /**动画值变化之后计算数据*/ + @Override + protected void evaluatorData(ValueAnimator animation) { + animPro = (float)animation.getAnimatedValue(); + } + + + + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/anim/AngleEvaluator.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/anim/AngleEvaluator.java new file mode 100644 index 0000000..4693fe8 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/anim/AngleEvaluator.java @@ -0,0 +1,22 @@ +package com.tairui.gov_affairs_cloud.widget.charts.anim; + + +import android.animation.TypeEvaluator; + +/** + * autour : openXu + * date : 2017/7/28 9:12 + * className : AngleEvaluator + * version : 1.0 + * description : 角度计算器 + */ +public class AngleEvaluator implements TypeEvaluator { + + @Override + public Object evaluate(float fraction, Object startValue, Object endValue) { + float start = (float)startValue; + float end = (float)endValue; + return start+fraction*(end-start); + } + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/barchart/BarHorizontalChart.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/barchart/BarHorizontalChart.java new file mode 100644 index 0000000..7001aae --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/barchart/BarHorizontalChart.java @@ -0,0 +1,415 @@ +package com.tairui.gov_affairs_cloud.widget.charts.barchart; + +import static com.tairui.gov_affairs_cloud.widget.charts.BaseChart.TOUCH_EVENT_TYPE.EVENT_Y; + +import java.util.ArrayList; +import java.util.List; + +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.util.DensityUtils; +import com.tairui.gov_affairs_cloud.util.FontUtil; +import com.tairui.gov_affairs_cloud.util.LogUtil; +import com.tairui.gov_affairs_cloud.widget.charts.BaseChart; +import com.tairui.gov_affairs_cloud.widget.charts.anim.AngleEvaluator; +import com.tairui.gov_affairs_cloud.widget.charts.bean.BarBean; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PointF; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.animation.AccelerateDecelerateInterpolator; + +/** + * autour : openXu + * date : 2017/7/24 10:46 + * className : BarHorizontalChart + * version : 1.0 + * description : 横向(柱子水平) 柱状图,支持多柱 + */ +public class BarHorizontalChart extends BaseChart { + + private List> dataList; + private List strList; + + /** + * 可以设置的属性 + */ + + private int barNum = 2; //柱子数量 + private int XMARK_NUM = 5; //X轴刻度数量 + + private int barWidth = DensityUtils.dp2px(getContext(), 15); //柱宽度 + private int barSpace = DensityUtils.dp2px(getContext(), 1); //双柱间的间距 + private int barItemSpace = DensityUtils.dp2px(getContext(), 25);//一组柱之间的间距 + private int[] barColor = new int[] {R.color.color_blue, Color.YELLOW}; //柱颜色 + + private int textSizeCoordinate = (int) getResources().getDimension(R.dimen.text_size_level_small); //坐标文字大小 + private int textColorCoordinate = getResources().getColor(R.color.text_color_light_gray); + private int textSizeTag = (int) getResources().getDimension(R.dimen.text_size_level_small); //数值字体 + private int textColorTag = getResources().getColor(R.color.color_f8f8f8); + + private int textSpace = DensityUtils.dp2px(getContext(), 3); //默认的字与其他的间距 + + /** + * 需要计算相关值 + */ + private int oneBarW; //单个宽度,需要计算 + private int YMARK_MAX_WIDTH = DensityUtils.dp2px(getContext(), 30); //Y轴刻度最大值的宽度 + private int XMARK_H, XMARK_ALL_H; //Y轴刻度间距值 + private int topStartPointY; //从左侧开始绘制的X坐标 + private int minTopPointY; //滑动到最右侧时的X坐标 + + private PointF zeroPoint = new PointF(); //柱状图图体圆点坐标 + + /*字体绘制相关*/ + private int XMARK = 1; //X刻度间隔 + private int XMARK_MAX = 1; //X轴刻度最大值(根据设置的数据自动赋值) + + private int heightCoordinate; + private int leadCoordinate; + private int heightTag; + private int leadTag; + + public BarHorizontalChart(Context context) { + this(context, null); + } + + public BarHorizontalChart(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public BarHorizontalChart(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + public void init(Context context, AttributeSet attrs, int defStyleAttr) { + touchEventType = EVENT_Y; + dataList = new ArrayList<>(); + strList = new ArrayList<>(); + } + + /***********************************设置属性set方法**********************************/ + public void setBarNum(int barNum) { + this.barNum = barNum; + } + + public void setXMARK_NUM(int XMARK_NUM) { + this.XMARK_NUM = XMARK_NUM; + } + + public void setBarWidth(int barWidth) { + this.barWidth = barWidth; + } + + public void setBarSpace(int barSpace) { + this.barSpace = barSpace; + } + + public void setBarItemSpace(int barItemSpace) { + this.barItemSpace = barItemSpace; + } + + public void setBarColor(int[] barColor) { + this.barColor = barColor; + } + + public void setTextSizeCoordinate(int textSizeCoordinate) { + this.textSizeCoordinate = textSizeCoordinate; + } + + public void setTextColorCoordinate(int textColorCoordinate) { + this.textColorCoordinate = textColorCoordinate; + } + + public void setTextSizeTag(int textSizeTag) { + this.textSizeTag = textSizeTag; + } + + public void setTextColorTag(int textColorTag) { + this.textColorTag = textColorTag; + } + + public void setTextSpace(int textSpace) { + this.textSpace = textSpace; + } + + /***********************************设置属性set方法over**********************************/ + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + evaluatorByData(); + postInvalidate(); + } + + /***************************************************/ + /** + * 滑动 + */ + @Override + protected void evaluatorFling(float fling) { + LogUtil.i(TAG, "fling = " + fling); + //已经滚动到顶部或者底部 + if (topStartPointY + mMoveLen + fling <= minTopPointY) { + mMoveLen = minTopPointY - topStartPointY; + moveOver = true; + if (null != touchAnim && touchAnim.isRunning()) { + touchAnim.cancel(); + } + } else if (topStartPointY + mMoveLen + fling >= topStartPointY) { + mMoveLen = 0; + moveOver = true; + if (null != touchAnim && touchAnim.isRunning()) { + touchAnim.cancel(); + } + } else { + moveOver = false; + mMoveLen += fling; + } + } + /***************************************************/ + + /** + * 设置数据 + * + * @param dataList 柱状图数据 + * @param strYList Y轴坐标数据 + */ + public void setData(List> dataList, List strYList) { + this.strList.clear(); + this.dataList.clear(); + if (dataList != null) { + this.dataList.addAll(dataList); + } + if (strYList != null) { + this.strList.addAll(strYList); + } + if (rectChart != null) { + evaluatorByData(); + startDraw = false; + invalidate(); + } + } + + /** + * 设置数据后,计算相关值 + */ + private void evaluatorByData() { + total = 0; + //三种字体计算 + paintLabel.setTextSize(textSizeCoordinate); + heightCoordinate = (int) FontUtil.getFontHeight(paintLabel); + leadCoordinate = (int) FontUtil.getFontLeading(paintLabel); + paintLabel.setTextSize(textSizeTag); + heightTag = (int) FontUtil.getFontHeight(paintLabel); + leadTag = (int) FontUtil.getFontLeading(paintLabel); + //zeroPoint坐标 + if (strList != null && strList.size() > 0) { + YMARK_MAX_WIDTH = 0; + paintLabel.setTextSize(textSizeCoordinate); + for (String xStr : strList) { + int tw = (int) FontUtil.getFontlength(paintLabel, xStr); + YMARK_MAX_WIDTH = tw > YMARK_MAX_WIDTH ? tw : YMARK_MAX_WIDTH; + } + } + zeroPoint.x = rectChart.left + YMARK_MAX_WIDTH + textSpace; + zeroPoint.y = heightCoordinate + textSpace; + + /*计算X刻度最大值*/ + XMARK_MAX = 1; + for (List list : dataList) { + for (BarBean bean : list) { + total += bean.getNum(); + XMARK_MAX = (int) bean.getNum() > XMARK_MAX ? (int) bean.getNum() : XMARK_MAX; + } + } + + LogUtil.i(TAG, "真实XMARK_MAX=" + XMARK_MAX); + if (XMARK_MAX <= 5) { + XMARK_MAX = 5; + } + XMARK = XMARK_MAX / XMARK_NUM + 1; + + int MARK = (Integer.parseInt((XMARK + "").substring(0, 1)) + 1); + + if ((XMARK + "").length() == 1) { + //XMARK = 1、2、5、10 + XMARK = (XMARK == 3 || XMARK == 4 || XMARK == 6 || XMARK == 7 || XMARK == 8 || XMARK == 9) ? ((XMARK == 3 || XMARK == 4) ? 5 + : 10) : XMARK; + } else if ((XMARK + "").length() == 2) { + XMARK = MARK * 10; + } else if ((XMARK + "").length() == 3) { + XMARK = MARK * 100; + } else if ((XMARK + "").length() == 4) { + XMARK = MARK * 1000; + } else if ((XMARK + "").length() == 5) { + XMARK = MARK * 10000; + } else if ((XMARK + "").length() == 6) { + XMARK = MARK * 100000; + } + XMARK_MAX = XMARK * XMARK_NUM; + LogUtil.i(TAG, "计算XMARK_MAX=" + XMARK_MAX + " XMARK=" + XMARK); + + //Y轴刻度间距值 + XMARK_ALL_H = (int) (rectChart.right - zeroPoint.x); + XMARK_H = (int) ((float) XMARK_ALL_H / XMARK_NUM); + + //单份柱子(包含多个及其间距)宽度 + oneBarW = (barWidth * barNum) + (barSpace * (barNum - 1)); + + topStartPointY = (int) zeroPoint.y + barItemSpace / 2; //从左侧开始绘制的X坐标 + + int allW = (oneBarW + barItemSpace) * dataList.size(); //每份柱子宽度+item间距(其中包含第一个item左边和最后一个item右边的半份间距) + int contentW = (int) (rectChart.bottom - zeroPoint.y); + touchEnable = allW > contentW; + + if (touchEnable) { + //超出总宽度了 + minTopPointY = -allW + (int) (rectChart.bottom - topStartPointY - barItemSpace); + } + + LogUtil.w(TAG, "柱状图表宽高:" + getMeasuredWidth() + "*" + getMeasuredHeight() + + " 图表范围" + rectChart + " 圆点坐标zeroPoint=" + zeroPoint); + + } + + /** + * 绘制图表基本框架 + */ + @Override + public void drawDefult(Canvas canvas) { + paint.setStyle(Paint.Style.FILL); + paint.setStrokeWidth(lineWidth); + paint.setColor(defColor); + + // canvas.drawLine(zeroPoint.x, zeroPoint.y, rectChart.right, zeroPoint.y, paint); + if (touchEnable) { + //超出高度了 + // canvas.drawLine(zeroPoint.x, zeroPoint.y,zeroPoint.x , rectChart.bottom, paint); + } else { + // canvas.drawLine(zeroPoint.x, zeroPoint.y,zeroPoint.x , zeroPoint.y+(oneBarW+barItemSpace)*dataList.size(), paint); + } + } + + /** + * 绘制debug辅助线 + */ + @Override + public void drawDebug(Canvas canvas) { + super.drawDebug(canvas); + } + + /** + * 绘制图表 + */ + @Override + public void drawChart(Canvas canvas) { + + int topStart = topStartPointY + mMoveLen; + + // LogUtil.i(TAG, "leftStart:"+leftStart+" zezeroPoint"+zeroPoint+" barItemSpace="+barItemSpace+" + // barWidth="+barWidth +" oneBarW="+oneBarW); + + paint.setStyle(Paint.Style.FILL); + LogUtil.w(TAG, ""); + + for (int i = 0; i < dataList.size(); i++) { + String str = strList.get(i); + List list = dataList.get(i); + //柱子开始绘制的Y坐标 + int topY = topStart + (oneBarW + barItemSpace) * i; + //绘制X刻度 + paintLabel.setTextSize(textSizeCoordinate); + paintLabel.setColor(textColorCoordinate); + float tw = FontUtil.getFontlength(paintLabel, str); + canvas.drawText(str, zeroPoint.x - textSpace - tw, topY + oneBarW / 2 - heightCoordinate / 2 + leadCoordinate, paintLabel); + + //绘制辅助线 + // paint.setStrokeWidth(0.5f); + // paint.setColor(defColor); + // canvas.drawLine(zeroPoint.x, topY-15, rectChart.right, topY-15, paint); + + paintLabel.setTextSize(textSizeTag); + paintLabel.setColor(textColorTag); + for (int j = 0; j < list.size(); j++) { + BarBean bean = list.get(j); + + // //绘制辅助线 + // paint.setStrokeWidth(0.5f); + // paint.setColor(defColor); + // canvas.drawLine(zeroPoint.x, topY+barWidth/2, rectChart.right, topY+barWidth/2, paint); + + //绘制柱子 + paint.setColor(barColor[j]); + float right = (zeroPoint.x + XMARK_ALL_H * (bean.getNum() / XMARK_MAX) * animPro); + RectF br = new RectF(zeroPoint.x, topY, right, topY + barWidth); + canvas.drawRect(br, paint); + + //绘制柱子占比 + str = (int) bean.getNum() + ""; + canvas.drawText(str, right + textSpace, topY + barWidth / 2 - heightTag / 2 + leadTag, paintLabel); + + // LogUtil.d(TAG, "绘制bar:"+(br)+" "+getMeasuredWidth()+"*"+getMeasuredHeight()); + topY += (barWidth + barSpace); + lastY = topY; + } + + //绘制辅助线 + // paint.setStrokeWidth(0.5f); + // paint.setColor(defColor); + // canvas.drawLine(zeroPoint.x, topY-barSpace+15, rectChart.right, topY-barSpace+15, paint); + + } + + drawYmark(canvas); + } + + private int lastY; + + private void drawYmark(Canvas canvas) { + //遮盖超出的柱状 + paint.setStyle(Paint.Style.FILL); + paint.setColor(backColor); + canvas.drawRect(new RectF(0, 0, rectChart.right, zeroPoint.y - lineWidth), paint); + canvas.drawRect(new RectF(0, rectChart.bottom, rectChart.right, getMeasuredHeight()), paint); + + paintLabel.setTextSize(textSizeCoordinate); + paintLabel.setColor(textColorCoordinate); + for (int i = 0; i <= XMARK_MAX / XMARK; i++) { + //绘制X刻度 + String textX = (XMARK * i) + ""; + float tw = FontUtil.getFontlength(paintLabel, textX); + // canvas.drawText(textX, (int)(zeroPoint.x + (i*XMARK_H) - tw/2), zeroPoint + // .y-textSpace-heightCoordinate+leadCoordinate,paintLabel); + canvas.drawText(textX, (int) (zeroPoint.x + (i * XMARK_H) - tw / 2), lastY + textSpace + heightCoordinate, paintLabel); + } + } + + private float animPro; //动画计算的占比数量 + + /** + * 创建动画 + */ + @Override + protected ValueAnimator initAnim() { + if (dataList.size() > 0) { + ValueAnimator anim = ValueAnimator.ofObject(new AngleEvaluator(), 0f, 1f); + anim.setInterpolator(new AccelerateDecelerateInterpolator()); + return anim; + } + return null; + } + + /** + * 动画值变化之后计算数据 + */ + @Override + protected void evaluatorData(ValueAnimator animation) { + animPro = (float) animation.getAnimatedValue(); + } + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/barchart/BarVerticalChart.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/barchart/BarVerticalChart.java new file mode 100644 index 0000000..14747ea --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/barchart/BarVerticalChart.java @@ -0,0 +1,539 @@ +package com.tairui.gov_affairs_cloud.widget.charts.barchart; + +import static com.tairui.gov_affairs_cloud.widget.charts.BaseChart.TOUCH_EVENT_TYPE.EVENT_X; + +import java.util.ArrayList; +import java.util.List; + +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.util.DensityUtils; +import com.tairui.gov_affairs_cloud.util.FontUtil; +import com.tairui.gov_affairs_cloud.util.LogUtil; +import com.tairui.gov_affairs_cloud.widget.charts.BaseChart; +import com.tairui.gov_affairs_cloud.widget.charts.anim.AngleEvaluator; +import com.tairui.gov_affairs_cloud.widget.charts.bean.BarBean; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PointF; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.animation.AccelerateDecelerateInterpolator; + +/** + * autour : openXu + * date : 2017/7/24 10:46 + * className : BarVerticalChart + * version : 1.0 + * description : 竖向(柱子竖直) 柱状图,支持多柱 + */ +public class BarVerticalChart extends BaseChart { + + private List> dataList; + private List strList; + + /** + * 可以设置的属性 + */ + + private boolean showLable = true; //是否显示下面的lable + + private boolean showEnd = true; //当数据超出一屏宽度时,实现最后的数据 + + private int barNum = 2; //柱子数量 + private int YMARK_NUM = 5; //Y轴刻度数量 + + private int barWidth = DensityUtils.dp2px(getContext(), 15); //柱宽度 + private int barSpace = DensityUtils.dp2px(getContext(), 1); //双柱间的间距 + private int barItemSpace = DensityUtils.dp2px(getContext(), 25);//一组柱之间的间距 + private int[] barColor = new int[]{Color.BLUE, Color.YELLOW}; //柱颜色 + + private int rectW = DensityUtils.dp2px(getContext(), 10); //lable矩形宽高 + private int rectH = DensityUtils.dp2px(getContext(), 10); + + private int textSizeCoordinate = (int) getResources().getDimension(R.dimen.text_size_level_small); //坐标文字大小 + private int textColorCoordinate = getResources().getColor(R.color.text_color_light_gray); + private int textSizeTag = (int) getResources().getDimension(R.dimen.text_size_level_small); //数值字体 + private int textColorTag = getResources().getColor(R.color.text_color_light_gray); + private int textSizeLable = (int) getResources().getDimension(R.dimen.text_size_level_small); //lable字体 + private int textColorLable = getResources().getColor(R.color.text_color_light_gray); + + private int textSpace = DensityUtils.dp2px(getContext(), 3); //默认的字与其他的间距 + private int textLableSpace = DensityUtils.dp2px(getContext(), 10); //默认的lable字与其他的间距 + private int lableItemSpace = DensityUtils.dp2px(getContext(), 30); //默认的lable字与其他的间距 + private int lableTopSpace = DensityUtils.dp2px(getContext(), 20); //默认的lable字与其他的间距 + + /** + * 需要计算相关值 + */ + private int oneBarW; //单个宽度,需要计算 + private int YMARK_MAX_WIDTH; //Y轴刻度最大值的宽度 + private int YMARK_H, YMARK_ALL_H; //Y轴刻度间距值 + private int leftStartPointX; //从左侧开始绘制的X坐标 + private int minLeftPointX; //滑动到最右侧时的X坐标 + + private PointF zeroPoint = new PointF(); //柱状图图体圆点坐标 + + private RectF lableRect; + + /*字体绘制相关*/ + private int YMARK = 1; //Y轴刻度最大值(根据设置的数据自动赋值) + private int YMARK_MAX = 1; //Y轴刻度最大值(根据设置的数据自动赋值) + + private int heightCoordinate; + private int leadCoordinate; + private int heightTag; + private int leadTag; + private int heightLable; + private int leadLable; + private float animPro; //动画计算的占比数量 + + public BarVerticalChart(Context context) { + this(context, null); + } + + public BarVerticalChart(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public BarVerticalChart(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + public void init(Context context, AttributeSet attrs, int defStyleAttr) { + touchEventType = EVENT_X; + dataList = new ArrayList<>(); + strList = new ArrayList<>(); + } + + public void setShowEnd(boolean showEnd) { + this.showEnd = showEnd; + } + + /***********************************设置属性set方法over**********************************/ + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + evaluatorByData(); + postInvalidate(); + } + + /** + * 设置数据后,计算相关值 + */ + private void evaluatorByData() { + total = 0; + //三种字体计算 + paintLabel.setTextSize(textSizeCoordinate); + heightCoordinate = (int) FontUtil.getFontHeight(paintLabel); + leadCoordinate = (int) FontUtil.getFontLeading(paintLabel); + paintLabel.setTextSize(textSizeTag); + heightTag = (int) FontUtil.getFontHeight(paintLabel); + leadTag = (int) FontUtil.getFontLeading(paintLabel); + paintLabel.setTextSize(textSizeLable); + heightLable = (int) FontUtil.getFontHeight(paintLabel); + leadLable = (int) FontUtil.getFontLeading(paintLabel); + //下方lable范围计算 + int lableH = 0; + if (showLable) { + lableH = (heightLable > rectH ? heightLable : rectH) + lableTopSpace; + lableRect = new RectF(rectChart.left, getMeasuredHeight() - getPaddingBottom() - lableH, + rectChart.right, rectChart.bottom); + } + //Y轴开始绘制的坐标 = 控件高度-padingB-lable高度-X轴刻度字高度-X刻度间距 + zeroPoint.y = getMeasuredHeight() - getPaddingBottom() - lableH - heightCoordinate - textSpace; + + LogUtil.w(TAG, "lableRect:" + lableRect + " lableH=" + lableH + " heightCoordinate=" + heightCoordinate + " textSpace=" + textSpace); + YMARK_MAX = 1; + /*计算Y刻度最大值*/ + for (List list : dataList) { + for (BarBean bean : list) { + total += bean.getNum(); + YMARK_MAX = (int) bean.getNum() > YMARK_MAX ? (int) bean.getNum() : YMARK_MAX; + } + } + LogUtil.i(TAG, "真实YMARK_MAX=" + YMARK_MAX); + if (YMARK_MAX <= 5) + YMARK_MAX = 5; + YMARK = YMARK_MAX / YMARK_NUM + 1; + + int MARK = (Integer.parseInt((YMARK + "").substring(0, 1)) + 1); + + if ((YMARK + "").length() == 1) { + //YMARK = 1、2、5、10 + YMARK = (YMARK == 3 || YMARK == 4 || YMARK == 6 || YMARK == 7 || YMARK == 8 || YMARK == 9) ? ((YMARK == 3 || YMARK == 4) ? 5 : 10) : YMARK; + } else if ((YMARK + "").length() == 2) { + YMARK = MARK * 10; + } else if ((YMARK + "").length() == 3) { + YMARK = MARK * 100; + } else if ((YMARK + "").length() == 4) { + YMARK = MARK * 1000; + } else if ((YMARK + "").length() == 5) { + YMARK = MARK * 10000; + } else if ((YMARK + "").length() == 6) { + YMARK = MARK * 100000; + } + YMARK_MAX = YMARK * YMARK_NUM; + + LogUtil.i(TAG, "计算YMARK_MAX=" + YMARK_MAX + " YMARK=" + YMARK); + + //Y轴刻度间距值 + YMARK_ALL_H = (int) (zeroPoint.y - getPaddingTop() - heightCoordinate); + YMARK_H = (int) ((float) YMARK_ALL_H / YMARK_NUM); + + //单份柱子(包含多个及其间距)宽度 + oneBarW = (barWidth * barNum) + (barSpace * (barNum - 1)); + + int allW = (oneBarW + barItemSpace) * dataList.size(); //每份柱子宽度+item间距(其中包含第一个item左边和最后一个item右边的半份间距) + paintLabel.setTextSize(textSizeCoordinate); + if(drawLine){ + YMARK_MAX_WIDTH = (int) FontUtil.getFontlength(paintLabel, YMARK_MAX + ""); + }else{ + YMARK_MAX_WIDTH = 0; + } + + int contentW = (int) (rectChart.right - rectChart.left - YMARK_MAX_WIDTH - textSpace); + touchEnable = allW > contentW; + + zeroPoint.x = (int) rectChart.left + YMARK_MAX_WIDTH + textSpace; + leftStartPointX = (int) zeroPoint.x + barItemSpace / 2; //从左侧开始绘制的X坐标 + + if (touchEnable) { + //超出总宽度了 + minLeftPointX = -allW + (int) rectChart.right; + mMoveLen = showEnd?(minLeftPointX - leftStartPointX):0; + } else { + minLeftPointX = 0; + mMoveLen = 0; + } + + LogUtil.w(TAG, "柱状图表宽高:" + getMeasuredWidth() + "*" + getMeasuredHeight() + + " 图表范围" + rectChart + " 圆点坐标zeroPoint=" + zeroPoint); + LogUtil.w(TAG, "YMARK_MAX=" + YMARK_MAX + " YMARK=" + YMARK + " YMARK_H=" + YMARK_H + " YMARK_MAX_WIDTH=" + YMARK_MAX_WIDTH); + LogUtil.w(TAG, "minLeftPointX=" + minLeftPointX + " mMoveLen=" + mMoveLen + " leftStartPointX=" + leftStartPointX); + } + + /** + * 绘制图表基本框架 + */ + @Override + public void drawDefult(Canvas canvas) { + paint.setStyle(Paint.Style.FILL); + paint.setStrokeWidth(lineWidth); + paint.setColor(defColor); + //float startX, float startY, float stopX, float stopY + for (int i = 0; i <= YMARK_MAX / YMARK; i++) { + //绘制横向X轴刻度 + float startX = zeroPoint.x; + float startY = zeroPoint.y - (i * YMARK_H); + float stopX = rectChart.right; + float stopY = startY; + if (drawLine) { + canvas.drawLine(startX, startY, stopX, stopY, paint); + } +// 绘制最下面的基线 + if(drawBottomLine&&i==0){ + canvas.drawLine(startX, startY, stopX, stopY, paint); + } + + +// LogUtil.w(TAG, "绘制直线start="+startX+"*"+startY+" stop="+stopX+"*"+stopY); + + //绘制Y刻度 +// paintLabel.setTextSize(textSizeCoordinate); +// String textY = (YMARK*i)+""; +// float tw = FontUtil.getFontlength(paintLabel, textY); +// canvas.drawText(textY, getPaddingLeft()+(YMARK_MAX_WIDTH-tw), startY - heightCoordinate/2+leadCoordinate,paintLabel); + } + + //绘制左侧Y轴 + if (drawLine) { + canvas.drawLine(zeroPoint.x + lineWidth / 2, zeroPoint.y, zeroPoint.x + lineWidth / 2, getPaddingTop(), paint); + } + + if (showLable) { + //绘制lable + List lableList = new ArrayList<>(); + if (dataList.size() > 0) { + for (BarBean bean : dataList.get(0)) { + lableList.add(bean.getName()); + } + } + + paintLabel.setTextSize(textSizeLable); + paintLabel.setColor(textColorLable); + if (lableList != null && lableList.size() > 0) { + int lableAllW = 0; + for (int i = 0; i < lableList.size(); i++) { + lableAllW += (rectW + textLableSpace + FontUtil.getFontlength(paintLabel, lableList.get(i))); + } + lableAllW += (lableItemSpace * lableList.size() - 1); + int lableStart = 0; + if (lableAllW > ((int) (lableRect.right - lableRect.left))) { + //超过了,从left开始画 + lableStart = (int) lableRect.left; + } else { + //没超过,话中间 + lableStart = (int) (lableRect.left + ((lableRect.right - lableRect.left) / 2 - lableAllW / 2)); + } + int left = lableStart; + + for (int i = 0; i < lableList.size(); i++) { + String lable = lableList.get(i); + int tw = (int) FontUtil.getFontlength(paintLabel, lable); + paint.setColor(barColor[i]); + + float rectTop = lableRect.bottom - rectH; + RectF rect = new RectF(left, rectTop, left + rectW, rectTop + rectH); + canvas.drawRect(rect, paint); + + left += (rectW + textLableSpace); + + rectTop = rectTop + rectH / 2 - heightLable / 2 + leadLable; + canvas.drawText(lable, left, rectTop, paintLabel); + + left += (tw + lableItemSpace); + } + } + } + + } + // 是否绘制最基础的线 + public void setBaseLineAndText(boolean drawLine) { + this.drawLine = drawLine; + } + + + // 是否绘制最下面的基线 + public void setBottomLine(boolean drawBottomLine) { + this.drawBottomLine = drawBottomLine; + } + + + /** + * 绘制debug辅助线 + */ + @Override + public void drawDebug(Canvas canvas) { + super.drawDebug(canvas); + paint.setStyle(Paint.Style.STROKE);//设置空心 + paint.setStrokeWidth(lineWidth); + paint.setColor(Color.BLACK); + canvas.drawRect(lableRect, paint); + } + + /** + * 绘制图表 + */ + @Override + public void drawChart(Canvas canvas) { + + int leftStart = leftStartPointX + mMoveLen; + +// LogUtil.i(TAG, "leftStart:"+leftStart+" zezeroPoint"+zeroPoint+" barItemSpace="+barItemSpace+" barWidth="+barWidth +" oneBarW="+oneBarW); + + paint.setStyle(Paint.Style.FILL); + LogUtil.w(TAG, ""); + + for (int i = 0; i < dataList.size(); i++) { + String str = strList.get(i); + List list = dataList.get(i); + //柱子开始绘制的X坐标 + int leftX = leftStart + (oneBarW + barItemSpace) * i; + //绘制X刻度 + paintLabel.setTextSize(textSizeCoordinate); + paintLabel.setColor(textColorCoordinate); + float tw = FontUtil.getFontlength(paintLabel, str); + canvas.drawText(str, leftX + oneBarW / 2 - tw / 2, zeroPoint.y + textSpace + leadCoordinate, paintLabel); +// LogUtil.i(TAG, "绘制X刻度:leftX="+leftX +" "+(leftX + oneBarW/2-tw/2)+"*"+(zeroPoint.y+textSpace + leadCoordinate)); +// LogUtil.i(TAG, "leftStartPointX="+leftStartPointX+" leftStart="+leftStart+ " oneBarW="+oneBarW +" barWidth="+barWidth+" barSpace="+barSpace); + paintLabel.setTextSize(textSizeTag); + paintLabel.setColor(textColorTag); + for (int j = 0; j < list.size(); j++) { + BarBean bean = list.get(j); + paint.setColor(barColor[j]); + float top = (zeroPoint.y - YMARK_ALL_H * (bean.getNum() / YMARK_MAX) * animPro); + RectF br = new RectF(leftX, top, leftX + barWidth, zeroPoint.y); + canvas.drawRect(br, paint); + + str = (int) bean.getNum() + ""; + tw = FontUtil.getFontlength(paintLabel, str); + canvas.drawText(str, leftX + barWidth / 2 - tw / 2, top - textSpace - heightTag + leadTag, paintLabel); + +// LogUtil.d(TAG, "绘制bar:"+(br)+" "+getMeasuredWidth()+"*"+getMeasuredHeight()); + leftX += (barWidth + barSpace); + } + } + if (drawLine) { + drawYmark(canvas); + } + + } + + private void drawYmark(Canvas canvas) { + //遮盖超出的柱状 + paint.setStyle(Paint.Style.FILL); + paint.setColor(backColor); + canvas.drawRect(new RectF(0, 0, zeroPoint.x, lableRect.top), paint); + canvas.drawRect(new RectF(rectChart.right, 0, getMeasuredWidth(), lableRect.top), paint); +// LogUtil.d(TAG, "遮盖超出的柱状:"+new RectF(0,0,zeroPoint.x, lableRect.top)); +// LogUtil.d(TAG, "遮盖超出的柱状:"+new RectF(rectChart.right,0,getMeasuredWidth(), lableRect.top)); + + paintLabel.setTextSize(textSizeCoordinate); + paintLabel.setColor(textColorCoordinate); + for (int i = 0; i <= YMARK_MAX / YMARK; i++) { + //绘制Y刻度 + String textY = (YMARK * i) + ""; + float tw = FontUtil.getFontlength(paintLabel, textY); + canvas.drawText(textY, getPaddingLeft() + (YMARK_MAX_WIDTH - tw), zeroPoint.y - (i * YMARK_H) - heightCoordinate / 2 + leadCoordinate, paintLabel); + } + } + + /** + * 创建动画 + */ + @Override + protected ValueAnimator initAnim() { + if (dataList.size() > 0) { + ValueAnimator anim = ValueAnimator.ofObject(new AngleEvaluator(), 0f, 1f); + anim.setInterpolator(new AccelerateDecelerateInterpolator()); + return anim; + } + return null; + } + + /** + * 动画值变化之后计算数据 + */ + @Override + protected void evaluatorData(ValueAnimator animation) { + animPro = (float) animation.getAnimatedValue(); + } + + /***************************************************/ + + @Override + protected void evaluatorFling(float fling) { + LogUtil.i(TAG, "fling = " + fling); + if (leftStartPointX + mMoveLen + fling <= minLeftPointX) { + //最右侧 + mMoveLen = minLeftPointX - leftStartPointX; + if (null != touchAnim && touchAnim.isRunning()) + touchAnim.cancel(); + } else if (leftStartPointX + mMoveLen + fling >= leftStartPointX) { + //最左侧 + mMoveLen = 0; + if (null != touchAnim && touchAnim.isRunning()) + touchAnim.cancel(); + } else { + mMoveLen += fling; + } + } + + /***********************************设置属性set方法**********************************/ + public void setRectW(int rectW) { + this.rectW = rectW; + } + + public void setRectH(int rectH) { + this.rectH = rectH; + } + + public void setShowLable(boolean showLable) { + this.showLable = showLable; + } + + public void setBarNum(int barNum) { + this.barNum = barNum; + } + + public void setYMARK_NUM(int YMARK_NUM) { + this.YMARK_NUM = YMARK_NUM; + } + + public void setBarWidth(int barWidth) { + this.barWidth = barWidth; + } + + public void setBarSpace(int barSpace) { + this.barSpace = barSpace; + } + + public void setBarItemSpace(int barItemSpace) { + this.barItemSpace = barItemSpace; + } + + public void setBarColor(int[] barColor) { + this.barColor = barColor; + } + + public void setTextSizeCoordinate(int textSizeCoordinate) { + this.textSizeCoordinate = textSizeCoordinate; + } + + public void setTextColorCoordinate(int textColorCoordinate) { + this.textColorCoordinate = textColorCoordinate; + } + + /***************************************************/ + + public void setTextSizeTag(int textSizeTag) { + this.textSizeTag = textSizeTag; + } + + public void setTextColorTag(int textColorTag) { + this.textColorTag = textColorTag; + } + + public void setTextSizeLable(int textSizeLable) { + this.textSizeLable = textSizeLable; + } + + public void setTextColorLable(int textColorLable) { + this.textColorLable = textColorLable; + } + + public void setTextSpace(int textSpace) { + this.textSpace = textSpace; + } + + public void setTextLableSpace(int textLableSpace) { + this.textLableSpace = textLableSpace; + } + + public void setLableItemSpace(int lableItemSpace) { + this.lableItemSpace = lableItemSpace; + } + + public void setLableTopSpace(int lableTopSpace) { + this.lableTopSpace = lableTopSpace; + } + + /** + * 设置数据 + * + * @param dataList 柱状图数据 + * @param strXList X轴坐标数据 + */ + public void setData(List> dataList, List strXList) { + LogUtil.w(TAG, "柱状图设置数据" + dataList); + this.strList.clear(); + this.dataList.clear(); + if (dataList != null) + this.dataList.addAll(dataList); + if (strXList != null) + this.strList.addAll(strXList); + if (rectChart!=null) { + evaluatorByData(); + startDraw = false; + invalidate(); + } + } + + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/bean/BarBean.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/bean/BarBean.java new file mode 100644 index 0000000..53af34e --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/bean/BarBean.java @@ -0,0 +1,69 @@ +package com.tairui.gov_affairs_cloud.widget.charts.bean; + +import android.graphics.RectF; +import android.graphics.Region; + +/** + * autour : openXu + * date : 2017/7/24 11:04 + * className : PieChartBean + * version : 1.0 + * description : 柱状图数据 + */ +public class BarBean { + + private float num; + private String name; + + //bar绘制矩形 + private RectF arcRect; + //触摸相关 + private Region region; //扇形区域--用于判断手指触摸点是否在此范围 + + @Override + public String toString() { + return "BarBean{" + + "num=" + num + + ", name='" + name + '\'' + + '}'; + } + + public BarBean() { + } + + public BarBean(float num, String name) { + this.num = num; + this.name = name; + } + public float getNum() { + return num; + } + + public void setNum(float num) { + this.num = num; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public RectF getArcRect() { + return arcRect; + } + + public void setArcRect(RectF arcRect) { + this.arcRect = arcRect; + } + + public Region getRegion() { + return region; + } + + public void setRegion(Region region) { + this.region = region; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/bean/ChartLable.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/bean/ChartLable.java new file mode 100644 index 0000000..0fd4d33 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/bean/ChartLable.java @@ -0,0 +1,55 @@ +package com.tairui.gov_affairs_cloud.widget.charts.bean; + +/** + * autour : openXu + * date : 2017/10/11 14:08 + * className : ChartLable + * version : 1.0 + * description : 图表lable文字对象,包含文字大小和颜色 + */ +public class ChartLable { + + private String text; + private int textSize; + private int textColor; + + public ChartLable(String text, int textSize, int textColor) { + this.text = text; + this.textSize = textSize; + this.textColor = textColor; + } + public ChartLable() { + } + @Override + public String toString() { + return "ChartLable{" + + "text='" + text + '\'' + + ", textSize=" + textSize + + ", textColor=" + textColor + + '}'; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public int getTextSize() { + return textSize; + } + + public void setTextSize(int textSize) { + this.textSize = textSize; + } + + public int getTextColor() { + return textColor; + } + + public void setTextColor(int textColor) { + this.textColor = textColor; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/bean/PieChartBean.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/bean/PieChartBean.java new file mode 100644 index 0000000..088d584 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/bean/PieChartBean.java @@ -0,0 +1,133 @@ +package com.tairui.gov_affairs_cloud.widget.charts.bean; + +import java.util.List; + +import android.graphics.PointF; +import android.graphics.RectF; +import android.graphics.Region; + +/** + * autour : openXu + * date : 2017/7/24 11:04 + * className : PieChartBean + * version : 1.0 + * description : 饼状图数据 + */ +public class PieChartBean { + + private float num; + private String name; + + //触摸相关 + private Region region; //扇形区域--用于判断手指触摸点是否在此范围 + private RectF rectLable; //矩形区域--用于判断手指触摸点是否在此范围 + //扇形相关 + private RectF arcRect; + private float startAngle; + private float sweepAngle; + //tag线段 + private List tagLinePoints; + private String tagStr; + private PointF tagTextPoint; + +// //右侧lable +// private RectF colorRect; +// private PointF nameTextPoint; +// private PointF perTextPoint; +// private PointF dashPathPointStart; +// private PointF dashPathPointEnd; + + @Override + public String toString() { + return "RoseChartBean{" + + "num=" + num + + ", name='" + name + '\'' + + '}'; + } + + public PieChartBean(float num, String name) { + this.num = num; + this.name = name; + } + + public String getTagStr() { + return tagStr; + } + + public void setTagStr(String tagStr) { + this.tagStr = tagStr; + } + + + public PointF getTagTextPoint() { + return tagTextPoint; + } + + public void setTagTextPoint(PointF tagTextPoint) { + this.tagTextPoint = tagTextPoint; + } + + public List getTagLinePoints() { + return tagLinePoints; + } + + public void setTagLinePoints(List tagLinePoints) { + this.tagLinePoints = tagLinePoints; + } + + public RectF getArcRect() { + return arcRect; + } + + public void setArcRect(RectF arcRect) { + this.arcRect = arcRect; + } + + public float getStartAngle() { + return startAngle; + } + + public void setStartAngle(float startAngle) { + this.startAngle = startAngle; + } + + public float getSweepAngle() { + return sweepAngle; + } + + public void setSweepAngle(float sweepAngle) { + this.sweepAngle = sweepAngle; + } + + public RectF getRectLable() { + return rectLable; + } + + public void setRectLable(RectF rectLable) { + this.rectLable = rectLable; + } + + public Region getRegion() { + return region; + } + + public void setRegion(Region region) { + this.region = region; + } + + public float getNum() { + return num; + } + + public void setNum(float num) { + this.num = num; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/dashboard/DashBoardItem.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/dashboard/DashBoardItem.java new file mode 100644 index 0000000..b69ad7f --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/dashboard/DashBoardItem.java @@ -0,0 +1,67 @@ +package com.tairui.gov_affairs_cloud.widget.charts.dashboard; + +/** + * autour : openXu + * date : 2018/4/20 15:14 + * className : DashBoardItem + * version : 1.0 + * description : 请添加类说明 + */ +public class DashBoardItem { + + private int color; + private String lable; + private float num; + + private float angle; + + public DashBoardItem() { + } + public DashBoardItem(int color, String lable, float num) { + this.color = color; + this.lable = lable; + this.num = num; + } + + @Override + public String toString() { + return "DashBoardItem{" + + "color=" + color + + ", lable='" + lable + '\'' + + ", num=" + num + + ", angle=" + angle + + '}'; + } + + public float getAngle() { + return angle; + } + + public void setAngle(float angle) { + this.angle = angle; + } + + public int getColor() { + return color; + } + + public void setColor(int color) { + this.color = color; + } + + public String getLable() { + return lable; + } + + public void setLable(String lable) { + this.lable = lable; + } + + public float getNum() { + return num; + } + + public void setNum(float num) { + this.num = num; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/dashboard/DashBoardView.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/dashboard/DashBoardView.java new file mode 100644 index 0000000..5b2633f --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/dashboard/DashBoardView.java @@ -0,0 +1,270 @@ +package com.tairui.gov_affairs_cloud.widget.charts.dashboard; + +import java.util.ArrayList; +import java.util.List; + +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.util.DensityUtils; +import com.tairui.gov_affairs_cloud.util.FontUtil; +import com.tairui.gov_affairs_cloud.util.LogUtil; +import com.tairui.gov_affairs_cloud.widget.charts.BaseChart; +import com.tairui.gov_affairs_cloud.widget.charts.anim.AngleEvaluator; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.DashPathEffect; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PathEffect; +import android.graphics.PointF; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.animation.AccelerateDecelerateInterpolator; + + +/** + * autour : openXu + * date : 2018/4/20 15:12 + * className : DashBoardView + * version : 1.0 + * description : 仪表 + */ +public class DashBoardView extends BaseChart { + + private List dataList; + + /**设置的属性*/ + + private int ringWidth = DensityUtils.dp2px(getContext(), 20);//圆环宽度 + + private int textSizeCoordinate = (int)getResources().getDimension(R.dimen.ts_barchart_x); + private int textSizeLable = (int)getResources().getDimension(R.dimen.ts_barchart_lable); + private int textColorCoordinate = getResources().getColor(R.color.text_color_light_gray); + private int textColorLable = getResources().getColor(R.color.text_color_def); + + + private int textXSpace = DensityUtils.dp2px(getContext(), 6); + private int textLableSpace = DensityUtils.dp2px(getContext(), 10); + //小圆圈半径 + private int lableCircleSize = DensityUtils.dp2px(getContext(), 4); + //指针半径 + private int centerPointSize = DensityUtils.dp2px(getContext(), 5); + + /**常量*/ + private final float startAngle = 180; + private final float endAngle = 360; + + /**计算*/ + private PointF arcCenter; + private float arcRaidus; //饼状图半径 + private float tagMaxW; + + + public DashBoardView(Context context) { + super(context, null); + } + public DashBoardView(Context context, AttributeSet attrs) { + super(context, attrs, 0); + } + public DashBoardView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + public void init(Context context, AttributeSet attrs, int defStyleAttr) { + dataList = new ArrayList<>(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + setMeasuredDimension(widthSize, heightSize); + calculatData(); + } + + /***********************************设置属性set方法**********************************/ + public void setData(List dataList) { + this.dataList.clear(); + if(dataList!=null) + this.dataList.addAll(dataList); + calculatData(); + } + private float progress; + private float progressAnim; + public void setPro(float progress){ + this.progress = progress; + invalidate(); + } +/***********************************设置属性set方法over**********************************/ + + public void calculatData() { + total = 0; + float maxLableLength = 0; //lable最长的长度 + paintLabel.setTextSize(textSizeLable); + for(DashBoardItem bean : dataList){ + total += bean.getNum(); + float l = FontUtil.getFontlength(paintLabel, bean.getLable()); + maxLableLength = maxLableLength>l?maxLableLength:l; + } + //计算每个部分的角度 + float allAngle = endAngle - startAngle; + for(DashBoardItem bean : dataList){ + bean.setAngle(allAngle * (bean.getNum()/total*1.0f)); + } + + //lable所占用的宽度 + maxLableLength = maxLableLength + textLableSpace + lableCircleSize * 2; + + int widthSize = getMeasuredWidth(); + int heightSize = getMeasuredHeight(); + + paintLabel.setTextSize(textSizeCoordinate); + float xLableSize = FontUtil.getFontHeight(paint); + + arcCenter = new PointF( + getPaddingLeft()+(widthSize - getPaddingLeft() - maxLableLength -getPaddingRight())/2, + heightSize - xLableSize - textXSpace- getPaddingBottom() + ); + float raidusX = arcCenter.x - getPaddingLeft(); + float raidusY = arcCenter.y - getPaddingTop(); + arcRaidus = raidusX0){ + startDraw = false; + invalidate(); + } + } + + /**绘制图表基本框架*/ + @Override + public void drawDefult(Canvas canvas) { + /* paint.setStyle(Paint.Style.FILL); + paint.setColor(defColor); + canvas.drawCircle(centerPoint.x,centerPoint.y,chartRaidus, paint); + if(ringWidth>0){ //绘制空心圆圈 + paint.setColor(backColor); + canvas.drawCircle(centerPoint.x,centerPoint.y,chartRaidus-ringWidth, paint); + }*/ + } + /**绘制debug辅助线*/ + @Override + public void drawDebug(Canvas canvas) { + super.drawDebug(canvas); + paint.setColor(Color.RED); + canvas.drawRect(rectChart, paint); + } + @Override + public void drawChart(Canvas canvas) { +// paint.setStrokeWidth(ringWidth); + if(null==dataList || dataList.size()<=0) + return; + + paint.setStyle(Paint.Style.FILL);//设置空心 + float angle = startAngle; + + float lableTop = getPaddingTop(); + paintLabel.setTextSize(textSizeLable); + paintLabel.setColor(textColorLable); + float lableLead = FontUtil.getFontLeading(paintLabel); + float lableHeight = FontUtil.getFontHeight(paintLabel); + float lableCrc = (lableHeight - lableCircleSize*2)/2; +// canvas.drawArc(rectChart, 180, 180, false, paint); + for(DashBoardItem bean : dataList){ + paint.setColor(bean.getColor()); + LogUtil.w(TAG, "绘制扇形"+bean); + canvas.drawArc(rectChart, angle, bean.getAngle(), true, paint); + angle += bean.getAngle(); + + //绘制lable + canvas.drawCircle(rectChart.right+lableCircleSize, lableTop+lableCrc+lableCircleSize, lableCircleSize, paint); + canvas.drawText(bean.getLable(), rectChart.right+lableCircleSize*2+textLableSpace, lableTop + lableLead, paintLabel); + lableTop += lableHeight+DensityUtils.dp2px(getContext(),5); + } + + //覆盖 + paint.setColor(Color.WHITE); + canvas.drawCircle(arcCenter.x, arcCenter.y, arcRaidus - ringWidth, paint); + + //绘制x坐标 + paintLabel.setTextSize(textSizeCoordinate); + paintLabel.setColor(textColorCoordinate); + float xLead = FontUtil.getFontLeading(paintLabel); + float xLength = FontUtil.getFontlength(paintLabel, "0"); + + canvas.drawText("0", rectChart.left+(ringWidth-xLength)/2, + arcCenter.y + textXSpace+xLead, paintLabel); + xLength = FontUtil.getFontlength(paintLabel, "0分钟"); + canvas.drawText("0分钟", + rectChart.right-(Math.abs((ringWidth-xLength)/2))-(xLength dataList; + private List lableList; //需要绘制的lable集合 + + /**设置的属性*/ + private boolean showZeroPart = false; //如果某部分占比为0, 是否显示 + private int centerLableSpace; + //圆环宽度,如果值>0,则为空心圆环,内环为白色,可以在内环中绘制字 + private int ringWidth; + private int lineLenth = 0; // 设置为0 + private int outSpace = 0; // 设置为0 + private int textSpace = 0; // 设置为0 + + private PieChartLayout.TAG_TYPE tagType; //TAG展示类型 + private PieChartLayout.TAG_MODUL tagModul; //TAG展示位置 + private int tagTextSize; //tag文字大小 + private int tagTextColor; + + /**计算*/ + private int chartSize; //饼状图大小 + private int chartRaidus; //饼状图半径 + private float tagMaxW; + + private Paint paintSelected; + + //RGB颜色数组 + private int arrColorRgb[][]; + + + public PieChart(Context context) { + super(context, null); + } + public PieChart(Context context, AttributeSet attrs) { + super(context, attrs, 0); + } + public PieChart(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + public void init(Context context, AttributeSet attrs, int defStyleAttr) { + dataList = new ArrayList<>(); + startAngle = -90; //开始的角度 + + paintSelected = new Paint(); + paintSelected.setColor(Color.LTGRAY); + paintSelected.setStyle(Paint.Style.STROKE);//设置空心 + paintSelected.setStrokeWidth(lineWidth*5); + paintSelected.setAntiAlias(true); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + initSome(); + setMeasuredDimension(widthSize, heightSize); + } + + private void initSome(){ + int widthSize = getMeasuredWidth(); + int heightSize = getMeasuredHeight(); + chartSize = widthSize>heightSize?heightSize:widthSize; + // 调整图表半径计算,让图表尽可能大 + chartRaidus = chartSize / 2; + centerPoint = new PointF(widthSize/2, heightSize/2); + if(widthSize dataList, List lableList){ + total = 0; + this.lableList = lableList; + this.dataList.clear(); + if(dataList!=null) + this.dataList.addAll(dataList); + for(PieChartBean bean : this.dataList){ + total += bean.getNum(); + } + if(centerPoint!=null && centerPoint.x>0){ + startDraw = false; + invalidate(); + } + } + /***********************************设置属性set方法over**********************************/ + /**绘制图表基本框架*/ + @Override + public void drawDefult(Canvas canvas) { + paint.setStyle(Paint.Style.FILL); + paint.setColor(defColor); + canvas.drawCircle(centerPoint.x,centerPoint.y,chartRaidus, paint); + if(ringWidth>0){ //绘制空心圆圈 + paint.setColor(backColor); + canvas.drawCircle(centerPoint.x,centerPoint.y,chartRaidus-ringWidth, paint); + } + } + /**绘制debug辅助线*/ + @Override + public void drawDebug(Canvas canvas) { + super.drawDebug(canvas); + canvas.drawCircle(centerPoint.x, centerPoint.y, chartRaidus, paint); + canvas.drawCircle(centerPoint.x, centerPoint.y, chartRaidus+lineLenth, paint); + canvas.drawCircle(centerPoint.x, centerPoint.y, chartRaidus+lineLenth+textSpace, paint); + canvas.drawCircle(centerPoint.x, centerPoint.y, chartRaidus+lineLenth+textSpace+(int)tagMaxW, paint); + canvas.drawCircle(centerPoint.x, centerPoint.y, chartRaidus+lineLenth+textSpace+(int)tagMaxW+outSpace, paint); + } + private int selectedIndex = -1; //被选中的索引 + /**绘制图表*/ + @Override + public void drawChart(Canvas canvas) { + int index = -1; + for(int i = 0; i < dataList.size(); i++){ + PieChartBean bean = dataList.get(i); + if(bean.getNum() == 0){ + if(showZeroPart) + index++; + continue; + } + index++; + paint.setARGB(255, arrColorRgb[index%arrColorRgb.length][0], arrColorRgb[index%arrColorRgb.length][1], arrColorRgb[index%arrColorRgb.length][2]); + paintLabel.setARGB(255, arrColorRgb[index%arrColorRgb.length][0], arrColorRgb[index%arrColorRgb.length][1], arrColorRgb[index%arrColorRgb.length][2]); + + if(selectedIndex == i){ + paint.setTypeface(Typeface.DEFAULT_BOLD); + paintLabel.setTypeface(Typeface.DEFAULT_BOLD); + }else{ + paint.setTypeface(Typeface.DEFAULT); + paintLabel.setTypeface(Typeface.DEFAULT); + } + + /**1、绘制扇形*/ + paint.setStyle(Paint.Style.FILL);//设置实心 + canvas.drawArc(bean.getArcRect(), bean.getStartAngle(), bean.getSweepAngle(), true, paint); + if(selectedIndex == i){ + //被选中的,绘制边界 + paintSelected.setStyle(Paint.Style.STROKE);//设置空心 + canvas.drawArc(bean.getArcRect(), bean.getStartAngle(), bean.getSweepAngle(), true, paintSelected); + } + if(MODUL_CHART == tagModul){ + /**2、绘制直线*/ + List tagLinePoints = bean.getTagLinePoints(); + if (tagLinePoints != null && tagLinePoints.size() > 0) { + for (int p = 1; p < tagLinePoints.size(); p++) { + canvas.drawLine(tagLinePoints.get(p - 1).x, tagLinePoints.get(p - 1).y, + tagLinePoints.get(p).x, tagLinePoints.get(p).y, paint); + } + } + /**3、绘制指示标签*/ + paintLabel.setTextSize(tagTextSize); + if (tagTextColor != 0) { + paintLabel.setColor(tagTextColor); + } + canvas.drawText(bean.getTagStr() + "", bean.getTagTextPoint().x, bean.getTagTextPoint().y, paintLabel); + } + + } + + //绘制中心内圆 + if(ringWidth>0){ + paint.setColor(backColor); + paint.setStyle(Paint.Style.FILL);//设置实心 + canvas.drawCircle(centerPoint.x, centerPoint.y, chartRaidus-ringWidth, paint); + } + + + /**4 绘制中间文字*/ + if(ringWidth>0 && lableList!=null &&lableList.size()>0){ + float textAllHeight = 0; + float textW, textH, textL; + for(ChartLable lable : lableList){ + paintLabel.setTextSize(lable.getTextSize()); + textH = FontUtil.getFontHeight(paintLabel); + textAllHeight += (textH+centerLableSpace); + } + textAllHeight -= centerLableSpace; + int top = (int)(centerPoint.y-textAllHeight/2); + for(ChartLable lable : lableList){ + paintLabel.setColor(lable.getTextColor()); + paintLabel.setTextSize(lable.getTextSize()); + textW = FontUtil.getFontlength(paintLabel, lable.getText()); + textH = FontUtil.getFontHeight(paintLabel); + textL = FontUtil.getFontLeading(paintLabel); + canvas.drawText(lable.getText(), centerPoint.x-textW/2, top + textL, paintLabel); + top += (textH+centerLableSpace); + } + } + + } + /**创建动画*/ + @Override + protected ValueAnimator initAnim() { + anim = ValueAnimator.ofObject(new AngleEvaluator(), 0f, 1.0f); + anim.setInterpolator(new AccelerateDecelerateInterpolator()); + return anim; + } + /**动画值变化之后计算数据*/ + @Override + protected void evaluatorData(ValueAnimator animation) { + float percentage = (float) animation.getAnimatedValue(); + evaluatorData(percentage); + } + + /**计算各种绘制坐标*/ + private void evaluatorData(float animPre){ + paintLabel.setTextSize(tagTextSize); + float tagTextLead = FontUtil.getFontLeading(paintLabel); + float tagTextHeight = FontUtil.getFontHeight(paintLabel); + float oneStartAngle = startAngle; + for(int i = 0; i < dataList.size(); i++) { + PieChartBean bean = dataList.get(i); + /* if(bean.getNum() == 0 && !showZeroPart){ + continue; + }*/ + /**1、绘制扇形*/ + float arcLeft = centerPoint.x - chartRaidus; //扇形半径 + float arcTop = centerPoint.y - chartRaidus; + float arcRight = centerPoint.x + chartRaidus; + float arcBottom = centerPoint.y + chartRaidus; + + // float percentage = 360.0f / total * bean.getNum(); + float percentage = (bean.getNum()==0?0:(360.0f / total * bean.getNum())*animPre); + bean.setArcRect(new RectF(arcLeft, arcTop, arcRight, arcBottom)); + bean.setStartAngle(oneStartAngle); + bean.setSweepAngle(percentage); + + /**2、计算扇形区域*/ + arcLeft = centerPoint.x - chartSize; + arcTop = centerPoint.y - chartSize; + arcRight = centerPoint.x + chartSize; + arcBottom = centerPoint.y + chartSize; + Path allPath = new Path(); + allPath.moveTo(centerPoint.x, centerPoint.y);//添加原始点 + float ovalX = centerPoint.x + (float) (chartRaidus * Math.cos(Math.toRadians(oneStartAngle))); + float ovalY = centerPoint.y + (float) (chartRaidus * Math.sin(Math.toRadians(oneStartAngle))); + allPath.lineTo(ovalX, ovalY); + RectF touchOval = new RectF(arcLeft, arcTop, arcRight, arcBottom); + allPath.addArc(touchOval, oneStartAngle, percentage); + allPath.lineTo(centerPoint.x, centerPoint.y); + allPath.close(); + RectF r = new RectF(); + allPath.computeBounds(r, true); + Region region = new Region(); + region.setPath(allPath, new Region((int) r.left, (int) r.top, (int) r.right, (int) r.bottom)); + bean.setRegion(region); + + if(MODUL_CHART == tagModul) { + /**3、绘制直线*/ + //确定直线的起始和结束的点的位置 + float startX = centerPoint.x + (float) (chartRaidus * Math.cos(Math.toRadians(oneStartAngle + percentage / 2))); + float startY = centerPoint.y + (float) (chartRaidus * Math.sin(Math.toRadians(oneStartAngle + percentage / 2))); + float endX = centerPoint.x + (float) ((chartRaidus + lineLenth - 20) * Math.cos(Math.toRadians(oneStartAngle + percentage / 2))); + float endY = centerPoint.y + (float) ((chartRaidus + lineLenth - 20) * Math.sin(Math.toRadians(oneStartAngle + percentage / 2))); + boolean isRight = true; + float lineAngle = oneStartAngle + percentage / 2; + if (lineAngle > 90 && lineAngle < 270) { + isRight = false; + } + // LogUtil.i(TAG, "直线坐标:start=("+startX+","+startY +") end=("+endX+","+endY+")"+" lineAngle="+lineAngle+" isRight="+isRight); + List tagLinePoints = new ArrayList<>(); + tagLinePoints.add(new PointF(startX, startY)); + tagLinePoints.add(new PointF(endX, endY)); + float textX = isRight ? (endX + 20) : (endX - 20); + tagLinePoints.add(new PointF(textX, endY)); + bean.setTagLinePoints(tagLinePoints); + + /**3、绘制指示标签*/ + String tagText = ""; + paintLabel.setTextSize(tagTextSize); + if (tagType == PieChartLayout.TAG_TYPE.TYPE_NUM) { + tagText = bean.getNum() + ""; + } else if (tagType == PieChartLayout.TAG_TYPE.TYPE_PERCENT) { + DecimalFormat decimalFormat = new DecimalFormat("0.0%"); + tagText = (total==0?"/":decimalFormat.format(((float) bean.getNum() / (float) total))); + } + float textW = FontUtil.getFontlength(paintLabel, tagText); + textX = isRight ? textX + textSpace : (textX - textW - textSpace); + float textY = endY - tagTextHeight / 2 + tagTextLead; + bean.setTagStr(tagText); + bean.setTagTextPoint(new PointF(textX, textY)); + } + + /*开始角度累加*/ + oneStartAngle += percentage; + } + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/piechart/PieChartLableView.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/piechart/PieChartLableView.java new file mode 100644 index 0000000..4f1fe06 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/piechart/PieChartLableView.java @@ -0,0 +1,284 @@ +package com.tairui.gov_affairs_cloud.widget.charts.piechart; + +import static com.tairui.gov_affairs_cloud.widget.charts.BaseChart.TOUCH_EVENT_TYPE.EVENT_Y; +import static com.tairui.gov_affairs_cloud.widget.charts.piechart.PieChartLayout.TAG_MODUL.MODUL_LABLE; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.List; + +import com.tairui.gov_affairs_cloud.util.DensityUtils; +import com.tairui.gov_affairs_cloud.util.FontUtil; +import com.tairui.gov_affairs_cloud.util.LogUtil; +import com.tairui.gov_affairs_cloud.widget.charts.BaseChart; +import com.tairui.gov_affairs_cloud.widget.charts.bean.PieChartBean; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PointF; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.MotionEvent; + +/** + * autour : openXu + * date : 2017/7/24 10:46 + * className : PieChartLableView + * version : 1.0 + * description : 占比饼状图表 + */ +public class PieChartLableView extends BaseChart { + + private List dataList; + + private boolean showZeroPart = false; //如果某部分占比为0, 是否显示 + + protected RectF rectLable; //图表矩形 + private int minTopPointY; //滑动到最上面时的y坐标 + private int top; //绘制的y坐标 + private int oneLableHeight; //右侧标签单个高度,需要计算 + + /**设置的属性*/ + private int rectW; + private int rectH; + private int rectRaidus; //矩形圆角 + private int rectSpace; //右侧标签上下间距 + private int leftSpace; + private int textSize = 90; //文字大小 + private int textColor; + private int arrColorRgb[][]; + + private PieChartLayout.TAG_TYPE tagType; //TAG展示类型 + private PieChartLayout.TAG_MODUL tagModul; //TAG展示位置 + + public PieChartLableView(Context context) { + super(context, null); + } + public PieChartLableView(Context context, AttributeSet attrs) { + super(context, attrs, 0); + } + public PieChartLableView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + public void init(Context context, AttributeSet attrs, int defStyleAttr) { + touchEventType = EVENT_Y; + dataList = new ArrayList<>(); + setClickable(true); + } + /***********************************设置属性set方法**********************************/ + public void setArrColorRgb(int[][] arrColorRgb) { + this.arrColorRgb = arrColorRgb; + } + + public void setTextSize(int textSize) { + this.textSize = textSize; + } + public void setTextColor(int textColor) { + this.textColor = textColor; + } + public void setShowZeroPart(boolean showZeroPart) { + this.showZeroPart = showZeroPart; + } + public void setRectW(int rectW) { + this.rectW = rectW; + } + + public void setRectH(int rectH) { + this.rectH = rectH; + } + + public void setRectRaidus(int rectRaidus) { + this.rectRaidus = rectRaidus; + } + + public void setTagType(PieChartLayout.TAG_TYPE tagType) { + this.tagType = tagType; + } + + public void setTagModul(PieChartLayout.TAG_MODUL tagModul) { + this.tagModul = tagModul; + } + + public void setRectSpace(int rectSpace) { + this.rectSpace = rectSpace; + } + + public void setLeftSpace(int leftSpace) { + this.leftSpace = leftSpace; + } + /***********************************设置属性set方法over**********************************/ + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + centerPoint = new PointF(widthSize/2, heightSize/2); + rectLable = new RectF(0,0,widthSize, heightSize); + setMeasuredDimension(widthSize, heightSize); + evaluatorLable(); + } + + @Override + public void dispatchTouchEvent1(MotionEvent event) { + int move = (int)(event.getY() - lastTouchPoint.y); + if(top + mMoveLen <= minTopPointY){ + if(move<0){ + LogUtil.e(TAG, "已经到最下面了,还往上滑,不行"); + getParent().requestDisallowInterceptTouchEvent(false); + }else{ + getParent().requestDisallowInterceptTouchEvent(true); + } + }else if(top + mMoveLen>=rectSpace){ + if(move>0){ + LogUtil.w(TAG, "已经划到头了,还往下滑,不行"); + getParent().requestDisallowInterceptTouchEvent(false); + }else{ + getParent().requestDisallowInterceptTouchEvent(true); + } + }else{ + //请求所有父控件及祖宗控件不要拦截事件 + getParent().requestDisallowInterceptTouchEvent(true); + LogUtil.i(TAG, "正常请求事件"); + } + } + + @Override + protected void evaluatorFling(float fling) { + if(top + mMoveLen + fling <= minTopPointY){ + mMoveLen = minTopPointY-rectSpace; + }else if(top + mMoveLen+ fling>=rectSpace){ + mMoveLen = 0; + } else{ + mMoveLen += fling; + } + } + + /** + * 设置数据 + */ + public void setData(List dataList){ + this.dataList.clear(); + if(dataList!=null) + this.dataList.addAll(dataList); + evaluatorLable(); + startDraw = false; + invalidate(); + } + /**计算右侧标签相关坐标值*/ + private void evaluatorLable(){ + paintLabel.setTextSize(textSize); + oneLableHeight = (int) FontUtil.getFontHeight(paintLabel); + //字和矩形中高度的较大值 + oneLableHeight = oneLableHeight>rectH?oneLableHeight:rectH; + int allHeight = 0 ; + //总高度 + for(PieChartBean bean : dataList){ + if(bean.getNum() == 0 && !showZeroPart){ + continue; + } + allHeight += oneLableHeight+rectSpace; + } + if(allHeight>0) + allHeight -= rectSpace; + +// int allHeight = (oneLableHeight+rectSpace)*dataList.size() - rectSpace; + int contentH = getMeasuredHeight() - rectSpace*2; + touchEnable = allHeight>contentH; + if(touchEnable){ + //超出总高度了 + top = rectSpace; + minTopPointY = -allHeight - rectSpace + getMeasuredHeight(); + if(debug) + LogUtil.i(TAG, "边界"+minTopPointY+" "+getMeasuredHeight()); + }else{ + top = (getMeasuredHeight()-allHeight)/2; + } + } + + /**绘制图表基本框架*/ + @Override + public void drawDefult(Canvas canvas) { + } + /**绘制debug辅助线*/ + @Override + public void drawDebug(Canvas canvas) { + super.drawDebug(canvas); + } + /**绘制图表*/ + @Override + public void drawChart(Canvas canvas) { + + int topY = top + mMoveLen; + + paintLabel.setTextSize(textSize); + int lableH =(int) FontUtil.getFontHeight(paintLabel); + int lableL =(int) FontUtil.getFontLeading(paintLabel); + + paint.setStyle(Paint.Style.FILL); + + int index = -1; + for(int i = 0; i < dataList.size(); i++){ + PieChartBean bean = dataList.get(i); + if(bean.getNum() == 0 && !showZeroPart){ + continue; + } + index++; + paint.setARGB(255, arrColorRgb[index%arrColorRgb.length][0], arrColorRgb[index%arrColorRgb.length][1], arrColorRgb[index%arrColorRgb.length][2]); + paintLabel.setARGB(255, arrColorRgb[index%arrColorRgb.length][0], arrColorRgb[index%arrColorRgb.length][1], arrColorRgb[index%arrColorRgb.length][2]); + + int rectTop = topY+(oneLableHeight-rectH)/2; + RectF rect = new RectF(leftSpace, rectTop, leftSpace+rectW, rectTop+rectH); + canvas.drawRoundRect(rect, rectRaidus, rectRaidus, paint); + + + if(textColor!=0) { + paintLabel.setColor(textColor); + } + rectTop = topY+(oneLableHeight-lableH)/2; + canvas.drawText(bean.getName(), leftSpace+rectW+leftSpace , rectTop+lableL , paintLabel); + float textW = FontUtil.getFontlength(paintLabel, bean.getName()); + /**5、绘制指示标签*/ + if(MODUL_LABLE == tagModul){ + String tagText = ""; + if (tagType == PieChartLayout.TAG_TYPE.TYPE_NUM) { + tagText = bean.getNum() + ""; + } else if (tagType == PieChartLayout.TAG_TYPE.TYPE_PERCENT) { + DecimalFormat decimalFormat = new DecimalFormat("0.0%"); + tagText = decimalFormat.format(((float) bean.getNum() / (float) total)); + } + float tagW = FontUtil.getFontlength(paintLabel, tagText); + canvas.drawText(tagText, getMeasuredWidth()-tagW- DensityUtils.dp2px(getContext(),3), rectTop+lableL , paintLabel); + + /* DashPathEffect dashPathEffect = new DashPathEffect(new float[]{8,10,8,10}, 0); + paint.setColor(Color.RED); +// paint.setPathEffect(dashPathEffect); + paint.setStrokeWidth(4); + Path path = new Path(); + path.moveTo(leftSpace+rectW+leftSpace+textW, rectTop); + path.lineTo(getMeasuredWidth()-tagW- DensityUtil.dip2px(getContext(),3), rectTop); + LogUtil.i(TAG, "绘制虚线"+path); + canvas.drawPath(path,paint);*/ + } + topY += oneLableHeight + rectSpace; + } + + } + /**创建动画*/ + @Override + protected ValueAnimator initAnim() { + return null; + } + /**动画值变化之后计算数据*/ + @Override + protected void evaluatorData(ValueAnimator animation) { + + } + + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/piechart/PieChartLayout.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/piechart/PieChartLayout.java new file mode 100644 index 0000000..d514b6d --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/piechart/PieChartLayout.java @@ -0,0 +1,291 @@ +package com.tairui.gov_affairs_cloud.widget.charts.piechart; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.util.DensityUtils; +import com.tairui.gov_affairs_cloud.util.LogUtil; +import com.tairui.gov_affairs_cloud.widget.charts.bean.ChartLable; +import com.tairui.gov_affairs_cloud.widget.charts.bean.PieChartBean; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.widget.LinearLayout; + +/** + * autour : openXu + * date : 2017/7/24 10:46 + * className : PieChartLayout + * version : 1.0 + * description : 占比饼状图表 + */ +public class PieChartLayout extends LinearLayout { + + private String TAG = "PieChartLayout"; + + protected boolean isLoading = true; + + protected List dataList; + protected List lableList; + + private PieChart chartView; + /**饼状图设置属性*/ + private boolean showZeroPart = false; //如果某部分占比为0, 是否显示 + private int centerLableSpace = DensityUtils.dp2px(getContext(), 1); //中间文字行距 + //圆环宽度,如果值>0,则为空心圆环,内环为白色,可以在内环中绘制字 + private int ringWidth = DensityUtils.dp2px(getContext(), 20); //圆环宽度 + private int lineLenth = DensityUtils.dp2px(getContext(), 20); //指示线长度 + private int outSpace = DensityUtils.dp2px(getContext(), 0); + private int textSpace = DensityUtils.dp2px(getContext(), 3); //tag指示文字与线的距离 + private int tagTextSize = (int)getResources().getDimension(R.dimen.text_size_level_small); //饼状图占比指示文字大小 + private int tagTextColor = getResources().getColor(R.color.text_color_light_gray); //文字颜色,如果为0,则根据扇形颜色一样; + private TAG_MODUL tagModul = TAG_MODUL.MODUL_LABLE; //TAG展示位置 + private TAG_TYPE tagType = TAG_TYPE.TYPE_NUM; //TAG展示类型 + + + private PieChartLableView lableView; + /**右侧lable设置属性*/ + private int rectW = DensityUtils.dp2px(getContext(), 12); //lable矩形宽高 + private int rectH = DensityUtils.dp2px(getContext(), 6); + private int rectRaidus = 4; //矩形圆角 + private int rectSpace = DensityUtils.dp2px(getContext(), 8); //右侧标签上下间距 + private int leftSpace = DensityUtils.dp2px(getContext(), 5); //右侧标签左右间距 + private int lableTextSize = (int)getResources().getDimension(R.dimen.text_size_level_small); //饼状图占比指示文字大小 + private int lableTextColor = getResources().getColor(R.color.text_color_light_gray); + + + @Override + public boolean dispatchTouchEvent(MotionEvent ev) { + boolean result = super.dispatchTouchEvent(ev); + LogUtil.w(TAG, "dispatchTouchEvent分发事件 "+result); + return result; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + boolean result = super.onInterceptTouchEvent(ev); + LogUtil.e(TAG, "onInterceptTouchEvent拦截事件 "+result); + return result; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + boolean result = super.onTouchEvent(ev); + LogUtil.i(TAG, "onTouchEvent处理事件 "+result); + return result; + } + + //RGB颜色数组 + private int arrColorRgb[][] = { + {0, 122, 255}, // UIColorFromRGB(0xD95F5B), + {255, 78, 61}, // UIColorFromRGB(0x7189E6), + {42, 216, 72}, // UIColorFromRGB(0x5AB9C7), + {255, 164, 35}, // UIColorFromRGB(0xB096D5), + {107, 186, 151}, // UIColorFromRGB(0x6BBA97), + {91, 164, 231}, // UIColorFromRGB(0x5BA4E7), + {220, 170, 97},// UIColorFromRGB(0xDCAA61), + {125, 171, 88},// UIColorFromRGB(0x7DAB58), + {233, 200, 88},// UIColorFromRGB(0xE9C858), + {213, 150, 196},// UIColorFromRGB(0xd596c4) + {220, 127, 104},// UIColorFromRGB(0xDC7F68), + + +// {86, 138, 220}, // UIColorFromRGB(0x568ADC), +// {112, 173, 71}, //UIColorFromRGB(0x70AD47) +// {219, 69, 40}, // UIColorFromRGB(0xDB4528) +// {255, 193, 2}, // UIColorFromRGB(0xFFC102) +// {242, 141, 2}, // UIColorFromRGB(0xF28D02) +// {41, 182, 180}, // UIColorFromRGB(0x29B6B4) +// {187, 107, 201}, // UIColorFromRGB(0xbb6bc9) +// {124, 117, 214}, // UIColorFromRGB(0x7c75d6) + }; + + + /**tag类型*/ + public enum TAG_TYPE{ + TYPE_NUM, //数量 + TYPE_PERCENT, //百分比 + } + public enum TAG_MODUL{ + MODEUL_NULL, //不展示 + MODUL_CHART, //在扇形图上显示tag + MODUL_LABLE, //在lable后面显示tag + } + + public PieChartLayout(Context context) { + this(context, null); + } + public PieChartLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + public PieChartLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + private void init() { + this.dataList = new ArrayList<>(); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + for(int i = 0; i dataList, List lableList){ + this.lableList = lableList; + this.dataList.clear(); + if(dataList!=null){ + try{ + Field filedPer = clazz.getDeclaredField(per); + Field filedName = clazz.getDeclaredField(name); + filedPer.setAccessible(true); + filedName.setAccessible(true); + for(Object obj : dataList){ + String perStr = filedPer.get(obj).toString(); + PieChartBean bean = new PieChartBean(Float.parseFloat(perStr), (String)filedName.get(obj)); + this.dataList.add(bean); + } + }catch (Exception e){ + e.printStackTrace(); + } + } + setConfig(); + } + + + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/rosechart/NightingaleRoseChart.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/rosechart/NightingaleRoseChart.java new file mode 100644 index 0000000..6551386 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/rosechart/NightingaleRoseChart.java @@ -0,0 +1,638 @@ +package com.tairui.gov_affairs_cloud.widget.charts.rosechart; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.util.DensityUtils; +import com.tairui.gov_affairs_cloud.util.FontUtil; +import com.tairui.gov_affairs_cloud.util.LogUtil; +import com.tairui.gov_affairs_cloud.widget.charts.anim.AngleEvaluator; + +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.DashPathEffect; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PathEffect; +import android.graphics.PointF; +import android.graphics.RectF; +import android.graphics.Region; +import android.graphics.Typeface; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.AccelerateDecelerateInterpolator; + +/** + * autour : openXu + * date : 2017/7/24 10:46 + * className : NightingaleRoseChart + * version : 1.0 + * description : 南丁格尔玫瑰图 + */ +public class NightingaleRoseChart extends View { + + private String TAG = "NightingaleRoseChart"; + private int ScrWidth,ScrHeight; + private int backColor = Color.WHITE; + + private PointF centerPoint; //chart中心点坐标 + private int startAngle = -90; //开始的角度 + private int chartRaidusInner = DensityUtils.dp2px(getContext(), 15); //内圈半径 + private int chartRaidusOuter; //最大部分扇形区域半径 + private int outSpace = DensityUtils.dp2px(getContext(), 50); //图表与边界距离 + private int lineLenth = DensityUtils.dp2px(getContext(), 8); + private int lineWidth = 1; //线宽度 + + private RectF rectChart, rectLable; + + private int rightLableTop; + private int oneLableHeight; //右侧标签单个高度 + private int rightRectItemW = DensityUtils.dp2px(getContext(), 16); + private int rightRectItemH = DensityUtils.dp2px(getContext(), 8); + private int rightRectSpace = DensityUtils.dp2px(getContext(), 8); //右侧标签上下间距 + private int textSpace = DensityUtils.dp2px(getContext(), 5); + + private int lableTextSize = (int)getResources().getDimension(R.dimen.text_size_level_mid); //右侧标注字体大小 + private int tagTextSize = (int)getResources().getDimension(R.dimen.text_size_level_small); + + private String nullStr = "暂无数据"; + private List dataList; + private float max; + + private Paint paintArc , paintSelected; + private Paint paintLabel; + private Paint mLinePaint, mlableLinePaint; + + private int selectedIndex = -1; //被选中的索引 + /**正在加载*/ + boolean isLoading = true; + /**是否在图表上显示指示lable*/ + boolean showChartLable = false; + /**是否在图表上显示指示num*/ + boolean showChartNum = true; + /**点击显示数量*/ + boolean showNumTouched = false; + /**右侧显示数量*/ + boolean showRightNum = false; + + //RGB颜色数组 + //#D95F5B红 #7189E6蓝 #5AB9C7蓝1 #B096D5紫 #6BBA97绿1 #DCAA61黄 #7DAB58绿2 #DC7F68橙 + private final int arrColorRgb[][] = { + {113, 137, 230}, // UIColorFromRGB(0xD95F5B), + {217, 95, 91}, // UIColorFromRGB(0x7189E6), + {90, 185, 199}, // UIColorFromRGB(0x5AB9C7), + {170, 150, 213}, // UIColorFromRGB(0xB096D5), + {107, 186, 151}, // UIColorFromRGB(0x6BBA97), + {91, 164, 231}, // UIColorFromRGB(0x5BA4E7), + {220, 170, 97},// UIColorFromRGB(0xDCAA61), + {125, 171, 88},// UIColorFromRGB(0x7DAB58), + {233, 200, 88},// UIColorFromRGB(0xE9C858), + {213, 150, 196},// UIColorFromRGB(0xd596c4) + {220, 127, 104}// UIColorFromRGB(0xDC7F68), + }; + + public void setLoading(boolean loading) { + isLoading = loading; + } + + public void setShowNumTouched(boolean showNumTouched) { + this.showNumTouched = showNumTouched; + } + public void setShowRightNum(boolean showRightNum) { + this.showRightNum = showRightNum; + } + public void setChartRaidusInner(int chartRaidusInner) { + this.chartRaidusInner = DensityUtils.dp2px(getContext(), chartRaidusInner); //内圈半径 + } + + public void setChartRaidusOuter(int chartRaidusOuter) { + this.chartRaidusOuter = DensityUtils.dp2px(getContext(), chartRaidusOuter); //图表与边界距离 + } + + public NightingaleRoseChart(Context context) { + this(context, null); + } + + public NightingaleRoseChart(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public NightingaleRoseChart(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(context, attrs, defStyle); + } + + + public void init(Context context, AttributeSet attrs, int defStyleAttr) { + dataList = new ArrayList<>(); + DisplayMetrics dm = getResources().getDisplayMetrics(); + ScrHeight = dm.heightPixels; + ScrWidth = dm.widthPixels; + + //画笔初始化 + paintArc = new Paint(); + paintArc.setAntiAlias(true); + + paintLabel = new Paint(); + paintLabel.setAntiAlias(true); + + paintSelected = new Paint(); + paintSelected.setColor(Color.LTGRAY); + paintSelected.setStyle(Paint.Style.STROKE);//设置空心 + paintSelected.setStrokeWidth(lineWidth*5); + paintSelected.setAntiAlias(true); + + mLinePaint = new Paint(); + mLinePaint.setStyle(Paint.Style.FILL); + mLinePaint.setStrokeWidth(lineWidth); + mLinePaint.setAntiAlias(true); + + + mlableLinePaint = new Paint(); + mlableLinePaint.setStyle(Paint.Style.STROKE); + mlableLinePaint.setColor(Color.DKGRAY); + mlableLinePaint.setStrokeWidth(3); + // PathEffect是用来控制绘制轮廓(线条)的方式 + // 代码中的float数组,必须是偶数长度,且>=2,指定了多少长度的实线之后再画多少长度的空白 + // .如本代码中,绘制长度5的实线,再绘制长度5的空白,再绘制长度5的实线,再绘制长度5的空白,依次重复.1是偏移量,可以不用理会. + PathEffect effects = new DashPathEffect(new float[]{5,5,5,5},1); + mlableLinePaint.setPathEffect(effects); + + + } + + public void setData(Class clazz, String per, String name, List dataList){ + this.dataList.clear(); + max = 0; + LogUtil.i(TAG, "玫瑰图设置数据"+dataList); + if(dataList!=null){ + try{ + Field filedPer = clazz.getDeclaredField(per); + Field filedName = clazz.getDeclaredField(name); + filedPer.setAccessible(true); + filedName.setAccessible(true); + for(Object obj : dataList){ + String perStr = filedPer.get(obj).toString(); + this.dataList.add(new RoseChartBean(Float.parseFloat(perStr), (String)filedName.get(obj) )); + } + }catch (Exception e){ + e.printStackTrace(); + } + for(RoseChartBean bean : this.dataList){ + max = max>bean.getPer()?max:bean.getPer(); + } + if(getMeasuredHeight()>0){ + evaluatorLable(); + } + } + Log.i(TAG, "玫瑰图设置数据dataList"+this.dataList); + startDraw = false; + invalidate(); + } + + boolean startDraw = false; + public void setData(List dataList){ + this.dataList.clear(); + max = 0; + if(dataList!=null){ + this.dataList.addAll(dataList); + for(RoseChartBean bean : dataList){ + max = max>bean.getPer()?max:bean.getPer(); + } + evaluatorLable(); + } + startDraw = false; + invalidate(); + } + + /**计算右侧标签相关坐标值*/ + private void evaluatorLable(){ + paintLabel.setTextSize(lableTextSize); + oneLableHeight = (int) FontUtil.getFontHeight(paintLabel); + //字和矩形中高度的较大值 + oneLableHeight = oneLableHeight>rightRectItemH?oneLableHeight:rightRectItemH; + + int allHeight = (oneLableHeight+rightRectSpace)*dataList.size() +rightRectSpace; + LogUtil.e(TAG, "测量高度"+getMeasuredHeight()+" allHeight="+allHeight); + if(allHeight>getMeasuredHeight()){ + //超出总高度了 + oneLableHeight = getMeasuredHeight() / ((dataList==null || dataList.size()<=0)?1:dataList.size()); + rightLableTop = -1; + }else{ + rightLableTop = (getMeasuredHeight()-allHeight)/2; + } + } + + public void setShowChartLable(boolean showChartLable) { + this.showChartLable = showChartLable; + } + public void setShowChartNum(boolean showChartNum) { + this.showChartNum = showChartNum; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int width = MeasureSpec.getSize(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + int height; + if (heightMode == MeasureSpec.EXACTLY) { + height = heightSize; + } else { + height = ScrWidth/3 * 2; //3分之2的位置画图,3分1的位置画标注 + } + int chartWidth = width/3*2; + int chartSize = chartWidth>height?height:chartWidth; + //外圈半径=size/2-最大部分lable线长度-边距 + chartRaidusOuter = chartSize/2-lineLenth-outSpace; + centerPoint = new PointF(chartWidth/2, height/2); + + rectChart = new RectF(0,0,chartWidth, height); + rectLable = new RectF(chartWidth,0,width, height); + setMeasuredDimension(width, height); + if(dataList.size()>0){ + evaluatorLable(); + } + LogUtil.i(TAG, "图表总宽高="+width+"*"+height); + LogUtil.i(TAG, "chart宽高="+chartWidth+"*"+height); + LogUtil.i(TAG, "chart直径="+chartSize); + LogUtil.i(TAG, "lineLenth="+lineLenth+" outSpace="+outSpace); + + LogUtil.i(TAG, "chartRaidusOuter="+chartRaidusOuter); + LogUtil.i(TAG, "centerPoint="+centerPoint.x+"*"+ centerPoint.y); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + switch (event.getAction()){ + case MotionEvent.ACTION_DOWN: + PointF point = new PointF(event.getX(),event.getY()); + sureSelectedIndex(point); + break; + case MotionEvent.ACTION_MOVE: + // LogUtil.w(TAG, "长按后的移动时间"); + point = new PointF(event.getX(),event.getY()); + sureSelectedIndex(point); + break; + case MotionEvent.ACTION_UP: +// selectedIndex = -1; + invalidate(); + break; + } + return super.onTouchEvent(event); + } + + private boolean sureSelectedIndex(PointF point){ + for(int i = 0; i < dataList.size(); i++) { + RoseChartBean bean = dataList.get(i); + if(bean.getRegion()!=null && bean.getRegion().contains((int)point.x, (int)point.y)){ +// LogUtil.e(TAG, "在第"+i+"个扇形区域"); + selectedIndex = i; + invalidate(); + return true; + } + if(bean.getRectLable()!=null && bean.getRectLable().contains((int)point.x, (int)point.y)){ +// LogUtil.e(TAG, "在第"+i+"个lable区域"); + selectedIndex = i; + invalidate(); + return true; + } + } + return false; + } + + public void onDraw(Canvas canvas){ + + //画布背景 + canvas.drawColor(backColor); + + if(isLoading){ + paintLabel.setTextSize(lableTextSize); + float NullTextLead = FontUtil.getFontLeading(paintLabel); + float NullTextHeight = FontUtil.getFontHeight(paintLabel); + float textY = centerPoint.y-NullTextHeight/2+NullTextLead; + paintLabel.setColor(getContext().getResources().getColor(R.color.text_color_def)); + canvas.drawText("loading...", centerPoint.x- FontUtil.getFontlength(paintLabel, "loading...")/2, textY, paintLabel); + return; + } + if(dataList==null || dataList.size()<=0) { +// paintArc.setStyle(Paint.Style.STROKE);//设置空心 +// canvas.drawCircle(centerPoint.x, centerPoint.y, chartRaidusOuter, paintArc); + paintLabel.setTextSize(lableTextSize); + float NullTextLead = FontUtil.getFontLeading(paintLabel); + float NullTextHeight = FontUtil.getFontHeight(paintLabel); + float textY = centerPoint.y-NullTextHeight/2+NullTextLead; + canvas.drawText(nullStr, centerPoint.x- FontUtil.getFontlength(paintLabel, nullStr)/2, textY, paintLabel); + return; + } + +// drawDebug(canvas); + + if(!startDraw){ + startDraw = true; + startAnimation(); + }else{ + drawChart(canvas); + } + } + + private void drawDebug(Canvas canvas){ + paintArc.setStyle(Paint.Style.STROKE);//设置空心 + //绘制边界--chart区域 + paintArc.setColor(Color.YELLOW); + canvas.drawRect(rectChart, paintArc); + //绘制边界--标签区域 + paintArc.setColor(Color.RED); + canvas.drawRect(rectLable, paintArc); + //绘制边界--chart圆边界 + paintArc.setColor(Color.BLUE); + canvas.drawCircle(centerPoint.x, centerPoint.y, chartRaidusOuter+outSpace+lineLenth, paintArc); + //绘制边界--chart lable边缘 + paintArc.setColor(Color.GRAY); + //绘制边界--chart 扇形边缘 + canvas.drawCircle(centerPoint.x, centerPoint.y, chartRaidusOuter+lineLenth, paintArc); + paintArc.setColor(Color.LTGRAY); + canvas.drawCircle(centerPoint.x, centerPoint.y, chartRaidusOuter, paintArc); + } + + public int STYLE_1 = 1; + public int STYLE_2 = 2; + private int STYLE = STYLE_2; + public void setAnimStyle(int style){ + STYLE = style; + } + private long duration = 1000; + public void setAnimDuration(long duration){ + this.duration = duration; + } + ValueAnimator anim; + private void startAnimation() { + if(anim!=null){ + anim.cancel(); + } + Log.w(TAG, "开始动画"); + //将百分比转换为扇形半径长度 + float percentage = 360.0f / dataList.size(); + anim = ValueAnimator.ofObject(new AngleEvaluator(), 0f, percentage); + anim.setInterpolator(new AccelerateDecelerateInterpolator()); + anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + float percentage = (float) animation.getAnimatedValue(); + evaluatorData(percentage); + invalidate(); + } + }); + anim.setDuration(duration); + anim.start(); + } + + /** + * 计算各种绘制坐标 + * @param percentage 当前扇形度数 + */ + private void evaluatorData(float percentage){ + paintLabel.setTextSize(tagTextSize); + float chartTextLead = FontUtil.getFontLeading(paintLabel); + float chartTextHeight = FontUtil.getFontHeight(paintLabel); + paintLabel.setTextSize(lableTextSize); + float lableTextLead = FontUtil.getFontLeading(paintLabel); + float lableTextHeight = FontUtil.getFontHeight(paintLabel); + float radius; //每部分扇形半径 + for(int i = 0; i < dataList.size(); i++){ + RoseChartBean bean = dataList.get(i); + /**1、绘制扇形*/ + //将百分比转换为扇区的半径 + radius = chartRaidusInner+(chartRaidusOuter-chartRaidusInner)* (bean.getPer()*1.0f / max*1.0f); + float arcLeft = centerPoint.x - radius; + float arcTop = centerPoint.y - radius ; + float arcRight = centerPoint.x + radius ; + float arcBottom = centerPoint.y + radius ; + + float oneStartAngle = startAngle + i * percentage; + if(STYLE == STYLE_1){ + oneStartAngle = startAngle + i * percentage; + }else{ + //将百分比转换为扇形半径长度 + float partPercentage = 360.0f / dataList.size(); + oneStartAngle = startAngle + i * partPercentage; + } + bean.setArcRect(new RectF(arcLeft ,arcTop, arcRight, arcBottom)); + bean.setStartAngle(oneStartAngle); + bean.setSweepAngle(percentage); + /**计算扇形区域*/ + float Allradius = chartRaidusOuter+ lineLenth + outSpace; + arcLeft = centerPoint.x - Allradius; + arcTop = centerPoint.y - Allradius; + arcRight = centerPoint.x + Allradius; + arcBottom = centerPoint.y + Allradius; + Path allPath = new Path(); + allPath.moveTo(centerPoint.x, centerPoint.y);//添加原始点 + float ovalX = centerPoint.x+(float) (radius* Math.cos(Math.toRadians(oneStartAngle))); + float ovalY = centerPoint.y+(float) (radius* Math.sin(Math.toRadians(oneStartAngle))); + allPath.lineTo(ovalX, ovalY); + RectF touchOval = new RectF(arcLeft, arcTop, arcRight, arcBottom); + allPath.addArc(touchOval, oneStartAngle, percentage); + allPath.lineTo(centerPoint.x, centerPoint.y); + allPath.close(); + RectF r = new RectF(); + allPath.computeBounds(r, true); + Region region = new Region(); + region.setPath(allPath, new Region((int)r.left, (int) r.top, (int) r.right,(int)r.bottom)); + bean.setRegion(region); + + /**2、绘制直线*/ + //确定直线的起始和结束的点的位置 + float startX = centerPoint.x + (float) (radius * Math.cos(Math.toRadians(oneStartAngle + percentage / 2))); + float startY = centerPoint.y + (float) (radius * Math.sin(Math.toRadians(oneStartAngle + percentage / 2))); + float endX = centerPoint.x + (float) ((chartRaidusOuter + lineLenth) * Math.cos(Math.toRadians(oneStartAngle + percentage / 2))); + float endY = centerPoint.y + (float) ((chartRaidusOuter + lineLenth) * Math.sin(Math.toRadians(oneStartAngle + percentage / 2))); + boolean isRight = true; + float lineAngle = startAngle + i * percentage + percentage / 2; + if (lineAngle > 90 && lineAngle < 270) { + isRight = false; + } + +// LogUtil.i(TAG, "直线坐标:start=("+startX+","+startY +") end=("+endX+","+endY+")"+" lineAngle="+lineAngle+" isRight="+isRight); + List tagLinePoints = new ArrayList<>(); + tagLinePoints.add(new PointF(startX, startY)); + tagLinePoints.add(new PointF(endX, endY)); + float textX = isRight ? (endX + 20) : (endX - 20); + tagLinePoints.add(new PointF(textX, endY)); + bean.setTagLinePoints(tagLinePoints); + + /**3、绘制指示标签*/ + paintLabel.setTextSize(tagTextSize); + + String lableText = ""; + if(showChartLable){ + lableText = bean.getName(); + }else if(showChartNum){ + lableText = bean.getPer()+""; + } + if(showNumTouched){ + lableText = bean.getPer()+""; + } + + //标签字体长度 + float textW = FontUtil.getFontlength(paintLabel, lableText); + //字体绘制X坐标 + textX = isRight ? textX : (textX - textW); + float textY = endY - chartTextHeight / 2 + chartTextLead; + bean.setTagTextPoint(new PointF(textX, textY)); + + /**4、绘制右侧item矩形*/ + float rectL, rectT, rectR, centerY, DashPathL; + + if(rightLableTop<0){ + //超出总高度了 + bean.setRectLable(new RectF(rectLable.left, i * oneLableHeight, rectLable.right, (i+1) * oneLableHeight)); + + rectL = rectLable.left+textSpace; + rectT = i * oneLableHeight + (oneLableHeight-rightRectItemH)/2; + rectR = rectL + rightRectItemW; + centerY = i * oneLableHeight + oneLableHeight/2.0f; + RectF colorRect = new RectF(rectL, rectT, rectR, rectT+ rightRectItemH); + bean.setColorRect(colorRect); + }else{ + rectT = rightLableTop +rightRectSpace+ i * (oneLableHeight+rightRectSpace); + bean.setRectLable(new RectF(rectLable.left, rectT, rectLable.right, rectT+oneLableHeight)); + + centerY = rectT + oneLableHeight/2.0f; + + rectL = rectLable.left+textSpace; + rectT = rectT + (oneLableHeight-rightRectItemH)/2; + rectR = rectL + rightRectItemW; + RectF colorRect = new RectF(rectL, rectT, rectR, rectT+ rightRectItemH); + bean.setColorRect(colorRect); + } + + /**5、绘制指示标签*/ + paintLabel.setTextSize(lableTextSize); + //标签字体长度 + textW = FontUtil.getFontlength(paintLabel, bean.getName()); + //字体绘制X坐标 + rectL = rectR+textSpace; + textY = centerY -lableTextHeight/2 +lableTextLead; + bean.setNameTextPoint(new PointF(rectL, textY)); + DashPathL = rectL + textW + textSpace; + + /**6.绘制占比*/ + textW = FontUtil.getFontlength(paintLabel, bean.getPer()+""); + rectL = rectLable.right - textW - textSpace; + bean.setPerTextPoint(new PointF(rectL, textY)); + /**7、绘制虚线*/ + if(DashPathL<(rectL-textSpace)){ + bean.setDashPathPointStart(new PointF(DashPathL, centerY)); + bean.setDashPathPointEnd(new PointF(rectL-textSpace, centerY)); + } + + } + } + private void drawChart(Canvas canvas){ + paintArc.setStyle(Paint.Style.FILL);//设置实心 + + for(int i = 0; i < dataList.size(); i++){ + paintArc.setARGB(255, arrColorRgb[i%arrColorRgb.length][0], arrColorRgb[i%arrColorRgb.length][1], arrColorRgb[i%arrColorRgb.length][2]); + mLinePaint.setARGB(255, arrColorRgb[i%arrColorRgb.length][0], + arrColorRgb[i%arrColorRgb.length][1], arrColorRgb[i%arrColorRgb.length][2]); + paintLabel.setARGB(255, arrColorRgb[i%arrColorRgb.length][0], + arrColorRgb[i%arrColorRgb.length][1], arrColorRgb[i%arrColorRgb.length][2]); + if(selectedIndex == i){ + paintLabel.setTypeface(Typeface.DEFAULT_BOLD); + mLinePaint.setTypeface(Typeface.DEFAULT_BOLD); + }else{ + paintLabel.setTypeface(Typeface.DEFAULT); + mLinePaint.setTypeface(Typeface.DEFAULT); + } + paintLabel.setTextSize(tagTextSize); + + RoseChartBean bean = dataList.get(i); + + /**1、绘制扇形*/ + + canvas.drawArc(bean.getArcRect(), bean.getStartAngle(), bean.getSweepAngle(), true, paintArc); +// canvas.drawPath(allPath,mLinePaint); + if(selectedIndex == i){ + //被选中的,绘制边界 + paintSelected.setStyle(Paint.Style.STROKE);//设置空心 + canvas.drawArc(bean.getArcRect(), bean.getStartAngle(), bean.getSweepAngle(), true, paintSelected); + } + if(showChartLable || showChartNum){ + /**2、绘制直线*/ + List tagLinePoints = bean.getTagLinePoints(); + if (tagLinePoints != null && tagLinePoints.size() > 0) { + for (int p = 1; p < tagLinePoints.size(); p++) { + canvas.drawLine(tagLinePoints.get(p - 1).x, tagLinePoints.get(p - 1).y, + tagLinePoints.get(p).x, tagLinePoints.get(p).y, mLinePaint); + } + } + if(showChartLable){ + /**3、绘制指示标签*/ + canvas.drawText(bean.getName(), bean.getTagTextPoint().x, bean.getTagTextPoint().y, paintLabel); + }else if(showChartNum){ + /**3、绘制指示标签*/ + canvas.drawText(bean.getPer()+"", bean.getTagTextPoint().x, bean.getTagTextPoint().y, paintLabel); + } + + } + + if(showNumTouched && selectedIndex == i) { + /**2、绘制直线*/ + List tagLinePoints = bean.getTagLinePoints(); + if (tagLinePoints != null && tagLinePoints.size() > 0) { + for (int p = 1; p < tagLinePoints.size(); p++) { + canvas.drawLine(tagLinePoints.get(p - 1).x, tagLinePoints.get(p - 1).y, + tagLinePoints.get(p).x, tagLinePoints.get(p).y, mLinePaint); + } + } + /**3、绘制数量*/ + canvas.drawText(bean.getPer()+"", bean.getTagTextPoint().x, bean.getTagTextPoint().y, paintLabel); + LogUtil.i(TAG, "绘制bean="+bean.getName()+" "+bean.getPer()); + } + + + /**4、绘制右侧item矩形*/ + canvas.drawRoundRect(bean.getColorRect(), 8, 8, paintArc);//第二个参数是x半径,第三个参数是y半径 +// LogUtil.i(TAG, "绘制lable矩形"+bean.getColorRect()); + if(selectedIndex == i){ + canvas.drawRoundRect(bean.getColorRect(), 8, 8, paintSelected); + } + + + /**5、绘制指示标签*/ + paintLabel.setTextSize(lableTextSize); + paintLabel.setColor(getContext().getResources().getColor(R.color.text_color_def)); + canvas.drawText(bean.getName(), bean.getNameTextPoint().x, bean.getNameTextPoint().y , paintLabel); + + if(showRightNum){ + /**6.绘制占比*/ + canvas.drawText(bean.getPer()+"", bean.getPerTextPoint().x, bean.getPerTextPoint().y , paintLabel); + /**7、绘制虚线*/ + if(bean.getDashPathPointStart()!=null){ + Path path = new Path(); + path.moveTo(bean.getDashPathPointStart().x,bean.getDashPathPointStart().y); + path.lineTo( bean.getDashPathPointEnd().x,bean.getDashPathPointEnd().y); + canvas.drawPath(path, mlableLinePaint); + } + } + + } + + //绘制中心内圆 + paintArc.setColor(backColor); + canvas.drawCircle(centerPoint.x, centerPoint.y, chartRaidusInner, paintArc); + } + + + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/rosechart/RoseChartBean.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/rosechart/RoseChartBean.java new file mode 100644 index 0000000..7eea359 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/charts/rosechart/RoseChartBean.java @@ -0,0 +1,162 @@ +package com.tairui.gov_affairs_cloud.widget.charts.rosechart; + +import java.util.List; + +import android.graphics.PointF; +import android.graphics.RectF; +import android.graphics.Region; + +/** + * autour : openXu + * date : 2017/7/24 11:04 + * className : RoseChartBean + * version : 1.0 + * description : 南丁格尔玫瑰图数据 + */ +public class RoseChartBean { + + private float per; + private String name; + //触摸相关 + private Region region; //扇形区域--用于判断手指触摸点是否在此范围 + private RectF rectLable; //矩形区域--用于判断手指触摸点是否在此范围 + //扇形相关 + private RectF arcRect; + private float startAngle; + private float sweepAngle; + //tag线段 + private List tagLinePoints; + private PointF tagTextPoint; + + //右侧lable + private RectF colorRect; + private PointF nameTextPoint; + private PointF perTextPoint; + private PointF dashPathPointStart; + private PointF dashPathPointEnd; + + @Override + public String toString() { + return "RoseChartBean{" + + "per=" + per + + ", name='" + name + '\'' + + '}'; + } + + public RoseChartBean(float per, String name) { + this.per = per; + this.name = name; + } + + public PointF getDashPathPointStart() { + return dashPathPointStart; + } + + public void setDashPathPointStart(PointF dashPathPointStart) { + this.dashPathPointStart = dashPathPointStart; + } + + public PointF getDashPathPointEnd() { + return dashPathPointEnd; + } + + public void setDashPathPointEnd(PointF dashPathPointEnd) { + this.dashPathPointEnd = dashPathPointEnd; + } + + public PointF getNameTextPoint() { + return nameTextPoint; + } + + public void setNameTextPoint(PointF nameTextPoint) { + this.nameTextPoint = nameTextPoint; + } + + public PointF getPerTextPoint() { + return perTextPoint; + } + + public void setPerTextPoint(PointF perTextPoint) { + this.perTextPoint = perTextPoint; + } + + public RectF getColorRect() { + return colorRect; + } + + public void setColorRect(RectF colorRect) { + this.colorRect = colorRect; + } + + public PointF getTagTextPoint() { + return tagTextPoint; + } + + public void setTagTextPoint(PointF tagTextPoint) { + this.tagTextPoint = tagTextPoint; + } + + public List getTagLinePoints() { + return tagLinePoints; + } + + public void setTagLinePoints(List tagLinePoints) { + this.tagLinePoints = tagLinePoints; + } + + public RectF getArcRect() { + return arcRect; + } + + public void setArcRect(RectF arcRect) { + this.arcRect = arcRect; + } + + public float getStartAngle() { + return startAngle; + } + + public void setStartAngle(float startAngle) { + this.startAngle = startAngle; + } + + public float getSweepAngle() { + return sweepAngle; + } + + public void setSweepAngle(float sweepAngle) { + this.sweepAngle = sweepAngle; + } + + public RectF getRectLable() { + return rectLable; + } + + public void setRectLable(RectF rectLable) { + this.rectLable = rectLable; + } + + public Region getRegion() { + return region; + } + + public void setRegion(Region region) { + this.region = region; + } + + public float getPer() { + return per; + } + + public void setPer(float per) { + this.per = per; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/flowlayout/FlowLayout.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/flowlayout/FlowLayout.java new file mode 100644 index 0000000..67c7add --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/flowlayout/FlowLayout.java @@ -0,0 +1,251 @@ +package com.tairui.gov_affairs_cloud.widget.flowlayout; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +import com.tairui.gov_affairs_cloud.R; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.util.LayoutDirection; +import android.view.View; +import android.view.ViewGroup; +import androidx.core.text.TextUtilsCompat; + + +public class FlowLayout extends ViewGroup { + private static final String TAG = "FlowLayout"; + protected static final int LEFT = -1; + protected static final int CENTER = 0; + protected static final int RIGHT = 1; + + // 记录所有行 + protected List> mAllViews = new ArrayList>(); + // 记录所有行高 + protected List mLineHeight = new ArrayList(); + // 记录所有行宽 + protected List mLineWidth = new ArrayList(); + // 临时记录每行的view + protected List lineViews = new ArrayList<>(); + protected int mGravity; + // 最大行数 + private int maxLine = -1; + + /** + * 设置最大行数 + * + * @param maxLine 最大行数 + */ + public void setMaxLine(int maxLine) { + this.maxLine = maxLine; + } + + /** + * 获取当前总行数 + * + * @return + */ + public int getTotalLines() { + return mAllViews.size(); + } + + public FlowLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TagFlowLayout); + mGravity = ta.getInt(R.styleable.TagFlowLayout_tag_gravity, LEFT); + int layoutDirection = TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()); + if (layoutDirection == LayoutDirection.RTL) { + if (mGravity == LEFT) { + mGravity = RIGHT; + } else { + mGravity = LEFT; + } + } + ta.recycle(); + } + + public FlowLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public FlowLayout(Context context) { + this(context, null); + } + + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + + mAllViews.clear();//记录所有行的view + mLineHeight.clear();//记录每一行的高度 + mLineWidth.clear();//记录每一行的宽度 + lineViews.clear();//记录每一行的view + + int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); + int modeWidth = MeasureSpec.getMode(widthMeasureSpec); + int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); + int modeHeight = MeasureSpec.getMode(heightMeasureSpec); + + // wrap_content 最终宽高 + int width = 0; + int height = 0; + + //当前已用行宽高 + int lineWidth = 0; + int lineHeight = 0; + + int cCount = getChildCount(); + + for (int i = 0; i < cCount; i++) { + View child = getChildAt(i); + + if (child.getVisibility() == View.GONE) { + continue; + } + //测量子view + measureChild(child, widthMeasureSpec, heightMeasureSpec); + MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); + //子View宽高 + int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; + int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; + + if (lineWidth + childWidth > sizeWidth - getPaddingLeft() - getPaddingRight()) { + // +1是因为后面还有最后一行 + if (maxLine > 0 && mAllViews.size() + 1 >= maxLine) { + // 超过最大行数跳出循环 + break; + } + // 需要换行 + width = Math.max(width, lineWidth);// 记录最大行宽 + height += lineHeight;// 累加包裹内容所需的高度 + + //换行,保存上一行数据 + mLineHeight.add(lineHeight); + mLineWidth.add(lineWidth); + mAllViews.add(lineViews); + + //重置新行变量 + lineWidth = 0;//重新赋值行宽 + lineHeight = 0;//重新赋值行高 + lineViews = new ArrayList(); + } + //记录当前行数据 + lineWidth += childWidth;//累加行宽 + lineHeight = Math.max(lineHeight, childHeight);//取当前行最大高度作为行高 + lineViews.add(child); + + + } + + //添加最后一行数据 + //包裹内容所需的最大宽度 + width = Math.max(lineWidth, width); + height += lineHeight; + mLineHeight.add(lineHeight); + mLineWidth.add(lineWidth); + mAllViews.add(lineViews); + + setMeasuredDimension( + //父控件宽高确定则用确定的,否则用测量后的 + modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width + getPaddingLeft() + getPaddingRight(), + modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height + getPaddingTop() + getPaddingBottom()// + ); + + } + + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + //总宽 + int width = getWidth(); + //当前已用行宽高 + int lineHeight = 0; + //下面是对每一行的View进行布局 + int left = getPaddingLeft(); + int top = getPaddingTop(); + int lineNum = mAllViews.size(); + for (int i = 0; i < lineNum; i++) { + //获取当前行和行高 + lineViews = mAllViews.get(i); + lineHeight = mLineHeight.get(i); + + // set gravity + int currentLineWidth = this.mLineWidth.get(i); + switch (this.mGravity) { + case LEFT: + left = getPaddingLeft(); + break; + case CENTER: + left = (width - currentLineWidth) / 2 + getPaddingLeft(); + break; + case RIGHT: + // 适配了rtl,需要补偿一个padding值 ,从右边向左开始布局 + left = width - (currentLineWidth + getPaddingLeft()) - getPaddingRight(); + // 适配了rtl,需要把lineViews里面的数组倒序排,从右边开始存放view + Collections.reverse(lineViews); + break; + default: + break; + } + //开始一行行地布局子view + for (int j = 0; j < lineViews.size(); j++) { + View child = lineViews.get(j); + if (child.getVisibility() == View.GONE) { + continue; + } + + MarginLayoutParams lp = (MarginLayoutParams) child + .getLayoutParams(); + + int lc = left + lp.leftMargin; + int tc = top + lp.topMargin; + int rc = lc + child.getMeasuredWidth(); + int bc = tc + child.getMeasuredHeight(); + + child.layout(lc, tc, rc, bc); + + //更新下一个view添加到当前行的left + left += child.getMeasuredWidth() + lp.leftMargin + + lp.rightMargin; + } + //更新下一个view添加到下一行的top + top += lineHeight; + } + } + + @Override + public LayoutParams generateLayoutParams(AttributeSet attrs) { + return new MarginLayoutParams(getContext(), attrs); + } + + @Override + protected LayoutParams generateDefaultLayoutParams() { + return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + } + + @Override + protected LayoutParams generateLayoutParams(LayoutParams p) { + return new MarginLayoutParams(p); + } + + /** + * 获取指定行数内的item个数 + * + * @return 每行的个数之和 + * @lineNum 总行数 + */ + public int getTotalByLine(int lineNum) { + int count = 0; + if (lineNum <= mAllViews.size()) { + for (int i = 0; i < lineNum; i++) { + List line = mAllViews.get(i); + count += line.size(); + } + } + + return count; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/flowlayout/TagAdapter.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/flowlayout/TagAdapter.java new file mode 100644 index 0000000..79abb3e --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/flowlayout/TagAdapter.java @@ -0,0 +1,91 @@ +package com.tairui.gov_affairs_cloud.widget.flowlayout; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import android.util.Log; +import android.view.View; + +public abstract class TagAdapter { + private List mTagDatas; + private OnDataChangedListener mOnDataChangedListener; + @Deprecated + private HashSet mCheckedPosList = new HashSet(); + + public TagAdapter(List datas) { + mTagDatas = datas; + } + + @Deprecated + public TagAdapter(T[] datas) { + mTagDatas = new ArrayList(Arrays.asList(datas)); + } + + interface OnDataChangedListener { + void onChanged(); + } + + public void setData(List datas) { + mTagDatas = datas; + notifyDataChanged(); + } + + void setOnDataChangedListener(OnDataChangedListener listener) { + mOnDataChangedListener = listener; + } + + @Deprecated + public void setSelectedList(int... poses) { + Set set = new HashSet<>(); + for (int pos : poses) { + set.add(pos); + } + setSelectedList(set); + } + + @Deprecated + public void setSelectedList(Set set) { + mCheckedPosList.clear(); + if (set != null) { + mCheckedPosList.addAll(set); + } + notifyDataChanged(); + } + + @Deprecated + HashSet getPreCheckedList() { + return mCheckedPosList; + } + + public int getCount() { + return mTagDatas == null ? 0 : mTagDatas.size(); + } + + public void notifyDataChanged() { + if (mOnDataChangedListener != null) { + mOnDataChangedListener.onChanged(); + } + } + + public T getItem(int position) { + return mTagDatas.get(position); + } + + public abstract View getView(FlowLayout parent, int position, T t); + + public void onSelected(int position, View view) { + Log.d("zhy", "onSelected " + position); + } + + public void unSelected(int position, View view) { + Log.d("zhy", "unSelected " + position); + } + + public boolean setSelected(int position, T t) { + return false; + } + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/flowlayout/TagFlowLayout.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/flowlayout/TagFlowLayout.java new file mode 100644 index 0000000..aae917a --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/flowlayout/TagFlowLayout.java @@ -0,0 +1,247 @@ +package com.tairui.gov_affairs_cloud.widget.flowlayout; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import com.tairui.gov_affairs_cloud.R; + +import android.content.Context; +import android.content.res.TypedArray; +import android.os.Bundle; +import android.os.Parcelable; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; + + +/** + * Created by zhy on 15/9/10. + */ +public class TagFlowLayout extends FlowLayout implements TagAdapter.OnDataChangedListener { + + private TagAdapter mTagAdapter; + private int mSelectedMax = -1;//-1为不限制数量 + private static final String TAG = "TagFlowLayout"; + + private Set mSelectedView = new HashSet(); + + private OnSelectListener mOnSelectListener; + private OnTagClickListener mOnTagClickListener; + + public interface OnSelectListener { + void onSelected(Set selectPosSet); + } + + public interface OnTagClickListener { + boolean onTagClick(View view, int position, FlowLayout parent); + } + + public TagFlowLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TagFlowLayout); + mSelectedMax = ta.getInt(R.styleable.TagFlowLayout_max_select, -1); + ta.recycle(); + } + + public TagFlowLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public TagFlowLayout(Context context) { + this(context, null); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int cCount = getChildCount(); + for (int i = 0; i < cCount; i++) { + TagView tagView = (TagView) getChildAt(i); + if (tagView.getVisibility() == View.GONE) { + continue; + } + if (tagView.getTagView().getVisibility() == View.GONE) { + tagView.setVisibility(View.GONE); + } + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + public void setOnSelectListener(OnSelectListener onSelectListener) { + mOnSelectListener = onSelectListener; + } + + public void setOnTagClickListener(OnTagClickListener onTagClickListener) { + mOnTagClickListener = onTagClickListener; + } + + public void setAdapter(TagAdapter adapter) { + mTagAdapter = adapter; + mTagAdapter.setOnDataChangedListener(this); + mSelectedView.clear(); + changeAdapter(); + } + + @SuppressWarnings("ResourceType") + private void changeAdapter() { + removeAllViews(); + TagAdapter adapter = mTagAdapter; + TagView tagViewContainer = null; + HashSet preCheckedList = mTagAdapter.getPreCheckedList(); + for (int i = 0; i < adapter.getCount(); i++) { + View tagView = adapter.getView(this, i, adapter.getItem(i)); + + tagViewContainer = new TagView(getContext()); + tagView.setDuplicateParentStateEnabled(true); + if (tagView.getLayoutParams() != null) { + tagViewContainer.setLayoutParams(tagView.getLayoutParams()); + + } else { + ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + lp.setMargins(dip2px(getContext(), 5), + dip2px(getContext(), 5), + dip2px(getContext(), 5), + dip2px(getContext(), 5)); + tagViewContainer.setLayoutParams(lp); + } + ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + tagView.setLayoutParams(lp); + tagViewContainer.addView(tagView); + addView(tagViewContainer); + + if (preCheckedList.contains(i)) { + setChildChecked(i, tagViewContainer); + } + + if (mTagAdapter.setSelected(i, adapter.getItem(i))) { + setChildChecked(i, tagViewContainer); + } + tagView.setClickable(false); + final TagView finalTagViewContainer = tagViewContainer; + final int position = i; + tagViewContainer.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + doSelect(finalTagViewContainer, position); + if (mOnTagClickListener != null) { + mOnTagClickListener.onTagClick(finalTagViewContainer, position, + TagFlowLayout.this); + } + } + }); + } + mSelectedView.addAll(preCheckedList); + } + + public void setMaxSelectCount(int count) { + if (mSelectedView.size() > count) { + Log.w(TAG, "you has already select more than " + count + " views , so it will be clear ."); + mSelectedView.clear(); + } + mSelectedMax = count; + } + + public Set getSelectedList() { + return new HashSet(mSelectedView); + } + + private void setChildChecked(int position, TagView view) { + view.setChecked(true); + mTagAdapter.onSelected(position, view.getTagView()); + } + + private void setChildUnChecked(int position, TagView view) { + view.setChecked(false); + mTagAdapter.unSelected(position, view.getTagView()); + } + + private void doSelect(TagView child, int position) { + if (!child.isChecked()) { + //处理max_select=1的情况 + if (mSelectedMax == 1 && mSelectedView.size() == 1) { + Iterator iterator = mSelectedView.iterator(); + Integer preIndex = iterator.next(); + TagView pre = (TagView) getChildAt(preIndex); + setChildUnChecked(preIndex, pre); + setChildChecked(position, child); + + mSelectedView.remove(preIndex); + mSelectedView.add(position); + } else { + if (mSelectedMax > 0 && mSelectedView.size() >= mSelectedMax) { + return; + } + setChildChecked(position, child); + mSelectedView.add(position); + } + } else { + setChildUnChecked(position, child); + mSelectedView.remove(position); + } + if (mOnSelectListener != null) { + mOnSelectListener.onSelected(new HashSet(mSelectedView)); + } + } + + public TagAdapter getAdapter() { + return mTagAdapter; + } + + private static final String KEY_CHOOSE_POS = "key_choose_pos"; + private static final String KEY_DEFAULT = "key_default"; + + @Override + protected Parcelable onSaveInstanceState() { + Bundle bundle = new Bundle(); + bundle.putParcelable(KEY_DEFAULT, super.onSaveInstanceState()); + + String selectPos = ""; + if (mSelectedView.size() > 0) { + for (int key : mSelectedView) { + selectPos += key + "|"; + } + selectPos = selectPos.substring(0, selectPos.length() - 1); + } + bundle.putString(KEY_CHOOSE_POS, selectPos); + return bundle; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (state instanceof Bundle) { + Bundle bundle = (Bundle) state; + String mSelectPos = bundle.getString(KEY_CHOOSE_POS); + if (!TextUtils.isEmpty(mSelectPos)) { + String[] split = mSelectPos.split("\\|"); + for (String pos : split) { + int index = Integer.parseInt(pos); + mSelectedView.add(index); + + TagView tagView = (TagView) getChildAt(index); + if (tagView != null) { + setChildChecked(index, tagView); + } + } + + } + super.onRestoreInstanceState(bundle.getParcelable(KEY_DEFAULT)); + return; + } + super.onRestoreInstanceState(state); + } + + @Override + public void onChanged() { + mSelectedView.clear(); + changeAdapter(); + } + + public static int dip2px(Context context, float dpValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/flowlayout/TagView.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/flowlayout/TagView.java new file mode 100644 index 0000000..f473cef --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/flowlayout/TagView.java @@ -0,0 +1,72 @@ +package com.tairui.gov_affairs_cloud.widget.flowlayout; + +import android.content.Context; +import android.view.View; +import android.widget.Checkable; +import android.widget.FrameLayout; + +/** + * Created by zhy on 15/9/10. + */ +public class TagView extends FrameLayout implements Checkable +{ + private boolean isChecked; + private static final int[] CHECK_STATE = new int[]{android.R.attr.state_checked}; + + public TagView(Context context) + { + super(context); + } + + public View getTagView() + { + return getChildAt(0); + } + + @Override + public int[] onCreateDrawableState(int extraSpace) + { + int[] states = super.onCreateDrawableState(extraSpace + 1); + if (isChecked()) + { + mergeDrawableStates(states, CHECK_STATE); + } + return states; + } + + + /** + * Change the checked state of the view + * + * @param checked The new checked state + */ + @Override + public void setChecked(boolean checked) + { + if (this.isChecked != checked) + { + this.isChecked = checked; + refreshDrawableState(); + } + } + + /** + * @return The current checked state of the view + */ + @Override + public boolean isChecked() + { + return isChecked; + } + + /** + * Change the checked state of the view to the inverse of its current state + */ + @Override + public void toggle() + { + setChecked(!isChecked); + } + + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/FinishDrawListener.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/FinishDrawListener.java new file mode 100644 index 0000000..bd9611d --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/FinishDrawListener.java @@ -0,0 +1,16 @@ +package com.tairui.gov_affairs_cloud.widget.loading; + +import android.view.View; + +/** + * Created by Luo_xiasuhuei321@163.com on 2016/11/6. + * desc: + */ +public interface FinishDrawListener { + /** + * 分发绘制完成事件 + * + * @param v 绘制完成的View + */ + void dispatchFinishEvent(View v); +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/LVCircularRing.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/LVCircularRing.java new file mode 100644 index 0000000..5347282 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/LVCircularRing.java @@ -0,0 +1,136 @@ +package com.tairui.gov_affairs_cloud.widget.loading; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.LinearInterpolator; +import androidx.annotation.ColorInt; + +/** + * Created by Luo on 2016/9/23. + * desc: + */ +public class LVCircularRing extends View { + public final String TAG = getClass().getSimpleName(); + private float mWidth = 0f; + private float mPadding = 0f; + private float startAngle = 0f; + private Paint mPaint; + private int color = Color.argb(100, 255, 255, 255); + private Paint mPaint2; + + public LVCircularRing(Context context) { + this(context, null); + } + + public LVCircularRing(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public LVCircularRing(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initPaint(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + if (getMeasuredWidth() > getHeight()) + mWidth = getMeasuredHeight(); + else + mWidth = getMeasuredWidth(); + mPadding = 5; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + +// mPaint.setColor(Color.argb(100, 255, 255, 255)); + mPaint2.setColor(color); + canvas.drawCircle(mWidth / 2, mWidth / 2, mWidth / 2 - mPadding, mPaint2); + mPaint.setColor(Color.WHITE); + RectF rectF = new RectF(mPadding, mPadding, mWidth - mPadding, mWidth - mPadding); + canvas.drawArc(rectF, startAngle, 100 + , false, mPaint);//第四个参数是否显示半径 + } + + + private void initPaint() { + mPaint = new Paint(); + mPaint.setAntiAlias(true); + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setColor(color); + mPaint.setStrokeWidth(8); + + mPaint2 = new Paint(); + mPaint2.setAntiAlias(true); + mPaint2.setStyle(Paint.Style.STROKE); + mPaint2.setStrokeWidth(8); + mPaint2.setColor(color); + } + + public void startAnim() { + stopAnim(); + startViewAnim(0f, 1f, 1000); + } + + public void stopAnim() { + if (valueAnimator != null) { + clearAnimation(); + valueAnimator.setRepeatCount(1); + valueAnimator.cancel(); + valueAnimator.end(); + } + } + + ValueAnimator valueAnimator; + + private ValueAnimator startViewAnim(float startF, final float endF, long time) { + valueAnimator = ValueAnimator.ofFloat(startF, endF); + + valueAnimator.setDuration(time); + valueAnimator.setInterpolator(new LinearInterpolator()); + valueAnimator.setRepeatCount(ValueAnimator.INFINITE);//无限循环 + valueAnimator.setRepeatMode(ValueAnimator.RESTART);// + + valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + + float value = (float) valueAnimator.getAnimatedValue(); + startAngle = 360 * value; + + invalidate(); + } + }); + valueAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + } + }); + if (!valueAnimator.isRunning()) { + valueAnimator.start(); + } + + return valueAnimator; + } + + public void setColor(@ColorInt int color) { + this.color = color; + mPaint.setColor(color); + mPaint2.setColor(color); + } +} + + + diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/LoadCircleView.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/LoadCircleView.java new file mode 100644 index 0000000..62d2d89 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/LoadCircleView.java @@ -0,0 +1,100 @@ +package com.tairui.gov_affairs_cloud.widget.loading; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.View; + +/** + * Created by xiasuhuei321 on 2017/5/15. + * author:luo + * e-mail:xiasuhuei321@163.com + */ + +public class LoadCircleView extends View { + public final String TAG = getClass().getSimpleName(); + + private float mPadding = 0f; + private RectF rectF; + private Context mContext; + private Paint mPaint; + private int mWidth = 0; + private int currentLineIndex = 0; + + public LoadCircleView(Context context) { + this(context, null); + } + + public LoadCircleView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public LoadCircleView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + mContext = context; + init(); + } + + public void init() { + mPaint = new Paint(); + mPaint.setAntiAlias(true); + mPaint.setStyle(Paint.Style.STROKE); +// mPaint.setColor(Color.BLACK); + mPaint.setStrokeWidth(8); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); + int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); + + int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); + int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); + + if (widthSpecMode != MeasureSpec.AT_MOST && heightSpecMode != MeasureSpec.AT_MOST) { + mWidth = widthSpecSize >= heightSpecSize ? widthSpecSize : heightSpecSize; + } else if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode != MeasureSpec.AT_MOST) { + mWidth = heightSpecSize; + } else if (widthSpecMode != MeasureSpec.AT_MOST) { + mWidth = widthSpecSize; + } else { + mWidth = SizeUtils.dip2px(mContext, 50); + } + setMeasuredDimension(mWidth, mWidth); + mPadding = 8; +// rectF = new RectF(mPadding, mPadding, mWidth - mPadding, mWidth - mPadding); + } + + @Override + protected void onDraw(Canvas canvas) { + // 圆心坐标 (center,center) + int center = mWidth >> 1; + int radius = (mWidth >> 1) - 8; + if (currentLineIndex >= 12) + currentLineIndex = 0; +// canvas.rotate(currentLineIndex * 30, center, center); + // 画12根线 + for (int i = 0; i < 12; i++) { + if (i < currentLineIndex + 4 && i >= currentLineIndex) { + mPaint.setColor(Color.GRAY); + } else if (currentLineIndex > 8 && i < currentLineIndex + 4 - 12) { + mPaint.setColor(Color.GRAY); + } else { + mPaint.setColor(Color.WHITE); + } + +// canvas.drawLine(center, (float) (center + 1.0 / 4 * center), +// center, (float) (center + 1.0 / 2 * radius), mPaint); + canvas.drawLine(center, (float) (center + 1.0 / 2 * radius), + center, 2 * radius, mPaint); + canvas.rotate(30, center, center); + } + currentLineIndex++; + postInvalidateDelayed(50); + } + + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/LoadingDialog.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/LoadingDialog.java new file mode 100644 index 0000000..668f756 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/LoadingDialog.java @@ -0,0 +1,518 @@ +package com.tairui.gov_affairs_cloud.widget.loading; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; + +import com.tairui.gov_affairs_cloud.R; +import com.tairui.gov_affairs_cloud.widget.loading.manager.StyleManager; + +import android.annotation.SuppressLint; +import android.app.Dialog; +import android.content.Context; +import android.os.Handler; +import android.os.Message; +import android.text.TextUtils; +import android.util.Log; +import android.util.TypedValue; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.TextView; +import androidx.annotation.ColorInt; + +/** + * desc:加载等待的Dialog + */ +public class LoadingDialog implements FinishDrawListener { + // private final String TAG = "LoadingDialog"; + public static final int STYLE_RING = 0; + private static final int STYLE_LINE = 1; + // private Context mContext; + + private LVCircularRing mLoadingView; + private Dialog mLoadingDialog; + private LinearLayout layout; + private TextView loadingText; + private RightDiaView mSuccessView; + private WrongDiaView mFailedView; + + private String loadSuccessStr; + private String loadFailedStr; + private List viewList; + + private boolean interceptBack = true; + private boolean openSuccessAnim = true; + private boolean openFailedAnim = true; + private int speed = 1; + private long time = 1000; + private int loadStyle = STYLE_RING; + + private static StyleManager s = StyleManager.getDefault(); + private LoadCircleView mCircleLoadView; + + private MyHandler myHandler; + + public enum Speed { + SPEED_ONE, + SPEED_TWO + } + + private OnFinshListener onFinshListener; + private DismissListener dismissListener; + + @SuppressLint("InflateParams") + public LoadingDialog(Context context) { + // mContext = context; + // 首先得到整个View + View view = LayoutInflater.from(context).inflate( + R.layout.view_loading_dialog, null); + initView(view); + // 创建自定义样式的Dialog + mLoadingDialog = new Dialog(context, R.style.loading_dialog); + // mLoadingDialog = new Dialog(context, R.style.loading_dialog) { + // @Override + // public void onBackPressed() { + // if (interceptBack) { + // return; + // } + // LoadingDialog.this.close(); + // } + // }; + myHandler = new MyHandler(LoadingDialog.this); + // 设置返回键无效 + mLoadingDialog.setCancelable(!interceptBack); + mLoadingDialog.setContentView(layout, new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.MATCH_PARENT)); + + mLoadingDialog.setOnDismissListener(dialog -> { + // if (dismissListener != null) { + // dismissListener.dimiss(); + // } + dialog.dismiss(); + }); + initStyle(); + } + + private void initView(View view) { + layout = view.findViewById(R.id.dialog_view); + mLoadingView = view.findViewById(R.id.lv_circularring); + loadingText = view.findViewById(R.id.loading_text); + mSuccessView = view.findViewById(R.id.rdv_right); + mFailedView = view.findViewById(R.id.wv_wrong); + mCircleLoadView = view.findViewById(R.id.lcv_circleload); + initData(); + } + + private void initData() { + viewList = new ArrayList<>(); + viewList.add(mLoadingView); + viewList.add(mSuccessView); + viewList.add(mFailedView); + viewList.add(mCircleLoadView); + + mSuccessView.setOnDrawFinishListener(this); + mFailedView.setOnDrawFinishListener(this); + } + + @Override + public void dispatchFinishEvent(View v) { + if (v instanceof WrongDiaView) { + myHandler.sendEmptyMessageDelayed(2, time); + } else { + myHandler.sendEmptyMessageDelayed(1, time); + } + } + + private void hideAll() { + for (View v : viewList) { + if (v.getVisibility() != View.GONE) { + v.setVisibility(View.GONE); + } + } + } + + private void setParams(int size) { + if (size < 0) { + return; + } + ViewGroup.LayoutParams successParams = mSuccessView.getLayoutParams(); + successParams.height = size; + successParams.width = size; + mSuccessView.setLayoutParams(successParams); + + ViewGroup.LayoutParams failedParams = mFailedView.getLayoutParams(); + failedParams.height = size; + failedParams.width = size; + mFailedView.setLayoutParams(failedParams); + + ViewGroup.LayoutParams loadingParams = mLoadingView.getLayoutParams(); + loadingParams.height = size; + loadingParams.width = size; + } + + // 会在最后将所有消息移除 + // @SuppressLint("HandlerLeak") + // private Handler handler = new Handler() { + // + // @Override + // public void handleMessage(Message msg) { + // close(); + // if (onFinshListener != null) { + // onFinshListener.onFinish(); + // } + // } + // }; + + private static class MyHandler extends Handler { + private WeakReference weakReference; + + MyHandler(LoadingDialog loadingDialog) { + weakReference = new WeakReference<>(loadingDialog); + } + + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + LoadingDialog dialog = weakReference.get(); + if (dialog != null) { + dialog.close(); + if (null != dialog.onFinshListener) { + dialog.onFinshListener.onFinish(); + } + } + } + } + + private void initStyle() { + if (s != null) { + setInterceptBack(s.isInterceptBack()); + setRepeatCount(s.getRepeatTime()); + setParams(s.getContentSize()); + setTextSize(s.getTextSize()); + setShowTime(s.getShowTime()); + if (!s.isOpenAnim()) { + closeFailedAnim(); + closeSuccessAnim(); + } + setLoadingText(s.getLoadText()); + setSuccessText(s.getSuccessText()); + setFailedText(s.getFailedText()); + setLoadStyle(s.getLoadStyle()); + } + } + + //----------------------------------对外提供的api------------------------------// + + /** + * please invoke show() method at last,because it's + * return value is void + * 请在最后调用show,因此show返回值为void会使链式api断开 + */ + public void show() { + hideAll(); + if (loadStyle == STYLE_RING) { + mLoadingView.setVisibility(View.VISIBLE); + mCircleLoadView.setVisibility(View.GONE); + mLoadingDialog.show(); + mLoadingView.startAnim(); + Log.i("show", "style_ring"); + } else if (loadStyle == STYLE_LINE) { + mCircleLoadView.setVisibility(View.VISIBLE); + mLoadingView.setVisibility(View.GONE); + mLoadingDialog.show(); + Log.i("show", "style_line"); + } + } + + /** + * set load style + * 设置load的样式,目前支持转圈圈和菊花转圈圈 + * + * @param style 样式 + */ + public LoadingDialog setLoadStyle(int style) { + if (style >= 3) { + throw new IllegalArgumentException("Your style is wrong: style = " + style); + } + this.loadStyle = style; + return this; + } + + /** + * 让这个dialog消失,在拦截back事件的情况下一定要调用这个方法! + * 在调用了该方法之后如需再次使用loadingDialog,请新创建一个 + * LoadingDialog对象。 + */ + public void close() { + myHandler.removeCallbacksAndMessages(null); + if (mLoadingDialog != null) { + mLoadingView.stopAnim(); + mLoadingDialog.dismiss(); + } + } + + /** + * 设置加载时的文字提示 + * + * @param msg 文字 + * + * @return 这个对象 + */ + public LoadingDialog setLoadingText(String msg) { + if (!TextUtils.isEmpty(msg)) { + loadingText.setVisibility(View.VISIBLE); + loadingText.setText(msg); + } else { + loadingText.setVisibility(View.GONE); + } + return this; + } + + /** + * 设置加载成功的文字提示 + * + * @param msg 文字 + * + * @return 这个对象 + */ + public LoadingDialog setSuccessText(String msg) { + loadSuccessStr = msg; + return this; + } + + /** + * 设置加载失败的文字提示 + * + * @param msg 文字 + * + * @return 这个对象 + */ + public LoadingDialog setFailedText(String msg) { + loadFailedStr = msg; + return this; + } + + /** + * when you need a successful feedback,please invoke + * this method in success's callback + * 当你需要一个成功的反馈的时候,在加载成功的回调中调用此方法 + */ + public void loadSuccess() { + mLoadingView.stopAnim(); + hideAll(); + mSuccessView.setDrawDynamic(openSuccessAnim); + mSuccessView.setVisibility(View.VISIBLE); + if (loadSuccessStr == null) { + loadingText.setVisibility(View.GONE); + } else { + loadingText.setVisibility(View.VISIBLE); + loadingText.setText(loadSuccessStr); + } + } + + /** + * when you need a fail feedback,please invoke this + * method in failed callback + * 当你需要一个失败的反馈的时候,在加载失败的回调中调用此方法 + */ + public void loadFailed() { + mLoadingView.stopAnim(); + hideAll(); + mFailedView.setDrawDynamic(openFailedAnim); + mFailedView.setVisibility(View.VISIBLE); + if (loadFailedStr == null) { + loadingText.setVisibility(View.GONE); + } else { + loadingText.setVisibility(View.VISIBLE); + loadingText.setText(loadFailedStr); + } + } + + /** + * 关闭动态绘制 + */ + public LoadingDialog closeSuccessAnim() { + this.openSuccessAnim = false; + return this; + } + + /** + * 关闭动态绘制 + */ + public LoadingDialog closeFailedAnim() { + this.openFailedAnim = false; + return this; + } + + /** + * 设置是否拦截back,默认会拦截 + * + * @param interceptBack true拦截back,false不拦截 + * + * @return 这个对象 + */ + public LoadingDialog setInterceptBack(boolean interceptBack) { + this.interceptBack = interceptBack; + mLoadingDialog.setCancelable(!interceptBack); + return this; + } + + /** + * 当前dialog是否拦截back事件 + * + * @return 如果拦截返回true,反之false + */ + public boolean getInterceptBack() { + return interceptBack; + } + + /** + * 使用该方法改变成功和失败绘制的速度 + * + * @param speed 绘制速度 + * + * @return 这个对象 + */ + public LoadingDialog setLoadSpeed(Speed speed) { + if (speed == Speed.SPEED_ONE) { + this.speed = 1; + mSuccessView.setSpeed(1); + mFailedView.setSpeed(1); + } else { + this.speed = 2; + mSuccessView.setSpeed(2); + mFailedView.setSpeed(2); + } + return this; + } + + /** + * 返回当前绘制的速度 + * + * @return 速度 + */ + public int getSpeed() { + return this.speed; + } + + /** + * 此方法改变成功失败绘制的颜色,此方法增加了处理的复杂性,暂时不公开此方法。 + * 而且暂时没有做到方便调用,真的要用的话十分的麻烦,暂时隐藏,后续不确定是否公开。 + */ + private LoadingDialog setDrawColor(@ColorInt int color) { + mFailedView.setDrawColor(color); + mSuccessView.setDrawColor(color); + loadingText.setTextColor(color); + mLoadingView.setColor(color); + return this; + } + + /** + * 设置中间弹框的尺寸 + * + * @param size 尺寸,单位px + * + * @return 这个对象 + */ + public LoadingDialog setSize(int size) { + // int dip = SizeUtils.px2dip(mContext, size); + if (size <= 50) { + return this; + } + setParams(size); + return this; + } + + /** + * 设置重新绘制的次数,默认只绘制一次,如果你设置这个 + * 数值为1,那么在绘制一次过后,还会再次绘制一次。 + * + * @param count 绘制次数 + * + * @return 这个对象 + */ + public LoadingDialog setRepeatCount(int count) { + mFailedView.setRepeatTime(count); + mSuccessView.setRepeatTime(count); + return this; + } + + public boolean isShow() { + if (null != mLoadingDialog) { + return mLoadingDialog.isShowing(); + } else { + return false; + } + } + + /** + * 设置反馈展示时间 + * + * @param time 时间 + * + * @return 这个对象 + */ + public LoadingDialog setShowTime(long time) { + if (time < 0) { + return this; + } + this.time = time; + return this; + } + + /** + * set the size of load text size + * 设置加载字体大小 + * + * @param size 尺寸,单位sp,来将sp转换为对应的px值 + * + * @return 这个对象 + */ + public LoadingDialog setTextSize(float size) { + if (size < 0) { + return this; + } + loadingText.setTextSize(TypedValue.COMPLEX_UNIT_SP, size); + return this; + } + + public static void initStyle(StyleManager style) { + if (style != null) { + s = style; + } + } + + /** + * dispatch draw finish event + * 传递绘制完成的事件 + * + * @param onFinshListener 回调接口 + */ + public void setOnFinishListener(OnFinshListener onFinshListener) { + this.onFinshListener = onFinshListener; + } + + /** + * 设置 dismiss 监听 + * + * @param dismissListener dismiss callback + */ + public LoadingDialog setDimissListener(DismissListener dismissListener) { + this.dismissListener = dismissListener; + return this; + } + + /** + * 监听器 + */ + public interface OnFinshListener { + void onFinish(); + } + + public interface DismissListener { + void dimiss(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/RightDiaView.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/RightDiaView.java new file mode 100644 index 0000000..5a17ddf --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/RightDiaView.java @@ -0,0 +1,214 @@ +package com.tairui.gov_affairs_cloud.widget.loading; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.View; + +/** + * Created by Luo_xiasuhuei321@163.com on 2016/11/5. + * desc: + */ + +public class RightDiaView extends View { + private final String TAG = this.getClass().getSimpleName(); + + private FinishDrawListener listener; + + private Context mContext; + private int mWidth = 0; + private float mPadding = 0f; + private Paint mPaint; + private RectF rectF; + + private int line1_x; + private int line1_y; + + private int line2_x; + private int line2_y; + + private int times = 0; + private boolean drawEveryTime = true; + private int speed = 1; + + public RightDiaView(Context context) { + this(context, null); + } + + public RightDiaView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public RightDiaView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); + int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); + + int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); + int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); + + if (widthSpecMode != MeasureSpec.AT_MOST && heightSpecMode != MeasureSpec.AT_MOST) { + mWidth = widthSpecSize >= heightSpecSize ? widthSpecSize : heightSpecSize; + } else if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode != MeasureSpec.AT_MOST) { + mWidth = heightSpecSize; + } else if (widthSpecMode != MeasureSpec.AT_MOST) { + mWidth = widthSpecSize; + } else { + mWidth = SizeUtils.dip2px(mContext, 80); + } + setMeasuredDimension(mWidth, mWidth); + mPadding = 8; + rectF = new RectF(mPadding, mPadding, mWidth - mPadding, mWidth - mPadding); + } + + private void init(Context context) { + mPaint = new Paint(); + //抗锯齿 + mPaint.setAntiAlias(true); + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setColor(Color.WHITE); + mPaint.setStrokeWidth(8); + mContext = context; + } + + int progress = 0; + + @Override + protected void onDraw(Canvas canvas) { + if (drawEveryTime) + drawDynamic(canvas); + else { + drawStatic(canvas); + if (listener != null) + listener.dispatchFinishEvent(this); + } + } + + private int count = 0; + + private void drawDynamic(Canvas canvas) { + if (progress < 100) + progress += speed; + //根据进度画圆弧 + canvas.drawArc(rectF, 235, 360 * progress / 100, false, mPaint); + + int center = mWidth / 2; + int center1 = center - mWidth / 5; + + int radius = mWidth / 2 - 8; + + //绘制对勾 + if (progress == 100) { + if (line1_x < radius / 3) { + line1_x += speed; + line1_y += speed; + } + //画第一根线 + canvas.drawLine(center1, center, center1 + line1_x, center + line1_y, mPaint); + + if (line1_x >= radius / 3 && line2_x == 0 && line2_y == 0) { + line2_x = line1_x; + line2_y = line1_y; + line1_x += speed; + line1_y += speed; + } + + if (line1_x >= radius / 3 && line2_x <= radius && line2_y <= center - radius / 3) { + line2_x += speed; + line2_y -= speed; + } + //画第二根线 + canvas.drawLine(center1 + line1_x - 1, center + line1_y - 4, + center1 + line2_x, center + line2_y, mPaint); + } + + if (line2_x > radius && progress >= 100 && line1_x != radius / 3) { + //1.只分发一次绘制完成的事件 + //2.只在最后一次绘制时分发 + if (count == 0 && times == 0 && listener != null) { + listener.dispatchFinishEvent(this); + count++; + } + + times--; + if (times >= 0) { + reDraw(); + invalidate(); + } else { + return; + } + } + + invalidate(); + } + + private void drawStatic(Canvas canvas) { + canvas.drawArc(rectF, 0, 360, false, mPaint); + + int center = mWidth / 2; + int center1 = center - mWidth / 5; + int radius = mWidth / 2 - 8; + canvas.drawLine(center1, center, + center1 + radius / 3, center + radius / 3, mPaint); + canvas.drawLine(center1 + radius / 3 - 1, center + radius / 3 - 4, + center1 + radius, center - radius / 3, mPaint); + } + + + private void reDraw() { + line1_x = 0; + line2_x = 0; + line1_y = 0; + line2_y = 0; + progress = 0; + } + + //---------------------------对外提供的api-------------------------// + + /** + * 设置重复绘制的次数,只在drawEveryTime = true时有效 + * + * @param times 重复次数,例如设置1,除了第一次绘制还会额外重绘一次 + */ + protected void setRepeatTime(int times) { + if (drawEveryTime) + this.times = times; + } + + /** + * 动态画出还是直接画出 + */ + protected void setDrawDynamic(boolean drawEveryTime) { + this.drawEveryTime = drawEveryTime; + } + + /** + * 调整绘制的速度,最小值默认为1 + * + * @param speed 速度 + */ + protected void setSpeed(int speed) { + if (speed <= 0 && speed >= 3) { + throw new IllegalArgumentException("support speed >0 & < 3, the speed you set is: " + speed); + } else { + this.speed = speed; + } + } + + protected void setDrawColor(int color) { + mPaint.setColor(color); + } + + public void setOnDrawFinishListener(FinishDrawListener f) { + this.listener = f; + } +} + diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/SizeUtils.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/SizeUtils.java new file mode 100644 index 0000000..ee2497a --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/SizeUtils.java @@ -0,0 +1,43 @@ +package com.tairui.gov_affairs_cloud.widget.loading; + +import android.content.Context; + +/** + * Created by Luo_xiasuhuei321@163.com on 2016/11/6. + * desc: + */ + +public class SizeUtils { + /** + * dp转px + */ + public static int dip2px(Context context, float dpValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } + + /** + * px转dp + */ + public static int px2dip(Context context, float pxValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (pxValue / scale + 0.5f); + } + + /** + * px转sp + */ + public static int px2sp(Context context, float spValue) { + final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; + return (int) (spValue / fontScale + 0.5f); + } + + /** + * sp转px + */ + public static int sp2px(Context context, float spValue) { + final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; + return (int) (spValue * fontScale + 0.5f); + } + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/WrongDiaView.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/WrongDiaView.java new file mode 100644 index 0000000..d26d1ec --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/WrongDiaView.java @@ -0,0 +1,223 @@ +package com.tairui.gov_affairs_cloud.widget.loading; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.view.View; + + +/** + * Created by Luo_xiasuhuei321@163.com on 2016/11/6. + * desc: + */ +public class WrongDiaView extends View { + private final String TAG = this.getClass().getSimpleName(); + + private FinishDrawListener listener; + + private Context mContext; + private int mWidth = 0; + private Paint mPaint; + private RectF rectF; + + private int line1_x; + private int line1_y; + + private int line2_x; + private int line2_y; + + private int times = 0; + private boolean drawEveryTime = true; + private int speed = 1; + private int count = 0; +// private int color; + + public WrongDiaView(Context context) { + this(context, null); + } + + public WrongDiaView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public WrongDiaView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); +// initAttr(context, attrs, defStyleAttr); + initPaint(context); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); + int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); + + int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); + int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); + + if (widthSpecMode != MeasureSpec.AT_MOST && heightSpecMode != MeasureSpec.AT_MOST) { + mWidth = widthSpecSize >= heightSpecSize ? widthSpecSize : heightSpecSize; + } else if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode != MeasureSpec.AT_MOST) { + mWidth = heightSpecSize; + } else if (widthSpecMode != MeasureSpec.AT_MOST) { + mWidth = widthSpecSize; + } else { + mWidth = SizeUtils.dip2px(mContext, 80); + } + setMeasuredDimension(mWidth, mWidth); + float mPadding = 8; + rectF = new RectF(mPadding, mPadding, mWidth - mPadding, mWidth - mPadding); + } + +// private void initAttr(Context context, AttributeSet attrs, int defStyleAttr) { +// TypedArray a = context.getTheme() +// .obtainStyledAttributes(attrs, R.styleable.WrongDiaView, defStyleAttr, 0); +// for (int i = 0; i < a.getIndexCount(); i++) { +// int attr = a.getIndex(i); +// if (attr == R.styleable.RightDiaView_speed) { +// speed = a.getInt(attr, 1); +// } +// if (attr == R.styleable.RightDiaView_strokeColor) { +// color = a.getColor(attr, Color.WHITE); +// } +// } +// a.recycle(); +// } + + private void initPaint(Context context) { + mContext = context; + mPaint = new Paint(); + //抗锯齿 + mPaint.setAntiAlias(true); + mPaint.setStyle(Paint.Style.STROKE); + mPaint.setColor(Color.WHITE); + mPaint.setStrokeWidth(8); + } + + int progress = 0; + + @Override + protected void onDraw(Canvas canvas) { + if (drawEveryTime) + drawDynamic(canvas); + else { + drawStatic(canvas); + if (listener != null) + listener.dispatchFinishEvent(this); + } + } + + private void drawDynamic(Canvas canvas) { + if (progress < 100) + progress += speed; + //根据进度画圆弧 + canvas.drawArc(rectF, 235, 360 * progress / 100, false, mPaint); + + int line1_start = 3 * mWidth / 10; + int line2_startX = 7 * mWidth / 10; + + + //绘制× + if (progress == 100) { + if ((line1_x + line1_start) <= line2_startX) { + line1_x += speed; + line1_y += speed; + } + //画第一根线 + canvas.drawLine(line1_start, line1_start, + line1_start + line1_x, line1_start + line1_y, mPaint); + + if (line1_x == 2 * mWidth / 5) { + line1_x++; + line1_y++; + } + + if (line1_x >= 2 * mWidth / 5 && (line2_startX - line2_y) >= line1_start) { + line2_x -= speed; + line2_y += speed; + } + //画第二根线 + canvas.drawLine(line2_startX, line1_start, + line2_startX + line2_x, line1_start + line2_y, mPaint); + + if ((line2_startX - line2_y) < line1_start) { + //1.只分发一次绘制完成的事件 + //2.只在最后一次绘制时分发 + if (count == 0 && times == 0 && listener != null) { + listener.dispatchFinishEvent(this); + count++; + } + times--; + if (times >= 0) { + reDraw(); + invalidate(); + } else { + return; + } + } + } + invalidate(); + } + + private void drawStatic(Canvas canvas) { + canvas.drawArc(rectF, 0, 360, false, mPaint); + + int line1_start = 3 * mWidth / 10; + int line2_startX = 7 * mWidth / 10; + + canvas.drawLine(line1_start, line1_start, + line1_start + 2 * mWidth / 5, line1_start + 2 * mWidth / 5, mPaint); + canvas.drawLine(line1_start + 2 * mWidth / 5, line1_start, + line1_start, line1_start + 2 * mWidth / 5, mPaint); + } + + private void reDraw() { + line1_x = 0; + line2_x = 0; + line1_y = 0; + line2_y = 0; + progress = 0; + } + + //---------------------------对外提供的api-------------------------// + + /** + * 设置重复绘制的次数,只在drawEveryTime = true时有效 + * + * @param times 重复次数,例如设置1,除了第一次绘制还会额外重绘一次 + */ + protected void setRepeatTime(int times) { + if (drawEveryTime) + this.times = times; + } + + /** + * 动态画出还是直接画出 + */ + protected void setDrawDynamic(boolean drawEveryTime) { + this.drawEveryTime = drawEveryTime; + } + + /** + * 设置速度 + */ + protected void setSpeed(int speed) { + if (speed <= 0 && speed >= 3) { + throw new IllegalArgumentException("how can u set this speed?? " + speed + " do not " + + "use reflect to use this method!u can see the LoadingDialog class for how to" + + "set the speed"); + } else { + this.speed = speed; + } + } + + protected void setDrawColor(int color) { + mPaint.setColor(color); + } + + public void setOnDrawFinishListener(FinishDrawListener f) { + this.listener = f; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/manager/StyleManager.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/manager/StyleManager.java new file mode 100644 index 0000000..9216785 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/loading/manager/StyleManager.java @@ -0,0 +1,242 @@ +package com.tairui.gov_affairs_cloud.widget.loading.manager; + +import com.tairui.gov_affairs_cloud.widget.loading.LoadingDialog; + +/** + * Created by Luo_xiasuhuei321@163.com on 2016/11/12. + * desc:用于设置全局的loading样式 + */ + +public class StyleManager { + + public static StyleManager getDefault() { + return new StyleManager(true, 0, LoadingDialog.Speed.SPEED_TWO, -1, -1, 1000L, + true, "加载中...", "加载成功", "加载失败"); + } + + public StyleManager() { + } + + public StyleManager(boolean open, int repeatTime, LoadingDialog.Speed speed, + int contentSize, int textSize, long showTime, boolean interceptBack, + String loadText, String successText, String failedText) { + this.openAnim = open; + this.repeatTime = repeatTime; + this.speed = speed; + this.contentSize = contentSize; + this.textSize = textSize; + this.showTime = showTime; + this.interceptBack = interceptBack; + this.loadText = loadText; + this.successText = successText; + this.failedText = failedText; + + } + + public StyleManager(boolean open, int repeatTime, LoadingDialog.Speed speed, + int contentSize, int textSize, long showTime, boolean interceptBack, + String loadText, String successText, String failedText, int loadStyle) { + this.openAnim = open; + this.repeatTime = repeatTime; + this.speed = speed; + this.contentSize = contentSize; + this.textSize = textSize; + this.showTime = showTime; + this.interceptBack = interceptBack; + this.loadText = loadText; + this.successText = successText; + this.failedText = failedText; + this.loadStyle = loadStyle; + } + + /** + * 是否开启绘制 + */ + private boolean openAnim = true; + + /** + * 重绘次数 + */ + private int repeatTime; + + private LoadingDialog.Speed speed = LoadingDialog.Speed.SPEED_TWO; + + /** + * 反馈的尺寸,单位px + */ + private int contentSize = -1; + + /** + * 文字的尺寸,单位px + */ + private int textSize = -1; + + /** + * loading的反馈展示的时间,单位ms + */ + private long showTime = -1; + + private boolean interceptBack = true; + + private String loadText = "加载中..."; + + private String successText = "加载成功"; + + private String failedText = "加载失败"; + + private int loadStyle = LoadingDialog.STYLE_RING; + + public StyleManager setLoadStyle(int loadStyle) { + this.loadStyle = loadStyle; + return this; + } + + public int getLoadStyle() { + return loadStyle; + } + + public boolean isOpenAnim() { + return openAnim; + } + + public String getFailedText() { + return failedText; + } + + public String getSuccessText() { + return successText; + } + + public String getLoadText() { + return loadText; + } + + public boolean isInterceptBack() { + return interceptBack; + } + + public long getShowTime() { + return showTime; + } + + public int getTextSize() { + return textSize; + } + + public int getContentSize() { + return contentSize; + } + + public LoadingDialog.Speed getSpeed() { + return speed; + } + + public int getRepeatTime() { + return repeatTime; + } + + /** + * 是否开启动态绘制 + * + * @param openAnim true开启,false关闭 + * @return this + */ + public StyleManager Anim(boolean openAnim) { + this.openAnim = openAnim; + return this; + } + + /** + * 重复次数 + * + * @param times 次数 + * @return this + */ + public StyleManager repeatTime(int times) { + this.repeatTime = times; + return this; + } + + public StyleManager speed(LoadingDialog.Speed s) { + this.speed = s; + return this; + } + + /** + * 设置loading的大小 + * + * @param size 尺寸,单位px + * @return this + */ + public StyleManager contentSize(int size) { + this.contentSize = size; + return this; + } + + /** + * 设置loading 文字的大小 + * + * @param size 尺寸,单位px + * @return this + */ + public StyleManager textSize(int size) { + this.textSize = size; + return this; + } + + /** + * 设置展示的事件,如果开启绘制则从绘制完毕开始计算 + * + * @param showTime 事件 + * @return this + */ + public StyleManager showTime(long showTime) { + this.showTime = showTime; + return this; + } + + /** + * 设置是否拦截back,默认拦截 + * + * @param interceptBack true拦截,false不拦截 + * @return this + */ + public StyleManager intercept(boolean interceptBack) { + this.interceptBack = interceptBack; + return this; + } + + /** + * 设置loading时的文字 + * + * @param text 文字 + * @return this + */ + public StyleManager loadText(String text) { + this.loadText = text; + return this; + } + + /** + * 设置success时的文字 + * + * @param text 文字 + * @return this + */ + public StyleManager successText(String text) { + this.successText = text; + return this; + } + + /** + * 设置failed时的文字 + * + * @param text 文字 + * @return this + */ + public StyleManager failedText(String text) { + this.failedText = text; + return this; + } + +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/statusbar/OSUtils.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/statusbar/OSUtils.java new file mode 100644 index 0000000..b7c9c0e --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/statusbar/OSUtils.java @@ -0,0 +1,123 @@ +package com.tairui.gov_affairs_cloud.widget.statusbar; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import android.os.Build; +import android.text.TextUtils; + +/** + * Created by xiezonglin on 2018/12/20. + */ + +public class OSUtils { + + public static final String ROM_MIUI = "MIUI"; + public static final String ROM_EMUI = "EMUI"; + public static final String ROM_FLYME = "FLYME"; + public static final String ROM_OPPO = "OPPO"; + public static final String ROM_SMARTISAN = "SMARTISAN"; + public static final String ROM_VIVO = "VIVO"; + public static final String ROM_QIKU = "QIKU"; + + private static final String KEY_VERSION_MIUI = "ro.miui.ui.version.name"; + private static final String KEY_VERSION_EMUI = "ro.build.version.emui"; + private static final String KEY_VERSION_OPPO = "ro.build.version.opporom"; + private static final String KEY_VERSION_SMARTISAN = "ro.smartisan.version"; + private static final String KEY_VERSION_VIVO = "ro.vivo.os.version"; + + private static String sName; + private static String sVersion; + + public static boolean isEmui() { + return check(ROM_EMUI); + } + + public static boolean isMiui() { + return check(ROM_MIUI); + } + + public static boolean isVivo() { + return check(ROM_VIVO); + } + + public static boolean isOppo() { + return check(ROM_OPPO); + } + + public static boolean isFlyme() { + return check(ROM_FLYME); + } + + public static boolean is360() { + return check(ROM_QIKU) || check("360"); + } + + public static boolean isSmartisan() { + return check(ROM_SMARTISAN); + } + + public static String getName() { + if (sName == null) { + check(""); + } + return sName; + } + + public static String getVersion() { + if (sVersion == null) { + check(""); + } + return sVersion; + } + + public static boolean check(String rom) { + if (sName != null) { + return sName.equals(rom); + } + + if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_MIUI))) { + sName = ROM_MIUI; + } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_EMUI))) { + sName = ROM_EMUI; + } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_OPPO))) { + sName = ROM_OPPO; + } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_VIVO))) { + sName = ROM_VIVO; + } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_SMARTISAN))) { + sName = ROM_SMARTISAN; + } else { + sVersion = Build.DISPLAY; + if (sVersion.toUpperCase().contains(ROM_FLYME)) { + sName = ROM_FLYME; + } else { + sVersion = Build.UNKNOWN; + sName = Build.MANUFACTURER.toUpperCase(); + } + } + return sName.equals(rom); + } + + public static String getProp(String name) { + String line = null; + BufferedReader input = null; + try { + Process p = Runtime.getRuntime().exec("getprop " + name); + input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024); + line = input.readLine(); + input.close(); + } catch (IOException ex) { + return null; + } finally { + if (input != null) { + try { + input.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return line; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/statusbar/StatusBarHeightView.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/statusbar/StatusBarHeightView.java new file mode 100644 index 0000000..8c26d5a --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/statusbar/StatusBarHeightView.java @@ -0,0 +1,67 @@ +package com.tairui.gov_affairs_cloud.widget.statusbar; + +import com.tairui.gov_affairs_cloud.R; + +import android.content.Context; +import android.content.res.TypedArray; +import android.os.Build; +import android.util.AttributeSet; +import android.widget.LinearLayout; +import androidx.annotation.Nullable; + +/** + * Created by xiezonglin on 2018/12/20. + */ + +public class StatusBarHeightView extends LinearLayout { + private int statusBarHeight; + private int type; + + public StatusBarHeightView(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(attrs); + } + + public StatusBarHeightView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(attrs); + } + + public StatusBarHeightView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr); + init(attrs); + + + } + + private void init(@Nullable AttributeSet attrs) { + + int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + if (resourceId > 0) { + statusBarHeight = getResources().getDimensionPixelSize(resourceId); + } + } else { + //低版本 直接设置0 + statusBarHeight = 0; + } + if (attrs != null) { + TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.StatusBarHeightView); + type = typedArray.getInt(R.styleable.StatusBarHeightView_use_type, 0); + typedArray.recycle(); + } + if (type == 1) { + setPadding(getPaddingLeft(), statusBarHeight, getPaddingRight(), getPaddingBottom()); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (type == 0) { + setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), + statusBarHeight); + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/statusbar/StatusBarUtil.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/statusbar/StatusBarUtil.java new file mode 100644 index 0000000..cbc9fb4 --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/statusbar/StatusBarUtil.java @@ -0,0 +1,217 @@ +package com.tairui.gov_affairs_cloud.widget.statusbar; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.graphics.Color; +import android.os.Build; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import androidx.annotation.IntDef; + +/** + * Created by xiezonglin on 2018/12/20. + */ + +public class StatusBarUtil { + + public final static int TYPE_MIUI = 0; + public final static int TYPE_FLYME = 1; + public final static int TYPE_M = 3;//6.0 + + @IntDef({TYPE_MIUI, + TYPE_FLYME, + TYPE_M}) + @Retention(RetentionPolicy.SOURCE) + @interface ViewType { + } + + /** + * 修改状态栏颜色,支持4.4以上版本 + * + * @param colorId 颜色 + */ + public static void setStatusBarColor(Activity activity, int colorId) { + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + Window window = activity.getWindow(); + window.setStatusBarColor(colorId); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + //使用SystemBarTintManager,需要先将状态栏设置为透明 + setTranslucentStatus(activity); + SystemBarTintManager systemBarTintManager = new SystemBarTintManager(activity); + systemBarTintManager.setStatusBarTintEnabled(true);//显示状态栏 + systemBarTintManager.setStatusBarTintColor(colorId);//设置状态栏颜色 + } + } + + /** + * 设置状态栏透明 + */ + @TargetApi(19) + public static void setTranslucentStatus(Activity activity) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + //5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色 + Window window = activity.getWindow(); + View decorView = window.getDecorView(); + //两个 flag 要结合使用,表示让应用的主体内容占用系统状态栏的空间 + int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_LAYOUT_STABLE; + decorView.setSystemUiVisibility(option); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(Color.TRANSPARENT); + //导航栏颜色也可以正常设置 + //window.setNavigationBarColor(Color.TRANSPARENT); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + Window window = activity.getWindow(); + WindowManager.LayoutParams attributes = window.getAttributes(); + int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; + attributes.flags |= flagTranslucentStatus; + //int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; + //attributes.flags |= flagTranslucentNavigation; + window.setAttributes(attributes); + } + } + + + /** + * 代码实现android:fitsSystemWindows + * + * @param activity + */ + public static void setRootViewFitsSystemWindows(Activity activity, boolean fitSystemWindows) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + ViewGroup winContent = (ViewGroup) activity.findViewById(android.R.id.content); + if (winContent.getChildCount() > 0) { + ViewGroup rootView = (ViewGroup) winContent.getChildAt(0); + if (rootView != null) { + rootView.setFitsSystemWindows(fitSystemWindows); + } + } + } + + } + + + /** + * 设置状态栏深色浅色切换 + */ + public static boolean setStatusBarDarkTheme(Activity activity, boolean dark) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + setStatusBarFontIconDark(activity, TYPE_M, dark); + } else if (OSUtils.isMiui()) { + setStatusBarFontIconDark(activity, TYPE_MIUI, dark); + } else if (OSUtils.isFlyme()) { + setStatusBarFontIconDark(activity, TYPE_FLYME, dark); + } else {//其他情况 + return false; + } + + return true; + } + return false; + } + + /** + * 设置 状态栏深色浅色切换 + */ + public static boolean setStatusBarFontIconDark(Activity activity, @ViewType int type, boolean dark) { + switch (type) { + case TYPE_MIUI: + return setMiuiUI(activity, dark); + case TYPE_FLYME: + return setFlymeUI(activity, dark); + case TYPE_M: + default: + return setCommonUI(activity, dark); + } + } + + //设置6.0 状态栏深色浅色切换 + public static boolean setCommonUI(Activity activity, boolean dark) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + View decorView = activity.getWindow().getDecorView(); + if (decorView != null) { + int vis = decorView.getSystemUiVisibility(); + if (dark) { + vis |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + } else { + vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + } + if (decorView.getSystemUiVisibility() != vis) { + decorView.setSystemUiVisibility(vis); + } + return true; + } + } + return false; + + } + + //设置Flyme 状态栏深色浅色切换 + public static boolean setFlymeUI(Activity activity, boolean dark) { + try { + Window window = activity.getWindow(); + WindowManager.LayoutParams lp = window.getAttributes(); + Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON"); + Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags"); + darkFlag.setAccessible(true); + meizuFlags.setAccessible(true); + int bit = darkFlag.getInt(null); + int value = meizuFlags.getInt(lp); + if (dark) { + value |= bit; + } else { + value &= ~bit; + } + meizuFlags.setInt(lp, value); + window.setAttributes(lp); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + //设置MIUI 状态栏深色浅色切换 + public static boolean setMiuiUI(Activity activity, boolean dark) { + try { + Window window = activity.getWindow(); + Class clazz = activity.getWindow().getClass(); + @SuppressLint("PrivateApi") Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams"); + Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE"); + int darkModeFlag = field.getInt(layoutParams); + Method extraFlagField = clazz.getDeclaredMethod("setExtraFlags", int.class, int.class); + extraFlagField.setAccessible(true); + if (dark) { //状态栏亮色且黑色字体 + extraFlagField.invoke(window, darkModeFlag, darkModeFlag); + } else { + extraFlagField.invoke(window, 0, darkModeFlag); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + //获取状态栏高度 + public static int getStatusBarHeight(Context context) { + int result = 0; + int resourceId = context.getResources().getIdentifier( + "status_bar_height", "dimen", "android"); + if (resourceId > 0) { + result = context.getResources().getDimensionPixelSize(resourceId); + } + return result; + } +} diff --git a/app/src/main/java/com/tairui/gov_affairs_cloud/widget/statusbar/SystemBarTintManager.java b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/statusbar/SystemBarTintManager.java new file mode 100644 index 0000000..e6fae9b --- /dev/null +++ b/app/src/main/java/com/tairui/gov_affairs_cloud/widget/statusbar/SystemBarTintManager.java @@ -0,0 +1,548 @@ +package com.tairui.gov_affairs_cloud.widget.statusbar; + +import java.lang.reflect.Method; + +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.FrameLayout.LayoutParams; + +/** + * Created by xiezonglin on 2018/12/20. + */ + +public class SystemBarTintManager { + + static { + // Android allows a system property to override the presence of the navigation bar. + // Used by the emulator. + // See https://github.com/android/platform_frameworks_base/blob/master/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java#L1076 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + try { + Class c = Class.forName("android.os.SystemProperties"); + Method m = c.getDeclaredMethod("get", String.class); + m.setAccessible(true); + sNavBarOverride = (String) m.invoke(null, "qemu.hw.mainkeys"); + } catch (Throwable e) { + sNavBarOverride = null; + } + } + } + + + /** + * The default system bar tint color value. + */ + public static final int DEFAULT_TINT_COLOR = 0x99000000; + + private static String sNavBarOverride; + + private final SystemBarConfig mConfig; + private boolean mStatusBarAvailable; + private boolean mNavBarAvailable; + private boolean mStatusBarTintEnabled; + private boolean mNavBarTintEnabled; + private View mStatusBarTintView; + private View mNavBarTintView; + + /** + * Constructor. Call this in the host activity onCreate method after its + * content view has been set. You should always create new instances when + * the host activity is recreated. + * + * @param activity The host activity. + */ + @TargetApi(19) + public SystemBarTintManager(Activity activity) { + + Window win = activity.getWindow(); + ViewGroup decorViewGroup = (ViewGroup) win.getDecorView(); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + // check theme attrs + int[] attrs = {android.R.attr.windowTranslucentStatus, + android.R.attr.windowTranslucentNavigation}; + TypedArray a = activity.obtainStyledAttributes(attrs); + try { + mStatusBarAvailable = a.getBoolean(0, false); + mNavBarAvailable = a.getBoolean(1, false); + } finally { + a.recycle(); + } + + // check window flags + WindowManager.LayoutParams winParams = win.getAttributes(); + int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; + if ((winParams.flags & bits) != 0) { + mStatusBarAvailable = true; + } + bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; + if ((winParams.flags & bits) != 0) { + mNavBarAvailable = true; + } + } + + mConfig = new SystemBarConfig(activity, mStatusBarAvailable, mNavBarAvailable); + // device might not have virtual navigation keys + if (!mConfig.hasNavigtionBar()) { + mNavBarAvailable = false; + } + + if (mStatusBarAvailable) { + setupStatusBarView(activity, decorViewGroup); + } + if (mNavBarAvailable) { + setupNavBarView(activity, decorViewGroup); + } + + } + + /** + * Enable tinting of the system status bar. + * + * If the platform is running Jelly Bean or earlier, or translucent system + * UI modes have not been enabled in either the theme or via window flags, + * then this method does nothing. + * + * @param enabled True to enable tinting, false to disable it (default). + */ + public void setStatusBarTintEnabled(boolean enabled) { + mStatusBarTintEnabled = enabled; + if (mStatusBarAvailable) { + mStatusBarTintView.setVisibility(enabled ? View.VISIBLE : View.GONE); + } + } + + /** + * Enable tinting of the system navigation bar. + * + * If the platform does not have soft navigation keys, is running Jelly Bean + * or earlier, or translucent system UI modes have not been enabled in either + * the theme or via window flags, then this method does nothing. + * + * @param enabled True to enable tinting, false to disable it (default). + */ + public void setNavigationBarTintEnabled(boolean enabled) { + mNavBarTintEnabled = enabled; + if (mNavBarAvailable) { + mNavBarTintView.setVisibility(enabled ? View.VISIBLE : View.GONE); + } + } + + /** + * Apply the specified color tint to all system UI bars. + * + * @param color The color of the background tint. + */ + public void setTintColor(int color) { + setStatusBarTintColor(color); + setNavigationBarTintColor(color); + } + + /** + * Apply the specified drawable or color resource to all system UI bars. + * + * @param res The identifier of the resource. + */ + public void setTintResource(int res) { + setStatusBarTintResource(res); + setNavigationBarTintResource(res); + } + + /** + * Apply the specified drawable to all system UI bars. + * + * @param drawable The drawable to use as the background, or null to remove it. + */ + public void setTintDrawable(Drawable drawable) { + setStatusBarTintDrawable(drawable); + setNavigationBarTintDrawable(drawable); + } + + /** + * Apply the specified alpha to all system UI bars. + * + * @param alpha The alpha to use + */ + public void setTintAlpha(float alpha) { + setStatusBarAlpha(alpha); + setNavigationBarAlpha(alpha); + } + + /** + * Apply the specified color tint to the system status bar. + * + * @param color The color of the background tint. + */ + public void setStatusBarTintColor(int color) { + if (mStatusBarAvailable) { + mStatusBarTintView.setBackgroundColor(color); + } + } + + /** + * Apply the specified drawable or color resource to the system status bar. + * + * @param res The identifier of the resource. + */ + public void setStatusBarTintResource(int res) { + if (mStatusBarAvailable) { + mStatusBarTintView.setBackgroundResource(res); + } + } + + /** + * Apply the specified drawable to the system status bar. + * + * @param drawable The drawable to use as the background, or null to remove it. + */ + @SuppressWarnings("deprecation") + public void setStatusBarTintDrawable(Drawable drawable) { + if (mStatusBarAvailable) { + mStatusBarTintView.setBackgroundDrawable(drawable); + } + } + + /** + * Apply the specified alpha to the system status bar. + * + * @param alpha The alpha to use + */ + @TargetApi(11) + public void setStatusBarAlpha(float alpha) { + if (mStatusBarAvailable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + mStatusBarTintView.setAlpha(alpha); + } + } + + /** + * Apply the specified color tint to the system navigation bar. + * + * @param color The color of the background tint. + */ + public void setNavigationBarTintColor(int color) { + if (mNavBarAvailable) { + mNavBarTintView.setBackgroundColor(color); + } + } + + /** + * Apply the specified drawable or color resource to the system navigation bar. + * + * @param res The identifier of the resource. + */ + public void setNavigationBarTintResource(int res) { + if (mNavBarAvailable) { + mNavBarTintView.setBackgroundResource(res); + } + } + + /** + * Apply the specified drawable to the system navigation bar. + * + * @param drawable The drawable to use as the background, or null to remove it. + */ + @SuppressWarnings("deprecation") + public void setNavigationBarTintDrawable(Drawable drawable) { + if (mNavBarAvailable) { + mNavBarTintView.setBackgroundDrawable(drawable); + } + } + + /** + * Apply the specified alpha to the system navigation bar. + * + * @param alpha The alpha to use + */ + @TargetApi(11) + public void setNavigationBarAlpha(float alpha) { + if (mNavBarAvailable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + mNavBarTintView.setAlpha(alpha); + } + } + + /** + * Get the system bar configuration. + * + * @return The system bar configuration for the current device configuration. + */ + public SystemBarConfig getConfig() { + return mConfig; + } + + /** + * Is tinting enabled for the system status bar? + * + * @return True if enabled, False otherwise. + */ + public boolean isStatusBarTintEnabled() { + return mStatusBarTintEnabled; + } + + /** + * Is tinting enabled for the system navigation bar? + * + * @return True if enabled, False otherwise. + */ + public boolean isNavBarTintEnabled() { + return mNavBarTintEnabled; + } + + private void setupStatusBarView(Context context, ViewGroup decorViewGroup) { + mStatusBarTintView = new View(context); + LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getStatusBarHeight()); + params.gravity = Gravity.TOP; + if (mNavBarAvailable && !mConfig.isNavigationAtBottom()) { + params.rightMargin = mConfig.getNavigationBarWidth(); + } + mStatusBarTintView.setLayoutParams(params); + mStatusBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR); + mStatusBarTintView.setVisibility(View.GONE); + decorViewGroup.addView(mStatusBarTintView); + } + + private void setupNavBarView(Context context, ViewGroup decorViewGroup) { + mNavBarTintView = new View(context); + LayoutParams params; + if (mConfig.isNavigationAtBottom()) { + params = new LayoutParams(LayoutParams.MATCH_PARENT, mConfig.getNavigationBarHeight()); + params.gravity = Gravity.BOTTOM; + } else { + params = new LayoutParams(mConfig.getNavigationBarWidth(), LayoutParams.MATCH_PARENT); + params.gravity = Gravity.RIGHT; + } + mNavBarTintView.setLayoutParams(params); + mNavBarTintView.setBackgroundColor(DEFAULT_TINT_COLOR); + mNavBarTintView.setVisibility(View.GONE); + decorViewGroup.addView(mNavBarTintView); + } + + /** + * Class which describes system bar sizing and other characteristics for the current + * device configuration. + * + */ + public static class SystemBarConfig { + + private static final String STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height"; + private static final String NAV_BAR_HEIGHT_RES_NAME = "navigation_bar_height"; + private static final String NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME = "navigation_bar_height_landscape"; + private static final String NAV_BAR_WIDTH_RES_NAME = "navigation_bar_width"; + private static final String SHOW_NAV_BAR_RES_NAME = "config_showNavigationBar"; + + private final boolean mTranslucentStatusBar; + private final boolean mTranslucentNavBar; + private final int mStatusBarHeight; + private final int mActionBarHeight; + private final boolean mHasNavigationBar; + private final int mNavigationBarHeight; + private final int mNavigationBarWidth; + private final boolean mInPortrait; + private final float mSmallestWidthDp; + + private SystemBarConfig(Activity activity, boolean translucentStatusBar, boolean traslucentNavBar) { + Resources res = activity.getResources(); + mInPortrait = (res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT); + mSmallestWidthDp = getSmallestWidthDp(activity); + mStatusBarHeight = getInternalDimensionSize(res, STATUS_BAR_HEIGHT_RES_NAME); + mActionBarHeight = getActionBarHeight(activity); + mNavigationBarHeight = getNavigationBarHeight(activity); + mNavigationBarWidth = getNavigationBarWidth(activity); + mHasNavigationBar = (mNavigationBarHeight > 0); + mTranslucentStatusBar = translucentStatusBar; + mTranslucentNavBar = traslucentNavBar; + } + + @TargetApi(14) + private int getActionBarHeight(Context context) { + int result = 0; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + TypedValue tv = new TypedValue(); + context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true); + result = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics()); + } + return result; + } + + @TargetApi(14) + private int getNavigationBarHeight(Context context) { + Resources res = context.getResources(); + int result = 0; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + if (hasNavBar(context)) { + String key; + if (mInPortrait) { + key = NAV_BAR_HEIGHT_RES_NAME; + } else { + key = NAV_BAR_HEIGHT_LANDSCAPE_RES_NAME; + } + return getInternalDimensionSize(res, key); + } + } + return result; + } + + @TargetApi(14) + private int getNavigationBarWidth(Context context) { + Resources res = context.getResources(); + int result = 0; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + if (hasNavBar(context)) { + return getInternalDimensionSize(res, NAV_BAR_WIDTH_RES_NAME); + } + } + return result; + } + + @TargetApi(14) + private boolean hasNavBar(Context context) { + Resources res = context.getResources(); + int resourceId = res.getIdentifier(SHOW_NAV_BAR_RES_NAME, "bool", "android"); + if (resourceId != 0) { + boolean hasNav = res.getBoolean(resourceId); + // check override flag (see static block) + if ("1".equals(sNavBarOverride)) { + hasNav = false; + } else if ("0".equals(sNavBarOverride)) { + hasNav = true; + } + return hasNav; + } else { // fallback + return !ViewConfiguration.get(context).hasPermanentMenuKey(); + } + } + + private int getInternalDimensionSize(Resources res, String key) { + int result = 0; + int resourceId = res.getIdentifier(key, "dimen", "android"); + if (resourceId > 0) { + result = res.getDimensionPixelSize(resourceId); + } + return result; + } + + @SuppressLint("NewApi") + private float getSmallestWidthDp(Activity activity) { + DisplayMetrics metrics = new DisplayMetrics(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + activity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics); + } else { + // this is not correct, but we don't really care pre-kitkat + activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); + } + float widthDp = metrics.widthPixels / metrics.density; + float heightDp = metrics.heightPixels / metrics.density; + return Math.min(widthDp, heightDp); + } + + /** + * Should a navigation bar appear at the bottom of the screen in the current + * device configuration? A navigation bar may appear on the right side of + * the screen in certain configurations. + * + * @return True if navigation should appear at the bottom of the screen, False otherwise. + */ + public boolean isNavigationAtBottom() { + return (mSmallestWidthDp >= 600 || mInPortrait); + } + + /** + * Get the height of the system status bar. + * + * @return The height of the status bar (in pixels). + */ + public int getStatusBarHeight() { + return mStatusBarHeight; + } + + /** + * Get the height of the action bar. + * + * @return The height of the action bar (in pixels). + */ + public int getActionBarHeight() { + return mActionBarHeight; + } + + /** + * Does this device have a system navigation bar? + * + * @return True if this device uses soft key navigation, False otherwise. + */ + public boolean hasNavigtionBar() { + return mHasNavigationBar; + } + + /** + * Get the height of the system navigation bar. + * + * @return The height of the navigation bar (in pixels). If the device does not have + * soft navigation keys, this will always return 0. + */ + public int getNavigationBarHeight() { + return mNavigationBarHeight; + } + + /** + * Get the width of the system navigation bar when it is placed vertically on the screen. + * + * @return The width of the navigation bar (in pixels). If the device does not have + * soft navigation keys, this will always return 0. + */ + public int getNavigationBarWidth() { + return mNavigationBarWidth; + } + + /** + * Get the layout inset for any system UI that appears at the top of the screen. + * + * @param withActionBar True to include the height of the action bar, False otherwise. + * @return The layout inset (in pixels). + */ + public int getPixelInsetTop(boolean withActionBar) { + return (mTranslucentStatusBar ? mStatusBarHeight : 0) + (withActionBar ? mActionBarHeight : 0); + } + + /** + * Get the layout inset for any system UI that appears at the bottom of the screen. + * + * @return The layout inset (in pixels). + */ + public int getPixelInsetBottom() { + if (mTranslucentNavBar && isNavigationAtBottom()) { + return mNavigationBarHeight; + } else { + return 0; + } + } + + /** + * Get the layout inset for any system UI that appears at the right of the screen. + * + * @return The layout inset (in pixels). + */ + public int getPixelInsetRight() { + if (mTranslucentNavBar && !isNavigationAtBottom()) { + return mNavigationBarWidth; + } else { + return 0; + } + } + + } + +} diff --git a/app/src/main/res/drawable/bg_checkbox.xml b/app/src/main/res/drawable/bg_checkbox.xml new file mode 100644 index 0000000..65055a4 --- /dev/null +++ b/app/src/main/res/drawable/bg_checkbox.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_container_blue_raduis_30.xml b/app/src/main/res/drawable/bg_container_blue_raduis_30.xml new file mode 100644 index 0000000..e6a7b24 --- /dev/null +++ b/app/src/main/res/drawable/bg_container_blue_raduis_30.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_container_blue_raduis_5.xml b/app/src/main/res/drawable/bg_container_blue_raduis_5.xml new file mode 100644 index 0000000..ca8bd5c --- /dev/null +++ b/app/src/main/res/drawable/bg_container_blue_raduis_5.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_container_green_raduis_30.xml b/app/src/main/res/drawable/bg_container_green_raduis_30.xml new file mode 100644 index 0000000..adfb9a0 --- /dev/null +++ b/app/src/main/res/drawable/bg_container_green_raduis_30.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_container_light_blue_raduis_2.xml b/app/src/main/res/drawable/bg_container_light_blue_raduis_2.xml new file mode 100644 index 0000000..ae32491 --- /dev/null +++ b/app/src/main/res/drawable/bg_container_light_blue_raduis_2.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_container_light_gray_gradient_10.xml b/app/src/main/res/drawable/bg_container_light_gray_gradient_10.xml new file mode 100644 index 0000000..4b50d6d --- /dev/null +++ b/app/src/main/res/drawable/bg_container_light_gray_gradient_10.xml @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_container_light_gray_raduis_10.xml b/app/src/main/res/drawable/bg_container_light_gray_raduis_10.xml new file mode 100644 index 0000000..05253c3 --- /dev/null +++ b/app/src/main/res/drawable/bg_container_light_gray_raduis_10.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_container_light_gray_raduis_5.xml b/app/src/main/res/drawable/bg_container_light_gray_raduis_5.xml new file mode 100644 index 0000000..fe9baf9 --- /dev/null +++ b/app/src/main/res/drawable/bg_container_light_gray_raduis_5.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_container_toast.xml b/app/src/main/res/drawable/bg_container_toast.xml new file mode 100644 index 0000000..41de98c --- /dev/null +++ b/app/src/main/res/drawable/bg_container_toast.xml @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_container_white_raduis_10.xml b/app/src/main/res/drawable/bg_container_white_raduis_10.xml new file mode 100644 index 0000000..05337be --- /dev/null +++ b/app/src/main/res/drawable/bg_container_white_raduis_10.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_container_white_raduis_10_border.xml b/app/src/main/res/drawable/bg_container_white_raduis_10_border.xml new file mode 100644 index 0000000..38354bd --- /dev/null +++ b/app/src/main/res/drawable/bg_container_white_raduis_10_border.xml @@ -0,0 +1,14 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_container_white_raduis_15.xml b/app/src/main/res/drawable/bg_container_white_raduis_15.xml new file mode 100644 index 0000000..3b91be5 --- /dev/null +++ b/app/src/main/res/drawable/bg_container_white_raduis_15.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_container_white_raduis_5.xml b/app/src/main/res/drawable/bg_container_white_raduis_5.xml new file mode 100644 index 0000000..97e0ca3 --- /dev/null +++ b/app/src/main/res/drawable/bg_container_white_raduis_5.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_container_white_raduis_5_blue_border.xml b/app/src/main/res/drawable/bg_container_white_raduis_5_blue_border.xml new file mode 100644 index 0000000..a38f0a3 --- /dev/null +++ b/app/src/main/res/drawable/bg_container_white_raduis_5_blue_border.xml @@ -0,0 +1,14 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_container_white_raduis_5_border.xml b/app/src/main/res/drawable/bg_container_white_raduis_5_border.xml new file mode 100644 index 0000000..d69fb70 --- /dev/null +++ b/app/src/main/res/drawable/bg_container_white_raduis_5_border.xml @@ -0,0 +1,14 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_gradient_white.xml b/app/src/main/res/drawable/bg_gradient_white.xml new file mode 100644 index 0000000..8d87d36 --- /dev/null +++ b/app/src/main/res/drawable/bg_gradient_white.xml @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/checkbox_checked.xml b/app/src/main/res/drawable/checkbox_checked.xml new file mode 100644 index 0000000..59cb530 --- /dev/null +++ b/app/src/main/res/drawable/checkbox_checked.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/checkbox_unchecked.xml b/app/src/main/res/drawable/checkbox_unchecked.xml new file mode 100644 index 0000000..db3dadc --- /dev/null +++ b/app/src/main/res/drawable/checkbox_unchecked.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/container_timer_normal.xml b/app/src/main/res/drawable/container_timer_normal.xml new file mode 100644 index 0000000..2fc73ed --- /dev/null +++ b/app/src/main/res/drawable/container_timer_normal.xml @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/container_timer_press.xml b/app/src/main/res/drawable/container_timer_press.xml new file mode 100644 index 0000000..ebe4479 --- /dev/null +++ b/app/src/main/res/drawable/container_timer_press.xml @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/container_timer_selector.xml b/app/src/main/res/drawable/container_timer_selector.xml new file mode 100644 index 0000000..f8a2e0f --- /dev/null +++ b/app/src/main/res/drawable/container_timer_selector.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/custom_cursor.xml b/app/src/main/res/drawable/custom_cursor.xml new file mode 100644 index 0000000..57d70f7 --- /dev/null +++ b/app/src/main/res/drawable/custom_cursor.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dashed_border.xml b/app/src/main/res/drawable/dashed_border.xml new file mode 100644 index 0000000..1553dd7 --- /dev/null +++ b/app/src/main/res/drawable/dashed_border.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/dialog_bg.xml b/app/src/main/res/drawable/dialog_bg.xml new file mode 100644 index 0000000..cd21b0f --- /dev/null +++ b/app/src/main/res/drawable/dialog_bg.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_map_draw_point_white.xml b/app/src/main/res/drawable/shape_map_draw_point_white.xml new file mode 100644 index 0000000..140630e --- /dev/null +++ b/app/src/main/res/drawable/shape_map_draw_point_white.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/app/src/main/res/drawable/vector_drawable_back_black.xml b/app/src/main/res/drawable/vector_drawable_back_black.xml new file mode 100644 index 0000000..22f150b --- /dev/null +++ b/app/src/main/res/drawable/vector_drawable_back_black.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/vector_drawable_back_white.xml b/app/src/main/res/drawable/vector_drawable_back_white.xml new file mode 100644 index 0000000..cbb94ae --- /dev/null +++ b/app/src/main/res/drawable/vector_drawable_back_white.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_add_land.xml b/app/src/main/res/layout/activity_add_land.xml new file mode 100644 index 0000000..90b0658 --- /dev/null +++ b/app/src/main/res/layout/activity_add_land.xml @@ -0,0 +1,441 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +