├── .gitignore ├── README.md ├── README_English.md ├── README_Japanese.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ ├── cn │ │ └── finalteam │ │ │ └── rxgalleryfinal │ │ │ ├── Configuration.java │ │ │ ├── RxGalleryFinal.java │ │ │ ├── RxGalleryFinalApi.java │ │ │ ├── anim │ │ │ ├── Animation.java │ │ │ ├── AnimationListener.java │ │ │ ├── SlideInUnderneathAnimation.java │ │ │ └── SlideOutUnderneathAnimation.java │ │ │ ├── bean │ │ │ ├── BucketBean.java │ │ │ ├── ImageCropBean.java │ │ │ ├── MediaBean.java │ │ │ └── package-info.java │ │ │ ├── imageloader │ │ │ ├── AbsImageLoader.java │ │ │ ├── FrescoImageLoader.java │ │ │ ├── GlideImageLoader.java │ │ │ ├── ImageLoaderType.java │ │ │ ├── PicassoImageLoader.java │ │ │ ├── UniversalImageLoader.java │ │ │ └── rotate │ │ │ │ └── RotateTransformation.java │ │ │ ├── interactor │ │ │ ├── MediaBucketFactoryInteractor.java │ │ │ ├── MediaSrcFactoryInteractor.java │ │ │ ├── impl │ │ │ │ ├── MediaBucketFactoryInteractorImpl.java │ │ │ │ ├── MediaSrcFactoryInteractorImpl.java │ │ │ │ └── package-info.java │ │ │ └── package-info.java │ │ │ ├── package-info.java │ │ │ ├── presenter │ │ │ ├── MediaGridPresenter.java │ │ │ ├── impl │ │ │ │ ├── MediaGridPresenterImpl.java │ │ │ │ └── package-info.java │ │ │ └── package-info.java │ │ │ ├── rxbus │ │ │ ├── RxBus.java │ │ │ ├── RxBusDisposable.java │ │ │ ├── RxBusResultDisposable.java │ │ │ ├── event │ │ │ │ ├── BaseResultEvent.java │ │ │ │ ├── CloseMediaViewPageFragmentEvent.java │ │ │ │ ├── CloseRxMediaGridPageEvent.java │ │ │ │ ├── ImageMultipleResultEvent.java │ │ │ │ ├── ImageRadioResultEvent.java │ │ │ │ ├── MediaCheckChangeEvent.java │ │ │ │ ├── MediaViewPagerChangedEvent.java │ │ │ │ ├── OpenMediaPageFragmentEvent.java │ │ │ │ ├── OpenMediaPreviewFragmentEvent.java │ │ │ │ ├── RequestStorageReadAccessPermissionEvent.java │ │ │ │ └── package-info.java │ │ │ └── package-info.java │ │ │ ├── rxjob │ │ │ ├── Job.java │ │ │ ├── JobCreator.java │ │ │ ├── JobManager.java │ │ │ ├── RxJob.java │ │ │ ├── job │ │ │ │ ├── ImageThmbnailJob.java │ │ │ │ ├── ImageThmbnailJobCreate.java │ │ │ │ └── package-info.java │ │ │ └── package-info.java │ │ │ ├── ui │ │ │ ├── RxGalleryListener.java │ │ │ ├── activity │ │ │ │ ├── BaseActivity.java │ │ │ │ ├── MediaActivity.java │ │ │ │ └── package-info.java │ │ │ ├── adapter │ │ │ │ ├── BucketAdapter.java │ │ │ │ ├── MediaGridAdapter.java │ │ │ │ ├── MediaPreviewAdapter.java │ │ │ │ ├── RecyclingPagerAdapter.java │ │ │ │ └── package-info.java │ │ │ ├── base │ │ │ │ ├── IMultiImageCheckedListener.java │ │ │ │ └── IRadioImageCheckedListener.java │ │ │ ├── fragment │ │ │ │ ├── BaseFragment.java │ │ │ │ ├── MediaGridFragment.java │ │ │ │ ├── MediaPageFragment.java │ │ │ │ ├── MediaPreviewFragment.java │ │ │ │ └── package-info.java │ │ │ ├── package-info.java │ │ │ └── widget │ │ │ │ ├── FixImageView.java │ │ │ │ ├── FixViewPager.java │ │ │ │ ├── FlexibleDividerDecoration.java │ │ │ │ ├── FooterAdapter.java │ │ │ │ ├── HorizontalDividerItemDecoration.java │ │ │ │ ├── MarginDecoration.java │ │ │ │ ├── RecyclerViewFinal.java │ │ │ │ ├── SquareImageView.java │ │ │ │ ├── SquareLinearLayout.java │ │ │ │ ├── SquareRelativeLayout.java │ │ │ │ └── package-info.java │ │ │ ├── utils │ │ │ ├── BitmapUtils.java │ │ │ ├── CameraUtils.java │ │ │ ├── DeviceUtils.java │ │ │ ├── EmptyViewUtils.java │ │ │ ├── FileUtils.java │ │ │ ├── FilenameUtils.java │ │ │ ├── IOUtils.java │ │ │ ├── Logger.java │ │ │ ├── MediaScanner.java │ │ │ ├── MediaType.java │ │ │ ├── MediaUtils.java │ │ │ ├── ModelUtils.java │ │ │ ├── OsCompat.java │ │ │ ├── PermissionCheckUtils.java │ │ │ ├── SimpleDateUtils.java │ │ │ ├── StorageUtils.java │ │ │ ├── ThemeUtils.java │ │ │ └── package-info.java │ │ │ └── view │ │ │ ├── ActivityFragmentView.java │ │ │ ├── MediaGridView.java │ │ │ └── package-info.java │ └── uk │ │ └── co │ │ └── senab │ │ └── photoview │ │ ├── Compat.java │ │ ├── DefaultOnDoubleTapListener.java │ │ ├── IPhotoView.java │ │ ├── PhotoView.java │ │ ├── PhotoViewAttacher.java │ │ ├── gestures │ │ ├── CupcakeGestureDetector.java │ │ ├── EclairGestureDetector.java │ │ ├── FroyoGestureDetector.java │ │ ├── GestureDetector.java │ │ ├── OnGestureListener.java │ │ └── VersionedGestureDetector.java │ │ └── scrollerproxy │ │ ├── GingerScroller.java │ │ ├── IcsScroller.java │ │ ├── PreGingerScroller.java │ │ └── ScrollerProxy.java │ └── res │ ├── color │ └── gallery_text_color_selector.xml │ ├── drawable-hdpi │ └── gallery_ic_cross.png │ ├── drawable-ldpi │ └── gallery_ic_cross.png │ ├── drawable-mdpi │ └── gallery_ic_cross.png │ ├── drawable-xhdpi │ └── gallery_ic_cross.png │ ├── drawable-xxhdpi-v4 │ └── gallery_ic_corner_gray.png │ ├── drawable-xxhdpi │ ├── gallery_bg_bucket.9.png │ ├── gallery_ic_camera.png │ └── gallery_ic_cross.png │ ├── drawable-xxxhdpi │ ├── gallery_ic_corner_selector.xml │ └── gallery_ic_cross.png │ ├── drawable │ ├── gallery_bucket_item_selector.xml │ ├── gallery_button_selector.xml │ └── gallery_default_image.xml │ ├── layout │ ├── gallery_activity_media.xml │ ├── gallery_adapter_bucket_item.xml │ ├── gallery_fragment_media_grid.xml │ ├── gallery_fragment_media_page.xml │ ├── gallery_fragment_media_preview.xml │ ├── gallery_loading_view_final_footer_default.xml │ ├── gallery_media_image_preview_item.xml │ ├── item_gallery_media_grid.xml │ └── item_gallery_media_grid_fresco.xml │ └── values │ ├── gallery_attrs.xml │ ├── gallery_default_theme.xml │ ├── gallery_dimens.xml │ └── gallery_strings.xml ├── sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── cn │ │ └── finalteam │ │ └── rxgalleryfinal │ │ └── sample │ │ ├── IApplication.java │ │ ├── MainActivity.java │ │ ├── SimpleRxGalleryFinal.java │ │ └── imageloader │ │ └── ImageLoaderActivity.java │ └── res │ ├── layout │ ├── activity_imageloader.xml │ └── activity_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ ├── a1.png │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ ├── styles.xml │ └── themes.xml ├── screenshots ├── a1.png ├── device-2017-03-24-181216.png └── device-2017-04-11-154816.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/android,intellij,osx,windows,gradle,maven 3 | 4 | ### Android ### 5 | # Built application files 6 | #*.apk 7 | *.ap_ 8 | 9 | # Files for the Dalvik VM 10 | *.dex 11 | 12 | # Java class files 13 | *.class 14 | 15 | # Generated files 16 | bin/ 17 | gen/ 18 | out/ 19 | 20 | # Gradle files 21 | .gradle/ 22 | build/ 23 | gradle.properties 24 | 25 | # Local configuration file (sdk path, etc) 26 | local.properties 27 | 28 | # Proguard folder generated by Eclipse 29 | proguard/ 30 | 31 | # Log Files 32 | *.log 33 | 34 | # Android Studio Navigation editor temp files 35 | .navigation/ 36 | 37 | # Android Studio captures folder 38 | captures/ 39 | 40 | # Intellij 41 | *.iml 42 | 43 | # Keystore files 44 | *.jks 45 | 46 | ### Android Patch ### 47 | gen-external-apklibs 48 | 49 | 50 | ### Intellij ### 51 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 52 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 53 | 54 | # User-specific stuff: 55 | .idea/* 56 | .idea/workspace.xml 57 | .idea/tasks.xml 58 | .idea/dictionaries 59 | .idea/vcs.xml 60 | .idea/jsLibraryMappings.xml 61 | 62 | # Sensitive or high-churn files: 63 | .idea/dataSources.ids 64 | .idea/dataSources.xml 65 | .idea/dataSources.local.xml 66 | .idea/sqlDataSources.xml 67 | .idea/dynamic.xml 68 | .idea/uiDesigner.xml 69 | 70 | # Gradle: 71 | .idea/gradle.xml 72 | .idea/libraries 73 | 74 | # Mongo Explorer plugin: 75 | .idea/mongoSettings.xml 76 | 77 | ## File-based project format: 78 | *.iws 79 | 80 | ## Plugin-specific files: 81 | 82 | # IntelliJ 83 | /out/ 84 | 85 | # mpeltonen/sbt-idea plugin 86 | .idea_modules/ 87 | 88 | # JIRA plugin 89 | atlassian-ide-plugin.xml 90 | 91 | # Crashlytics plugin (for Android Studio and IntelliJ) 92 | com_crashlytics_export_strings.xml 93 | crashlytics.properties 94 | crashlytics-build.properties 95 | fabric.properties 96 | 97 | ### Intellij Patch ### 98 | *.iml 99 | 100 | 101 | ### OSX ### 102 | .DS_Store 103 | .AppleDouble 104 | .LSOverride 105 | 106 | # Icon must end with two \r 107 | Icon 108 | 109 | 110 | # Thumbnails 111 | ._* 112 | 113 | # Files that might appear in the root of a volume 114 | .DocumentRevisions-V100 115 | .fseventsd 116 | .Spotlight-V100 117 | .TemporaryItems 118 | .Trashes 119 | .VolumeIcon.icns 120 | 121 | # Directories potentially created on remote AFP share 122 | .AppleDB 123 | .AppleDesktop 124 | Network Trash Folder 125 | Temporary Items 126 | .apdisk 127 | 128 | 129 | ### Windows ### 130 | # Windows image file caches 131 | Thumbs.db 132 | ehthumbs.db 133 | 134 | # Folder config file 135 | Desktop.ini 136 | 137 | # Recycle Bin used on file shares 138 | $RECYCLE.BIN/ 139 | 140 | # Windows Installer files 141 | *.cab 142 | *.msi 143 | *.msm 144 | *.msp 145 | 146 | # Windows shortcuts 147 | *.lnk 148 | 149 | 150 | ### Maven ### 151 | target/ 152 | pom.xml.tag 153 | pom.xml.releaseBackup 154 | pom.xml.versionsBackup 155 | pom.xml.next 156 | release.properties 157 | dependency-reduced-pom.xml 158 | buildNumber.properties 159 | .mvn/timing.properties 160 | 161 | ### Gradle ### 162 | .gradle 163 | build/ 164 | 165 | # Ignore Gradle GUI config 166 | gradle-app.setting 167 | 168 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 169 | !gradle-wrapper.jar 170 | 171 | # Cache of project 172 | .gradletasknamecache 173 | 174 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 175 | # gradle/wrapper/gradle-wrapper.properties 176 | .idea/ 177 | docs/device-2016-06-08-155613.png 178 | docs/device-2016-07-04-183837.png 179 | docs/device-2016-07-04-183909.png 180 | library/libs/ 181 | sample/libs/ 182 | sample/src/main/res/drawable/ 183 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | mavenCentral() 5 | google() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.5.2' 9 | classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0' 10 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4' 11 | } 12 | } 13 | allprojects { 14 | repositories { 15 | google() 16 | jcenter() 17 | maven { url "https://jitpack.io" } 18 | } 19 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | android.useAndroidX=true 2 | android.enableJetifier=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FinalTeam/RxGalleryFinal/e61b3085605fdf5125ce9ef2d02f13720aa64702/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Nov 27 20:13:24 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | ############################################################################## 5 | ## 6 | ## Gradle start up script for UN*X 7 | ## 8 | ############################################################################## 9 | 10 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 11 | DEFAULT_JVM_OPTS="" 12 | 13 | APP_NAME="Gradle" 14 | APP_BASE_NAME=`basename "$0"` 15 | 16 | # Use the maximum available, or set MAX_FD != -1 to use that value. 17 | MAX_FD="maximum" 18 | 19 | warn ( ) { 20 | echo "$*" 21 | } 22 | 23 | die ( ) { 24 | echo 25 | echo "$*" 26 | echo 27 | exit 1 28 | } 29 | 30 | # OS specific support (must be 'true' or 'false'). 31 | cygwin=false 32 | msys=false 33 | darwin=false 34 | case "`uname`" in 35 | CYGWIN* ) 36 | cygwin=true 37 | ;; 38 | Darwin* ) 39 | darwin=true 40 | ;; 41 | MINGW* ) 42 | msys=true 43 | ;; 44 | esac 45 | 46 | # Attempt to set APP_HOME 47 | # Resolve links: $0 may be a link 48 | PRG="$0" 49 | # Need this for relative symlinks. 50 | while [ -h "$PRG" ] ; do 51 | ls=`ls -ld "$PRG"` 52 | link=`expr "$ls" : '.*-> \(.*\)$'` 53 | if expr "$link" : '/.*' > /dev/null; then 54 | PRG="$link" 55 | else 56 | PRG=`dirname "$PRG"`"/$link" 57 | fi 58 | done 59 | SAVED="`pwd`" 60 | cd "`dirname \"$PRG\"`/" >/dev/null 61 | APP_HOME="`pwd -P`" 62 | cd "$SAVED" >/dev/null 63 | 64 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 65 | 66 | # Determine the Java command to use to start the JVM. 67 | if [ -n "$JAVA_HOME" ] ; then 68 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 69 | # IBM's JDK on AIX uses strange locations for the executables 70 | JAVACMD="$JAVA_HOME/jre/sh/java" 71 | else 72 | JAVACMD="$JAVA_HOME/bin/java" 73 | fi 74 | if [ ! -x "$JAVACMD" ] ; then 75 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 76 | 77 | Please set the JAVA_HOME variable in your environment to match the 78 | location of your Java installation." 79 | fi 80 | else 81 | JAVACMD="java" 82 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 83 | 84 | Please set the JAVA_HOME variable in your environment to match the 85 | location of your Java installation." 86 | fi 87 | 88 | # Increase the maximum file descriptors if we can. 89 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 90 | MAX_FD_LIMIT=`ulimit -H -n` 91 | if [ $? -eq 0 ] ; then 92 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 93 | MAX_FD="$MAX_FD_LIMIT" 94 | fi 95 | ulimit -n $MAX_FD 96 | if [ $? -ne 0 ] ; then 97 | warn "Could not set maximum file descriptor limit: $MAX_FD" 98 | fi 99 | else 100 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 101 | fi 102 | fi 103 | 104 | # For Darwin, add options to specify how the application appears in the dock 105 | if $darwin; then 106 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 107 | fi 108 | 109 | # For Cygwin, switch paths to Windows format before running java 110 | if $cygwin ; then 111 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 112 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 113 | JAVACMD=`cygpath --unix "$JAVACMD"` 114 | 115 | # We build the pattern for arguments to be converted via cygpath 116 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 117 | SEP="" 118 | for dir in $ROOTDIRSRAW ; do 119 | ROOTDIRS="$ROOTDIRS$SEP$dir" 120 | SEP="|" 121 | done 122 | OURCYGPATTERN="(^($ROOTDIRS))" 123 | # Add a user-defined pattern to the cygpath arguments 124 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 125 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 126 | fi 127 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 128 | i=0 129 | for arg in "$@" ; do 130 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 131 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 132 | 133 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 134 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 135 | else 136 | eval `echo args$i`="\"$arg\"" 137 | fi 138 | i=$((i+1)) 139 | done 140 | case $i in 141 | (0) set -- ;; 142 | (1) set -- "$args0" ;; 143 | (2) set -- "$args0" "$args1" ;; 144 | (3) set -- "$args0" "$args1" "$args2" ;; 145 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 146 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 147 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 148 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 149 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 150 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 151 | esac 152 | fi 153 | 154 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 155 | function splitJvmOpts() { 156 | JVM_OPTS=("$@") 157 | } 158 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 159 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 160 | 161 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 162 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | 9 | @rem Set local scope for the variables with windows NT shell 10 | if "%OS%"=="Windows_NT" setlocal 11 | 12 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 13 | set DEFAULT_JVM_OPTS= 14 | 15 | set DIRNAME=%~dp0 16 | if "%DIRNAME%" == "" set DIRNAME=. 17 | set APP_BASE_NAME=%~n0 18 | set APP_HOME=%DIRNAME% 19 | 20 | @rem Find java.exe 21 | if defined JAVA_HOME goto findJavaFromJavaHome 22 | 23 | set JAVA_EXE=java.exe 24 | %JAVA_EXE% -version >NUL 2>&1 25 | if "%ERRORLEVEL%" == "0" goto init 26 | 27 | echo. 28 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 29 | echo. 30 | echo Please set the JAVA_HOME variable in your environment to match the 31 | echo location of your Java installation. 32 | 33 | goto fail 34 | 35 | :findJavaFromJavaHome 36 | set JAVA_HOME=%JAVA_HOME:"=% 37 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 38 | 39 | if exist "%JAVA_EXE%" goto init 40 | 41 | echo. 42 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 43 | echo. 44 | echo Please set the JAVA_HOME variable in your environment to match the 45 | echo location of your Java installation. 46 | 47 | goto fail 48 | 49 | :init 50 | @rem Get command-line arguments, handling Windowz variants 51 | 52 | if not "%OS%" == "Windows_NT" goto win9xME_args 53 | if "%@eval[2+2]" == "4" goto 4NT_args 54 | 55 | :win9xME_args 56 | @rem Slurp the command line arguments. 57 | set CMD_LINE_ARGS= 58 | set _SKIP=2 59 | 60 | :win9xME_args_slurp 61 | if "x%~1" == "x" goto execute 62 | 63 | set CMD_LINE_ARGS=%* 64 | goto execute 65 | 66 | :4NT_args 67 | @rem Get arguments from the 4NT Shell from JP Software 68 | set CMD_LINE_ARGS=%$ 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | @rem Execute Gradle 76 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 77 | 78 | :end 79 | @rem End local scope for the variables with windows NT shell 80 | if "%ERRORLEVEL%"=="0" goto mainEnd 81 | 82 | :fail 83 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 84 | rem the _cmd.exe /c_ return code! 85 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 86 | exit /b 1 87 | 88 | :mainEnd 89 | if "%OS%"=="Windows_NT" endlocal 90 | 91 | :omega 92 | -------------------------------------------------------------------------------- /library/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /library/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'com.github.dcendents.android-maven' 3 | apply plugin: "com.jfrog.bintray" 4 | 5 | version = "1.1.3" 6 | 7 | android { 8 | compileSdkVersion 28 9 | defaultConfig { 10 | minSdkVersion 14 11 | //noinspection OldTargetApi 12 | targetSdkVersion 28 13 | versionCode 3 14 | versionName version 15 | vectorDrawables.useSupportLibrary = true 16 | } 17 | lintOptions { 18 | abortOnError false 19 | checkReleaseBuilds false 20 | } 21 | resourcePrefix "gallery_" 22 | compileOptions { 23 | sourceCompatibility JavaVersion.VERSION_1_8 24 | targetCompatibility JavaVersion.VERSION_1_8 25 | } 26 | } 27 | dependencies { 28 | implementation 'androidx.appcompat:appcompat:1.1.0' 29 | implementation 'androidx.recyclerview:recyclerview:1.1.0' 30 | implementation 'androidx.exifinterface:exifinterface:1.1.0' 31 | 32 | implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' 33 | implementation 'io.reactivex.rxjava2:rxjava:2.2.15' 34 | implementation 'com.github.yalantis:ucrop:2.2.4' 35 | implementation 'com.squareup.picasso:picasso:2.71828' 36 | implementation 'com.facebook.fresco:fresco:2.0.0' 37 | implementation 'com.facebook.fresco:animated-gif:2.0.0' 38 | implementation 'com.github.bumptech.glide:glide:4.10.0' 39 | implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' 40 | } 41 | def siteUrl = 'https://github.com/FinalTeam/RxGalleryFinal' 42 | def gitUrl = 'https://github.com/FinalTeam/RxGalleryFinal.git' 43 | group = "cn.finalteam.rxgalleryfinal" 44 | install { 45 | repositories.mavenInstaller { 46 | pom { 47 | project { 48 | packaging 'aar' 49 | name 'RxGalleryFinal' 50 | description = 'dujinyang desc' 51 | url siteUrl 52 | licenses { 53 | license { 54 | name 'The Apache Software License, Version 2.0' 55 | url 'http://www.apache.org/licenses/LICENSE-2.0.txt' 56 | } 57 | } 58 | developers { 59 | developer { 60 | id 'dujinyang' 61 | name 'dujinyang' 62 | email '309933706@qq.com' 63 | } 64 | } 65 | scm { 66 | connection gitUrl 67 | developerConnection gitUrl 68 | url siteUrl 69 | } 70 | } 71 | } 72 | } 73 | } 74 | 75 | task sourcesJar(type: Jar) { 76 | from android.sourceSets.main.java.srcDirs 77 | classifier = 'sources' 78 | } 79 | 80 | artifacts { 81 | archives sourcesJar 82 | } 83 | 84 | Properties properties = new Properties() 85 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 86 | 87 | bintray { 88 | user = properties.getProperty("bintray.user") 89 | key = properties.getProperty("bintray.apikey") 90 | 91 | configurations = ['archives'] 92 | pkg { 93 | repo = "maven" 94 | name = "RxGalleryFinal" 95 | websiteUrl = siteUrl 96 | vcsUrl = gitUrl 97 | licenses = ["Apache-2.0"] 98 | publish = true 99 | version { 100 | gpg { 101 | passphrase = properties.getProperty("bintray.gpg.password") 102 | } 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /library/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/pengjianbo Dujinyang Dujinyang/Documents/dev/android_dev/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -dontwarn java.lang.invoke.* -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/anim/Animation.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.anim; 2 | 3 | import android.view.View; 4 | 5 | /** 6 | * The parent class of all animation classes. 7 | */ 8 | public abstract class Animation { 9 | 10 | public static final int DIRECTION_DOWN = 4; 11 | public static final int DURATION_DEFAULT = 300; // 300 ms 12 | // constants 13 | static final int DIRECTION_LEFT = 1; 14 | static final int DIRECTION_RIGHT = 2; 15 | static final int DIRECTION_UP = 3; 16 | static final int DURATION_LONG = 500; // 500 ms 17 | 18 | View view; 19 | 20 | /** 21 | * This method animates the properties of the view specific to the Animation 22 | * object. 23 | */ 24 | public abstract void animate(); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/anim/AnimationListener.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.anim; 2 | 3 | /** 4 | * This interface is a custom listener to determine the end of an animation. 5 | * 6 | * @author Phu 7 | */ 8 | public interface AnimationListener { 9 | 10 | /** 11 | * This method is called when the animation ends. 12 | * 13 | * @param animation The Animation object. 14 | */ 15 | void onAnimationEnd(Animation animation); 16 | } 17 | 18 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/anim/SlideInUnderneathAnimation.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.anim; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.animation.ObjectAnimator; 6 | import android.animation.TimeInterpolator; 7 | import android.annotation.TargetApi; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.view.animation.AccelerateDecelerateInterpolator; 11 | import android.widget.FrameLayout; 12 | 13 | /** 14 | * This animation causes the view to slide in underneath from its own borders. 15 | * 16 | * @author SiYao 17 | */ 18 | @TargetApi(14) 19 | public class SlideInUnderneathAnimation extends Animation { 20 | 21 | private int direction; 22 | private TimeInterpolator interpolator; 23 | private long duration; 24 | private AnimationListener listener; 25 | 26 | /** 27 | * This animation causes the view to slide in underneath from its own 28 | * borders. 29 | * 30 | * @param view The view to be animated. 31 | */ 32 | public SlideInUnderneathAnimation(View view) { 33 | this.view = view; 34 | direction = DIRECTION_LEFT; 35 | interpolator = new AccelerateDecelerateInterpolator(); 36 | duration = DURATION_LONG; 37 | listener = null; 38 | } 39 | 40 | @Override 41 | public void animate() { 42 | final ViewGroup parentView = (ViewGroup) view.getParent(); 43 | final FrameLayout slideInFrame = new FrameLayout(view.getContext()); 44 | final int positionView = parentView.indexOfChild(view); 45 | slideInFrame.setLayoutParams(view.getLayoutParams()); 46 | slideInFrame.setClipChildren(true); 47 | parentView.removeView(view); 48 | slideInFrame.addView(view); 49 | parentView.addView(slideInFrame, positionView); 50 | 51 | ObjectAnimator slideInAnim = null; 52 | float viewWidth = view.getWidth(), viewHeight = view.getHeight(); 53 | switch (direction) { 54 | case DIRECTION_LEFT: 55 | view.setTranslationX(-viewWidth); 56 | slideInAnim = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, 57 | slideInFrame.getX()); 58 | break; 59 | case DIRECTION_RIGHT: 60 | view.setTranslationX(viewWidth); 61 | slideInAnim = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, 62 | slideInFrame.getX()); 63 | break; 64 | case DIRECTION_UP: 65 | view.setTranslationY(-viewHeight); 66 | slideInAnim = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, 67 | slideInFrame.getY()); 68 | break; 69 | case DIRECTION_DOWN: 70 | view.setTranslationY(viewHeight); 71 | slideInAnim = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, 72 | slideInFrame.getY()); 73 | break; 74 | default: 75 | break; 76 | } 77 | if (slideInAnim == null) { 78 | return; 79 | } 80 | slideInAnim.setInterpolator(interpolator); 81 | slideInAnim.setDuration(duration); 82 | slideInAnim.addListener(new AnimatorListenerAdapter() { 83 | 84 | @Override 85 | public void onAnimationStart(Animator animation) { 86 | view.setVisibility(View.VISIBLE); 87 | } 88 | 89 | @Override 90 | public void onAnimationEnd(Animator animation) { 91 | slideInFrame.removeAllViews(); 92 | view.setLayoutParams(slideInFrame.getLayoutParams()); 93 | parentView.addView(view, positionView); 94 | if (getListener() != null) { 95 | getListener().onAnimationEnd( 96 | SlideInUnderneathAnimation.this); 97 | } 98 | } 99 | }); 100 | slideInAnim.start(); 101 | } 102 | 103 | /** 104 | * The available directions to slide in from are DIRECTION_LEFT 105 | * , DIRECTION_RIGHT, DIRECTION_TOP and 106 | * DIRECTION_BOTTOM. 107 | * 108 | * @return The direction to slide the view in from. 109 | * @see Animation 110 | */ 111 | public int getDirection() { 112 | return direction; 113 | } 114 | 115 | /** 116 | * The available directions to slide in from are DIRECTION_LEFT 117 | * , DIRECTION_RIGHT, DIRECTION_TOP and 118 | * DIRECTION_BOTTOM. 119 | * 120 | * @param direction The direction to set to slide the view in from. 121 | * @return This object, allowing calls to methods in this class to be 122 | * chained. 123 | * @see Animation 124 | */ 125 | public SlideInUnderneathAnimation setDirection(int direction) { 126 | this.direction = direction; 127 | return this; 128 | } 129 | 130 | /** 131 | * @return The interpolator of the entire animation. 132 | */ 133 | public TimeInterpolator getInterpolator() { 134 | return interpolator; 135 | } 136 | 137 | /** 138 | * @param interpolator The interpolator of the entire animation to set. 139 | */ 140 | public SlideInUnderneathAnimation setInterpolator( 141 | TimeInterpolator interpolator) { 142 | this.interpolator = interpolator; 143 | return this; 144 | } 145 | 146 | /** 147 | * @return The duration of the entire animation. 148 | */ 149 | public long getDuration() { 150 | return duration; 151 | } 152 | 153 | /** 154 | * @param duration The duration of the entire animation to set. 155 | * @return This object, allowing calls to methods in this class to be 156 | * chained. 157 | */ 158 | public SlideInUnderneathAnimation setDuration(long duration) { 159 | this.duration = duration; 160 | return this; 161 | } 162 | 163 | /** 164 | * @return The listener for the end of the animation. 165 | */ 166 | private AnimationListener getListener() { 167 | return listener; 168 | } 169 | 170 | /** 171 | * @param listener The listener to set for the end of the animation. 172 | * @return This object, allowing calls to methods in this class to be 173 | * chained. 174 | */ 175 | public SlideInUnderneathAnimation setListener(AnimationListener listener) { 176 | this.listener = listener; 177 | return this; 178 | } 179 | 180 | } 181 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/anim/SlideOutUnderneathAnimation.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.anim; 2 | 3 | import android.animation.Animator; 4 | import android.animation.AnimatorListenerAdapter; 5 | import android.animation.AnimatorSet; 6 | import android.animation.ObjectAnimator; 7 | import android.animation.TimeInterpolator; 8 | import android.animation.ValueAnimator; 9 | import android.annotation.TargetApi; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.view.animation.AccelerateDecelerateInterpolator; 13 | import android.widget.FrameLayout; 14 | 15 | /** 16 | * This animation causes the view to slide out underneath to its own borders. On 17 | * animation end, the view is restored to its original state and is set to 18 | * View.INVISIBLE. 19 | * 20 | * @author SiYao 21 | */ 22 | @TargetApi(14) 23 | public class SlideOutUnderneathAnimation extends Animation { 24 | 25 | private int direction; 26 | private TimeInterpolator interpolator; 27 | private long duration; 28 | private AnimationListener listener; 29 | private ValueAnimator slideAnim; 30 | 31 | /** 32 | * This animation causes the view to slide out underneath to its own 33 | * borders. On animation end, the view is restored to its original state and 34 | * is set to View.INVISIBLE. 35 | * 36 | * @param view The view to be animated. 37 | */ 38 | public SlideOutUnderneathAnimation(View view) { 39 | this.view = view; 40 | direction = DIRECTION_LEFT; 41 | interpolator = new AccelerateDecelerateInterpolator(); 42 | duration = DURATION_LONG; 43 | listener = null; 44 | } 45 | 46 | @Override 47 | public void animate() { 48 | final ViewGroup parentView = (ViewGroup) view.getParent(); 49 | final FrameLayout slideOutFrame = new FrameLayout(view.getContext()); 50 | final int positionView = parentView.indexOfChild(view); 51 | slideOutFrame.setLayoutParams(view.getLayoutParams()); 52 | slideOutFrame.setClipChildren(true); 53 | parentView.removeView(view); 54 | slideOutFrame.addView(view); 55 | parentView.addView(slideOutFrame, positionView); 56 | 57 | switch (direction) { 58 | case DIRECTION_LEFT: 59 | slideAnim = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, 60 | view.getTranslationX() - view.getWidth()); 61 | break; 62 | case DIRECTION_RIGHT: 63 | slideAnim = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, 64 | view.getTranslationX() + view.getWidth()); 65 | break; 66 | case DIRECTION_UP: 67 | slideAnim = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, 68 | view.getTranslationY() - view.getHeight()); 69 | break; 70 | case DIRECTION_DOWN: 71 | slideAnim = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, 72 | view.getTranslationY() + view.getHeight()); 73 | break; 74 | default: 75 | break; 76 | } 77 | 78 | AnimatorSet slideSet = new AnimatorSet(); 79 | slideSet.play(slideAnim); 80 | slideSet.setInterpolator(interpolator); 81 | slideSet.setDuration(duration); 82 | slideSet.addListener(new AnimatorListenerAdapter() { 83 | 84 | @Override 85 | public void onAnimationEnd(Animator animation) { 86 | view.setVisibility(View.INVISIBLE); 87 | slideAnim.reverse(); 88 | slideOutFrame.removeAllViews(); 89 | parentView.removeView(slideOutFrame); 90 | parentView.addView(view, positionView); 91 | if (getListener() != null) { 92 | getListener().onAnimationEnd( 93 | SlideOutUnderneathAnimation.this); 94 | } 95 | } 96 | }); 97 | slideSet.start(); 98 | } 99 | 100 | /** 101 | * The available directions to slide in from are DIRECTION_LEFT 102 | * , DIRECTION_RIGHT, DIRECTION_TOP and 103 | * DIRECTION_BOTTOM. 104 | * 105 | * @return The direction to slide the view out to. 106 | * @see Animation 107 | */ 108 | public int getDirection() { 109 | return direction; 110 | } 111 | 112 | /** 113 | * The available directions to slide in from are DIRECTION_LEFT 114 | * , DIRECTION_RIGHT, DIRECTION_TOP and 115 | * DIRECTION_BOTTOM. 116 | * 117 | * @param direction The direction to set to slide the view out to. 118 | * @return This object, allowing calls to methods in this class to be 119 | * chained. 120 | * @see Animation 121 | */ 122 | public SlideOutUnderneathAnimation setDirection(int direction) { 123 | this.direction = direction; 124 | return this; 125 | } 126 | 127 | /** 128 | * @return The interpolator of the entire animation. 129 | */ 130 | public TimeInterpolator getInterpolator() { 131 | return interpolator; 132 | } 133 | 134 | /** 135 | * @param interpolator The interpolator of the entire animation to set. 136 | */ 137 | public SlideOutUnderneathAnimation setInterpolator( 138 | TimeInterpolator interpolator) { 139 | this.interpolator = interpolator; 140 | return this; 141 | } 142 | 143 | /** 144 | * @return The duration of the entire animation. 145 | */ 146 | public long getDuration() { 147 | return duration; 148 | } 149 | 150 | /** 151 | * @param duration The duration of the entire animation to set. 152 | * @return This object, allowing calls to methods in this class to be 153 | * chained. 154 | */ 155 | public SlideOutUnderneathAnimation setDuration(long duration) { 156 | this.duration = duration; 157 | return this; 158 | } 159 | 160 | /** 161 | * @return The listener for the end of the animation. 162 | */ 163 | private AnimationListener getListener() { 164 | return listener; 165 | } 166 | 167 | /** 168 | * @param listener The listener to set for the end of the animation. 169 | * @return This object, allowing calls to methods in this class to be 170 | * chained. 171 | */ 172 | public SlideOutUnderneathAnimation setListener(AnimationListener listener) { 173 | this.listener = listener; 174 | return this; 175 | } 176 | 177 | } 178 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/bean/BucketBean.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.bean; 2 | 3 | import android.text.TextUtils; 4 | 5 | /** 6 | * Desction:文件夹信息 7 | * Author:pengjianbo Dujinyang 8 | * Date:16/6/9 下午2:47 9 | */ 10 | public class BucketBean { 11 | private String bucketId; 12 | private String bucketName; 13 | private int imageCount; 14 | private String cover; 15 | //图片方向 16 | private int orientation; 17 | 18 | public String getBucketId() { 19 | return bucketId; 20 | } 21 | 22 | public void setBucketId(String bucketId) { 23 | this.bucketId = bucketId; 24 | } 25 | 26 | public String getBucketName() { 27 | return bucketName; 28 | } 29 | 30 | public void setBucketName(String bucketName) { 31 | this.bucketName = bucketName; 32 | } 33 | 34 | public int getImageCount() { 35 | return imageCount; 36 | } 37 | 38 | public void setImageCount(int imageCount) { 39 | this.imageCount = imageCount; 40 | } 41 | 42 | public String getCover() { 43 | if (cover == null) { 44 | return ""; 45 | } 46 | return cover; 47 | } 48 | 49 | public void setCover(String cover) { 50 | this.cover = cover; 51 | } 52 | 53 | public int getOrientation() { 54 | return orientation; 55 | } 56 | 57 | public void setOrientation(int orientation) { 58 | this.orientation = orientation; 59 | } 60 | 61 | @Override 62 | public boolean equals(Object o) { 63 | if (o == null || !(o instanceof BucketBean)) { 64 | return false; 65 | } 66 | BucketBean bucketBean = (BucketBean) o; 67 | return TextUtils.equals(bucketBean.getBucketId(), getBucketId()); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/bean/ImageCropBean.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.bean; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | /** 7 | * Desction: 8 | * Author:pengjianbo Dujinyang 9 | * Date:16/8/1 下午10:27 10 | */ 11 | public class ImageCropBean extends MediaBean implements Parcelable { 12 | public static final Creator CREATOR = new Creator() { 13 | @Override 14 | public ImageCropBean createFromParcel(Parcel in) { 15 | return new ImageCropBean(in); 16 | } 17 | 18 | @Override 19 | public ImageCropBean[] newArray(int size) { 20 | return new ImageCropBean[size]; 21 | } 22 | }; 23 | private String cropPath; 24 | private float aspectRatio; 25 | 26 | public ImageCropBean() { 27 | } 28 | 29 | private ImageCropBean(Parcel in) { 30 | super(in); 31 | cropPath = in.readString(); 32 | aspectRatio = in.readFloat(); 33 | } 34 | 35 | @Override 36 | public void writeToParcel(Parcel dest, int flags) { 37 | super.writeToParcel(dest, flags); 38 | dest.writeString(cropPath); 39 | dest.writeFloat(aspectRatio); 40 | } 41 | 42 | @Override 43 | public int describeContents() { 44 | return 0; 45 | } 46 | 47 | public String getCropPath() { 48 | return cropPath; 49 | } 50 | 51 | public void setCropPath(String cropPath) { 52 | this.cropPath = cropPath; 53 | } 54 | 55 | public float getAspectRatio() { 56 | return aspectRatio; 57 | } 58 | 59 | public void setAspectRatio(float aspectRatio) { 60 | this.aspectRatio = aspectRatio; 61 | } 62 | 63 | public void copyMediaBean(MediaBean mediaBean) { 64 | if (mediaBean != null) { 65 | setId(mediaBean.getId()); 66 | setTitle(mediaBean.getTitle()); 67 | setOriginalPath(mediaBean.getOriginalPath()); 68 | setCreateDate(mediaBean.getCreateDate()); 69 | setModifiedDate(mediaBean.getModifiedDate()); 70 | setMimeType(mediaBean.getMimeType()); 71 | setBucketId(mediaBean.getBucketId()); 72 | setBucketDisplayName(mediaBean.getBucketDisplayName()); 73 | setThumbnailSmallPath(mediaBean.getThumbnailSmallPath()); 74 | setThumbnailBigPath(mediaBean.getThumbnailBigPath()); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/bean/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 数据模型 3 | */ 4 | package cn.finalteam.rxgalleryfinal.bean; -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/imageloader/AbsImageLoader.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.imageloader; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.drawable.Drawable; 6 | 7 | import cn.finalteam.rxgalleryfinal.ui.widget.FixImageView; 8 | 9 | /** 10 | * Desction: 11 | * Author:pengjianbo Dujinyang 12 | * Date:16/6/17 下午1:05 13 | */ 14 | public interface AbsImageLoader { 15 | void displayImage(Context context, 16 | String path, 17 | FixImageView imageView, 18 | Drawable defaultDrawable, 19 | Bitmap.Config config, 20 | boolean resize, 21 | boolean isGif, 22 | int width, 23 | int height, 24 | int rotate); 25 | } 26 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/imageloader/FrescoImageLoader.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.imageloader; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Canvas; 7 | import android.graphics.drawable.Drawable; 8 | import android.net.Uri; 9 | import android.view.MotionEvent; 10 | import android.widget.RelativeLayout; 11 | 12 | import com.facebook.common.util.UriUtil; 13 | import com.facebook.drawee.backends.pipeline.Fresco; 14 | import com.facebook.drawee.generic.GenericDraweeHierarchy; 15 | import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; 16 | import com.facebook.drawee.interfaces.DraweeController; 17 | import com.facebook.drawee.view.DraweeHolder; 18 | import com.facebook.drawee.view.SimpleDraweeView; 19 | import com.facebook.imagepipeline.common.ResizeOptions; 20 | import com.facebook.imagepipeline.common.RotationOptions; 21 | import com.facebook.imagepipeline.request.ImageRequest; 22 | import com.facebook.imagepipeline.request.ImageRequestBuilder; 23 | 24 | import cn.finalteam.rxgalleryfinal.ui.widget.FixImageView; 25 | import cn.finalteam.rxgalleryfinal.ui.widget.SquareRelativeLayout; 26 | 27 | /** 28 | * Created by pengjianbo Dujinyang on 2016/8/13 0013. 29 | */ 30 | public class FrescoImageLoader implements AbsImageLoader { 31 | 32 | private DraweeHolder draweeHolder; 33 | 34 | public static void setImageSmall(String url, 35 | SimpleDraweeView simpleDraweeView, 36 | int width, 37 | int height, 38 | SquareRelativeLayout relativeLayout, boolean playGif) { 39 | 40 | Uri uri = Uri.parse(url); 41 | ImageRequest request = ImageRequestBuilder 42 | .newBuilderWithSource(uri) 43 | .setRotationOptions(RotationOptions.autoRotate()) 44 | .setResizeOptions(new ResizeOptions(width, height)) 45 | .setLowestPermittedRequestLevel(ImageRequest.RequestLevel.FULL_FETCH) 46 | .build(); 47 | DraweeController controller = Fresco.newDraweeControllerBuilder() 48 | .setTapToRetryEnabled(true) 49 | .setImageRequest(request) 50 | .setAutoPlayAnimations(playGif) 51 | .setOldController(simpleDraweeView.getController()) 52 | .build(); 53 | relativeLayout.setLayoutParams(new RelativeLayout.LayoutParams(width - 5, height)); 54 | simpleDraweeView.setController(controller); 55 | } 56 | 57 | private void init(Context ctx, Drawable defaultDrawable) { 58 | if (draweeHolder == null) { 59 | Resources resources = ctx.getResources(); 60 | GenericDraweeHierarchy hierarchy = new GenericDraweeHierarchyBuilder(resources) 61 | .setPlaceholderImage(defaultDrawable) 62 | .setFailureImage(defaultDrawable) 63 | .build(); 64 | draweeHolder = DraweeHolder.create(hierarchy, ctx); 65 | } 66 | } 67 | 68 | @Override 69 | public void displayImage(Context context, 70 | String path, 71 | FixImageView imageView, 72 | Drawable defaultDrawable, 73 | Bitmap.Config config, 74 | boolean resize, boolean isGif, 75 | int width, 76 | int height, 77 | int rotate) { 78 | init(context, defaultDrawable); 79 | 80 | imageView.setOnImageViewListener(new FixImageView.OnImageViewListener() { 81 | @Override 82 | public void onDetach() { 83 | draweeHolder.onDetach(); 84 | } 85 | 86 | @Override 87 | public void onAttach() { 88 | draweeHolder.onAttach(); 89 | } 90 | 91 | @Override 92 | public boolean verifyDrawable(Drawable dr) { 93 | return dr == draweeHolder.getHierarchy().getTopLevelDrawable(); 94 | } 95 | 96 | @Override 97 | public void onDraw(Canvas canvas) { 98 | Drawable drawable = draweeHolder.getHierarchy().getTopLevelDrawable(); 99 | if (drawable == null) { 100 | imageView.setImageDrawable(defaultDrawable); 101 | } else { 102 | imageView.setImageDrawable(drawable); 103 | } 104 | } 105 | 106 | @Override 107 | public boolean onTouchEvent(MotionEvent event) { 108 | return draweeHolder.onTouchEvent(event); 109 | } 110 | }); 111 | Uri uri = new Uri.Builder() 112 | .scheme(UriUtil.LOCAL_FILE_SCHEME) 113 | .path(path) 114 | .build(); 115 | ImageRequestBuilder builder = ImageRequestBuilder.newBuilderWithSource(uri) 116 | .setAutoRotateEnabled(true); 117 | if (resize) { 118 | builder.setResizeOptions(new ResizeOptions(width, height)); 119 | } 120 | ImageRequest request = builder.build(); 121 | DraweeController controller = Fresco.newDraweeControllerBuilder() 122 | .setOldController(draweeHolder.getController()) 123 | .setImageRequest(request) 124 | .build(); 125 | draweeHolder.setController(controller); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/imageloader/GlideImageLoader.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.imageloader; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.drawable.Drawable; 6 | 7 | import com.bumptech.glide.Glide; 8 | import com.bumptech.glide.load.engine.DiskCacheStrategy; 9 | 10 | import cn.finalteam.rxgalleryfinal.imageloader.rotate.RotateTransformation; 11 | import cn.finalteam.rxgalleryfinal.ui.widget.FixImageView; 12 | 13 | /** 14 | * Created by pengjianbo Dujinyang on 2016/8/13 0013. 15 | */ 16 | public class GlideImageLoader implements AbsImageLoader { 17 | 18 | @Override 19 | public void displayImage(Context context, String path, FixImageView imageView, Drawable defaultDrawable, Bitmap.Config config, boolean resize, boolean isGif, int width, int height, int rotate) { 20 | if (isGif) { 21 | Glide 22 | .with(context) 23 | .load(path) 24 | .placeholder(defaultDrawable) 25 | .error(defaultDrawable) 26 | .override(width, height) 27 | .transform(new RotateTransformation(rotate)) 28 | .diskCacheStrategy(DiskCacheStrategy.NONE) 29 | .into(imageView); 30 | } else { 31 | Glide 32 | .with(context) 33 | .asBitmap() 34 | .load(path) 35 | .placeholder(defaultDrawable) 36 | .error(defaultDrawable) 37 | .override(width, height) 38 | .transform(new RotateTransformation(rotate)) 39 | .diskCacheStrategy(DiskCacheStrategy.NONE) 40 | .into(imageView); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/imageloader/ImageLoaderType.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.imageloader; 2 | 3 | /** 4 | * Desction: 5 | * Author:pengjianbo Dujinyang 6 | * Date:16/7/25 下午3:36 7 | */ 8 | public enum ImageLoaderType { 9 | PICASSO, GLIDE, FRESCO, UNIVERSAL 10 | } 11 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/imageloader/PicassoImageLoader.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.imageloader; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.drawable.Drawable; 6 | 7 | import com.squareup.picasso.NetworkPolicy; 8 | import com.squareup.picasso.Picasso; 9 | import com.squareup.picasso.RequestCreator; 10 | 11 | import java.io.File; 12 | 13 | import cn.finalteam.rxgalleryfinal.ui.widget.FixImageView; 14 | 15 | /** 16 | * Desction: 17 | * .centerCrop() 预览大图 18 | * Author:dujinyang 19 | * Date:16/6/17 下午1:23 20 | */ 21 | public class PicassoImageLoader implements AbsImageLoader { 22 | 23 | @Override 24 | public void displayImage(Context context, String path, FixImageView imageView, Drawable defaultDrawable, Bitmap.Config config, boolean resize, boolean isGif, int width, int height, int rotate) { 25 | RequestCreator creator = Picasso.get() 26 | .load(new File(path)) 27 | .placeholder(defaultDrawable) 28 | .error(defaultDrawable) 29 | .rotate(rotate) 30 | .networkPolicy(NetworkPolicy.NO_STORE) 31 | .config(config) 32 | .tag(context); 33 | if (resize) { 34 | creator = creator.resize(width, height) 35 | .centerCrop(); 36 | } 37 | creator.into(imageView); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/imageloader/UniversalImageLoader.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.imageloader; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.drawable.Drawable; 6 | 7 | import com.nostra13.universalimageloader.core.DisplayImageOptions; 8 | import com.nostra13.universalimageloader.core.ImageLoader; 9 | import com.nostra13.universalimageloader.core.assist.ImageSize; 10 | import com.nostra13.universalimageloader.core.imageaware.ImageViewAware; 11 | 12 | import cn.finalteam.rxgalleryfinal.ui.widget.FixImageView; 13 | 14 | /** 15 | * Created by pengjianbo Dujinyang on 2016/8/13 0013. 16 | */ 17 | public class UniversalImageLoader implements AbsImageLoader { 18 | 19 | private DisplayImageOptions displayImageOptions; 20 | 21 | @Override 22 | public void displayImage(Context context, String path, FixImageView imageView, Drawable defaultDrawable, Bitmap.Config config, boolean resize, boolean isGif, int width, int height, int rotate) { 23 | if (displayImageOptions == null) { 24 | displayImageOptions = new DisplayImageOptions.Builder() 25 | .cacheOnDisk(false) 26 | .cacheInMemory(true) 27 | .bitmapConfig(config) 28 | .showImageOnFail(defaultDrawable) 29 | .showImageOnLoading(defaultDrawable) 30 | .showImageForEmptyUri(defaultDrawable) 31 | .build(); 32 | } 33 | ImageSize imageSize = null; 34 | if (resize) { 35 | imageSize = new ImageSize(width, height); 36 | } 37 | ImageLoader.getInstance().displayImage("file://" + path, new ImageViewAware(imageView), displayImageOptions, imageSize, null, null); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/imageloader/rotate/RotateTransformation.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.imageloader.rotate; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Matrix; 5 | 6 | import androidx.annotation.NonNull; 7 | import androidx.annotation.Nullable; 8 | 9 | import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; 10 | import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; 11 | 12 | import java.nio.charset.Charset; 13 | import java.security.MessageDigest; 14 | 15 | /** 16 | * Created by pengjianbo Dujinyang on 2016/8/16 0016. 17 | */ 18 | public class RotateTransformation extends BitmapTransformation { 19 | private static final String ID = "cn.finalteam.rxgalleryfinal.imageloader.rotate.RotateTransformation"; 20 | private static final byte[] ID_BYTES = ID.getBytes(Charset.forName("UTF-8")); 21 | private float rotateRotationAngle; 22 | 23 | public RotateTransformation(float rotateRotationAngle) { 24 | this.rotateRotationAngle = rotateRotationAngle; 25 | } 26 | 27 | @Override 28 | protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) { 29 | Matrix matrix = new Matrix(); 30 | matrix.postRotate(rotateRotationAngle); 31 | return Bitmap.createBitmap(toTransform, 0, 0, toTransform.getWidth(), toTransform.getHeight(), matrix, true); 32 | } 33 | 34 | @Override 35 | public boolean equals(@Nullable Object obj) { 36 | return obj instanceof RotateTransformation; 37 | } 38 | 39 | @Override 40 | public int hashCode() { 41 | return ID.hashCode(); 42 | } 43 | 44 | @Override 45 | public void updateDiskCacheKey(MessageDigest messageDigest) { 46 | messageDigest.update(ID_BYTES); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/interactor/MediaBucketFactoryInteractor.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.interactor; 2 | 3 | import java.util.List; 4 | 5 | import cn.finalteam.rxgalleryfinal.bean.BucketBean; 6 | 7 | /** 8 | * Desction: 9 | * Author:pengjianbo Dujinyang 10 | * Date:16/7/4 下午8:24 11 | */ 12 | public interface MediaBucketFactoryInteractor { 13 | 14 | void generateBuckets(); 15 | 16 | interface OnGenerateBucketListener { 17 | void onFinished(List list); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/interactor/MediaSrcFactoryInteractor.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.interactor; 2 | 3 | import java.util.List; 4 | 5 | import cn.finalteam.rxgalleryfinal.bean.MediaBean; 6 | 7 | /** 8 | * Desction:媒体资源工厂 9 | * Author:pengjianbo Dujinyang 10 | * Date:16/5/14 上午11:06 11 | */ 12 | public interface MediaSrcFactoryInteractor { 13 | 14 | /** 15 | * 生产资源 16 | */ 17 | void generateMeidas(String bucketId, int page, int limit); 18 | 19 | interface OnGenerateMediaListener { 20 | void onFinished(String bucketId, int pageSize, int currentOffset, List list); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/interactor/impl/MediaBucketFactoryInteractorImpl.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.interactor.impl; 2 | 3 | 4 | import android.content.Context; 5 | 6 | import java.util.List; 7 | 8 | import cn.finalteam.rxgalleryfinal.bean.BucketBean; 9 | import cn.finalteam.rxgalleryfinal.interactor.MediaBucketFactoryInteractor; 10 | import cn.finalteam.rxgalleryfinal.utils.MediaUtils; 11 | import io.reactivex.Observable; 12 | import io.reactivex.ObservableOnSubscribe; 13 | import io.reactivex.android.schedulers.AndroidSchedulers; 14 | import io.reactivex.observers.DisposableObserver; 15 | import io.reactivex.schedulers.Schedulers; 16 | 17 | /** 18 | * Desction: 19 | * Author:pengjianbo Dujinyang 20 | * Date:16/7/4 下午8:29 21 | */ 22 | public class MediaBucketFactoryInteractorImpl implements MediaBucketFactoryInteractor { 23 | 24 | private final Context context; 25 | private final boolean isImage; 26 | private final OnGenerateBucketListener onGenerateBucketListener; 27 | 28 | public MediaBucketFactoryInteractorImpl(Context context, boolean isImage, OnGenerateBucketListener onGenerateBucketListener) { 29 | this.context = context; 30 | this.isImage = isImage; 31 | this.onGenerateBucketListener = onGenerateBucketListener; 32 | } 33 | 34 | @Override 35 | public void generateBuckets() { 36 | Observable.create((ObservableOnSubscribe>) subscriber -> { 37 | List bucketBeanList = null; 38 | if (isImage) { 39 | bucketBeanList = MediaUtils.getAllBucketByImage(context); 40 | } else { 41 | bucketBeanList = MediaUtils.getAllBucketByVideo(context); 42 | } 43 | subscriber.onNext(bucketBeanList); 44 | subscriber.onComplete(); 45 | }) 46 | .subscribeOn(Schedulers.io()) 47 | .observeOn(AndroidSchedulers.mainThread()) 48 | .subscribe(new DisposableObserver>() { 49 | @Override 50 | public void onComplete() { 51 | } 52 | 53 | @Override 54 | public void onError(Throwable e) { 55 | onGenerateBucketListener.onFinished(null); 56 | } 57 | 58 | @Override 59 | public void onNext(List bucketBeanList) { 60 | onGenerateBucketListener.onFinished(bucketBeanList); 61 | } 62 | }); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/interactor/impl/MediaSrcFactoryInteractorImpl.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.interactor.impl; 2 | 3 | import android.content.Context; 4 | 5 | import java.util.List; 6 | 7 | import cn.finalteam.rxgalleryfinal.bean.MediaBean; 8 | import cn.finalteam.rxgalleryfinal.interactor.MediaSrcFactoryInteractor; 9 | import cn.finalteam.rxgalleryfinal.utils.MediaUtils; 10 | import io.reactivex.Observable; 11 | import io.reactivex.ObservableOnSubscribe; 12 | import io.reactivex.android.schedulers.AndroidSchedulers; 13 | import io.reactivex.observers.DisposableObserver; 14 | import io.reactivex.schedulers.Schedulers; 15 | 16 | /** 17 | * Desction: 18 | * Author:pengjianbo Dujinyang 19 | * Date:16/5/14 上午11:08 20 | */ 21 | public class MediaSrcFactoryInteractorImpl implements MediaSrcFactoryInteractor { 22 | 23 | private final Context context; 24 | private final OnGenerateMediaListener onGenerateMediaListener; 25 | private final boolean isImage; 26 | 27 | public MediaSrcFactoryInteractorImpl(Context context, boolean isImage, OnGenerateMediaListener onGenerateMediaListener) { 28 | this.context = context; 29 | this.isImage = isImage; 30 | this.onGenerateMediaListener = onGenerateMediaListener; 31 | } 32 | 33 | @Override 34 | public void generateMeidas(final String bucketId, final int page, final int limit) { 35 | Observable.create((ObservableOnSubscribe>) subscriber -> { 36 | List mediaBeanList = null; 37 | if (isImage) { 38 | mediaBeanList = MediaUtils.getMediaWithImageList(context, bucketId, page, limit); 39 | } else { 40 | mediaBeanList = MediaUtils.getMediaWithVideoList(context, bucketId, page, limit); 41 | } 42 | subscriber.onNext(mediaBeanList); 43 | subscriber.onComplete(); 44 | }) 45 | .subscribeOn(Schedulers.io()) 46 | .observeOn(AndroidSchedulers.mainThread()) 47 | .subscribe(new DisposableObserver>() { 48 | @Override 49 | public void onComplete() { 50 | } 51 | 52 | @Override 53 | public void onError(Throwable e) { 54 | onGenerateMediaListener.onFinished(bucketId, page, limit, null); 55 | } 56 | 57 | @Override 58 | public void onNext(List mediaBeenList) { 59 | onGenerateMediaListener.onFinished(bucketId, page, limit, mediaBeenList); 60 | } 61 | }); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/interactor/impl/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MVP M层包(业务生产)--实现 3 | */ 4 | package cn.finalteam.rxgalleryfinal.interactor.impl; -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/interactor/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MVP M层包(业务生产)--抽象 3 | */ 4 | package cn.finalteam.rxgalleryfinal.interactor; -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 项目包名 3 | */ 4 | package cn.finalteam.rxgalleryfinal; -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/presenter/MediaGridPresenter.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.presenter; 2 | 3 | import cn.finalteam.rxgalleryfinal.view.MediaGridView; 4 | 5 | /** 6 | * Desction: 7 | * Author:pengjianbo Dujinyang 8 | * Date:16/5/14 上午10:53 9 | */ 10 | public interface MediaGridPresenter { 11 | 12 | void setMediaGridView(MediaGridView mediaGridView); 13 | 14 | void getMediaList(String bucketId, int pageSize, int currentOffset); 15 | 16 | void getBucketList(); 17 | } 18 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/presenter/impl/MediaGridPresenterImpl.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.presenter.impl; 2 | 3 | import android.content.Context; 4 | 5 | import java.util.List; 6 | 7 | import cn.finalteam.rxgalleryfinal.bean.BucketBean; 8 | import cn.finalteam.rxgalleryfinal.bean.MediaBean; 9 | import cn.finalteam.rxgalleryfinal.interactor.MediaBucketFactoryInteractor; 10 | import cn.finalteam.rxgalleryfinal.interactor.MediaSrcFactoryInteractor; 11 | import cn.finalteam.rxgalleryfinal.interactor.impl.MediaBucketFactoryInteractorImpl; 12 | import cn.finalteam.rxgalleryfinal.interactor.impl.MediaSrcFactoryInteractorImpl; 13 | import cn.finalteam.rxgalleryfinal.presenter.MediaGridPresenter; 14 | import cn.finalteam.rxgalleryfinal.view.MediaGridView; 15 | 16 | /** 17 | * Desction: 18 | * Author:pengjianbo Dujinyang 19 | * Date:16/5/14 上午10:58 20 | */ 21 | public class MediaGridPresenterImpl implements MediaGridPresenter, MediaSrcFactoryInteractor.OnGenerateMediaListener, 22 | MediaBucketFactoryInteractor.OnGenerateBucketListener { 23 | 24 | private final MediaSrcFactoryInteractor mediaSrcFactoryInteractor; 25 | private final MediaBucketFactoryInteractor mediaBucketFactoryInteractor; 26 | 27 | private MediaGridView mediaGridView; 28 | 29 | public MediaGridPresenterImpl(Context context, boolean isImage) { 30 | this.mediaSrcFactoryInteractor = new MediaSrcFactoryInteractorImpl(context, isImage, this); 31 | this.mediaBucketFactoryInteractor = new MediaBucketFactoryInteractorImpl(context, isImage, this); 32 | } 33 | 34 | /** 35 | * 设置MVP view(操作UI接口) 36 | */ 37 | @Override 38 | public void setMediaGridView(MediaGridView mediaGridView) { 39 | this.mediaGridView = mediaGridView; 40 | } 41 | 42 | /** 43 | * 分页获取media 44 | */ 45 | @Override 46 | public void getMediaList(String bucketId, int pageSize, int currentOffset) { 47 | mediaSrcFactoryInteractor.generateMeidas(bucketId, pageSize, currentOffset); 48 | } 49 | 50 | @Override 51 | public void getBucketList() { 52 | mediaBucketFactoryInteractor.generateBuckets(); 53 | } 54 | 55 | /** 56 | * Media获取事件回调 57 | */ 58 | @Override 59 | public void onFinished(String bucketId, int pageSize, int currentOffset, List list) { 60 | mediaGridView.onRequestMediaCallback(list); 61 | } 62 | 63 | /** 64 | * BUCKET获取事件回调 65 | */ 66 | @Override 67 | public void onFinished(List list) { 68 | mediaGridView.onRequestBucketCallback(list); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/presenter/impl/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MVP P层包(调度)--实现 3 | */ 4 | package cn.finalteam.rxgalleryfinal.presenter.impl; -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/presenter/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MVP P层包(调度)--抽象 3 | */ 4 | package cn.finalteam.rxgalleryfinal.presenter; -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxbus/RxBus.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.rxbus; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import io.reactivex.Observable; 7 | import io.reactivex.disposables.CompositeDisposable; 8 | import io.reactivex.disposables.Disposable; 9 | import io.reactivex.subjects.PublishSubject; 10 | import io.reactivex.subjects.Subject; 11 | 12 | 13 | /** 14 | * Desction: 15 | * Author:pengjianbo Dujinyang 16 | * Date:16/7/22 下午2:40 17 | */ 18 | public class RxBus { 19 | 20 | private static volatile RxBus mInstance; 21 | private final Subject mBus; 22 | private final Map, Object> mStickyEventMap; 23 | 24 | private final CompositeDisposable mDisposable; 25 | 26 | private RxBus() { 27 | mBus = PublishSubject.create().toSerialized(); 28 | mDisposable = new CompositeDisposable(); 29 | mStickyEventMap = new HashMap<>(); 30 | } 31 | 32 | public static RxBus getDefault() { 33 | if (mInstance == null) { 34 | synchronized (RxBus.class) { 35 | if (mInstance == null) { 36 | mInstance = new RxBus(); 37 | } 38 | } 39 | } 40 | return mInstance; 41 | } 42 | 43 | /** 44 | * 发送事件 45 | */ 46 | public void post(Object event) { 47 | mBus.onNext(event); 48 | } 49 | 50 | /** 51 | * 根据传递的 eventType 类型返回特定类型(eventType)的 被观察者 52 | */ 53 | public Observable toObservable(Class eventType) { 54 | return mBus.ofType(eventType); 55 | } 56 | 57 | /** 58 | * 判断是否有订阅者 59 | */ 60 | public boolean hasObservers() { 61 | return mBus.hasObservers(); 62 | } 63 | 64 | public void reset() { 65 | mInstance = null; 66 | } 67 | 68 | 69 | /** 70 | * 是否被取消订阅 71 | */ 72 | public boolean isUnsubscribed() { 73 | return mDisposable.isDisposed(); 74 | } 75 | 76 | /** 77 | * 添加订阅 78 | */ 79 | public void add(Disposable s) { 80 | if (s != null) { 81 | mDisposable.add(s); 82 | } 83 | } 84 | 85 | /** 86 | * 移除订阅 87 | */ 88 | public void remove(Disposable s) { 89 | if (s != null) { 90 | mDisposable.remove(s); 91 | } 92 | } 93 | 94 | /** 95 | * 清除所有订阅 96 | */ 97 | public void clear() { 98 | mDisposable.clear(); 99 | } 100 | 101 | /** 102 | * 取消订阅 103 | */ 104 | public void unsubscribe() { 105 | mDisposable.dispose(); 106 | } 107 | 108 | /** 109 | * 发送一个新Sticky事件 110 | */ 111 | public void postSticky(Object event) { 112 | synchronized (mStickyEventMap) { 113 | mStickyEventMap.put(event.getClass(), event); 114 | } 115 | post(event); 116 | } 117 | 118 | /** 119 | * 根据传递的 eventType 类型返回特定类型(eventType)的 被观察者 120 | */ 121 | public Observable toObservableSticky(final Class eventType) { 122 | synchronized (mStickyEventMap) { 123 | Observable observable = mBus.ofType(eventType); 124 | final Object event = mStickyEventMap.get(eventType); 125 | 126 | if (event != null) { 127 | return Observable.merge(observable, Observable.create(subscriber -> subscriber.onNext(eventType.cast(event)))); 128 | } else { 129 | return observable; 130 | } 131 | } 132 | } 133 | 134 | /** 135 | * 根据eventType获取Sticky事件 136 | */ 137 | public T getStickyEvent(Class eventType) { 138 | synchronized (mStickyEventMap) { 139 | return eventType.cast(mStickyEventMap.get(eventType)); 140 | } 141 | } 142 | 143 | /** 144 | * 移除指定eventType的Sticky事件 145 | */ 146 | public T removeStickyEvent(Class eventType) { 147 | synchronized (mStickyEventMap) { 148 | return eventType.cast(mStickyEventMap.remove(eventType)); 149 | } 150 | } 151 | 152 | /** 153 | * 移除所有的Sticky事件 154 | */ 155 | public void removeAllStickyEvents() { 156 | synchronized (mStickyEventMap) { 157 | mStickyEventMap.clear(); 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxbus/RxBusDisposable.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.rxbus; 2 | 3 | import cn.finalteam.rxgalleryfinal.utils.Logger; 4 | import io.reactivex.observers.DisposableObserver; 5 | 6 | /** 7 | * Desction: 8 | * Author:pengjianbo Dujinyang 9 | * Date:16/7/22 下午2:40 10 | */ 11 | public abstract class RxBusDisposable extends DisposableObserver { 12 | 13 | @Override 14 | public void onNext(T t) { 15 | try { 16 | onEvent(t); 17 | } catch (Exception e) { 18 | e.printStackTrace(); 19 | onError(e); 20 | } 21 | } 22 | 23 | 24 | @Override 25 | public void onComplete() { 26 | 27 | } 28 | 29 | @Override 30 | public void onError(Throwable e) { 31 | Logger.e(e.getMessage()); 32 | } 33 | 34 | protected abstract void onEvent(T t) throws Exception; 35 | 36 | } -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxbus/RxBusResultDisposable.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.rxbus; 2 | 3 | import cn.finalteam.rxgalleryfinal.rxbus.event.BaseResultEvent; 4 | 5 | /** 6 | * Desction: 7 | * Author:pengjianbo Dujinyang 8 | * Date:16/8/1 下午11:11 9 | */ 10 | public abstract class RxBusResultDisposable extends RxBusDisposable { 11 | } 12 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxbus/event/BaseResultEvent.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.rxbus.event; 2 | 3 | /** 4 | * Desction: 5 | * Author:pengjianbo Dujinyang 6 | * Date:16/7/31 下午10:37 7 | */ 8 | public interface BaseResultEvent { 9 | } 10 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxbus/event/CloseMediaViewPageFragmentEvent.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.rxbus.event; 2 | 3 | /** 4 | * Desction: 5 | * Author:pengjianbo Dujinyang 6 | * Date:16/7/28 上午12:19 7 | */ 8 | public class CloseMediaViewPageFragmentEvent { 9 | } 10 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxbus/event/CloseRxMediaGridPageEvent.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.rxbus.event; 2 | 3 | /** 4 | * Desction: 5 | * Author:pengjianbo Dujinyang 6 | * Date:16/8/1 下午11:51 7 | */ 8 | public class CloseRxMediaGridPageEvent { 9 | } 10 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxbus/event/ImageMultipleResultEvent.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.rxbus.event; 2 | 3 | import java.util.List; 4 | 5 | import cn.finalteam.rxgalleryfinal.bean.MediaBean; 6 | 7 | /** 8 | * Desction: 9 | * Author:pengjianbo Dujinyang 10 | * Date:16/8/1 下午10:52 11 | */ 12 | public class ImageMultipleResultEvent implements BaseResultEvent { 13 | private final List mediaResultList; 14 | 15 | public ImageMultipleResultEvent(List list) { 16 | this.mediaResultList = list; 17 | } 18 | 19 | public List getResult() { 20 | return mediaResultList; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxbus/event/ImageRadioResultEvent.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.rxbus.event; 2 | 3 | import cn.finalteam.rxgalleryfinal.bean.ImageCropBean; 4 | 5 | /** 6 | * Desction: 7 | * Author:pengjianbo Dujinyang 8 | * Date:16/8/1 下午10:49 9 | */ 10 | public class ImageRadioResultEvent implements BaseResultEvent { 11 | private final ImageCropBean resultBean; 12 | 13 | public ImageRadioResultEvent(ImageCropBean bean) { 14 | this.resultBean = bean; 15 | } 16 | 17 | public ImageCropBean getResult() { 18 | return resultBean; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxbus/event/MediaCheckChangeEvent.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.rxbus.event; 2 | 3 | import cn.finalteam.rxgalleryfinal.bean.MediaBean; 4 | 5 | /** 6 | * Desction: 7 | * Author:pengjianbo Dujinyang 8 | * Date:16/7/24 下午11:47 9 | */ 10 | public class MediaCheckChangeEvent { 11 | 12 | private final MediaBean mediaBean; 13 | 14 | public MediaCheckChangeEvent(MediaBean mediaBean) { 15 | this.mediaBean = mediaBean; 16 | } 17 | 18 | public MediaBean getMediaBean() { 19 | return this.mediaBean; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxbus/event/MediaViewPagerChangedEvent.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.rxbus.event; 2 | 3 | /** 4 | * Desction: 5 | * Author:pengjianbo Dujinyang 6 | * Date:16/7/25 下午3:45 7 | */ 8 | public class MediaViewPagerChangedEvent { 9 | 10 | private final int curIndex; 11 | private final int totalSize; 12 | private final boolean isPreview; 13 | 14 | public MediaViewPagerChangedEvent(int curIndex, int totalSize, boolean isPreview) { 15 | this.curIndex = curIndex; 16 | this.totalSize = totalSize; 17 | this.isPreview = isPreview; 18 | } 19 | 20 | public int getCurIndex() { 21 | return curIndex; 22 | } 23 | 24 | public int getTotalSize() { 25 | return totalSize; 26 | } 27 | 28 | public boolean isPreview() { 29 | return isPreview; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxbus/event/OpenMediaPageFragmentEvent.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.rxbus.event; 2 | 3 | import java.util.ArrayList; 4 | 5 | import cn.finalteam.rxgalleryfinal.bean.MediaBean; 6 | 7 | /** 8 | * Desction: 9 | * Author:pengjianbo Dujinyang 10 | * Date:16/7/27 下午11:14 11 | */ 12 | public class OpenMediaPageFragmentEvent { 13 | private final ArrayList mediaBeanList; 14 | private final int position; 15 | 16 | public OpenMediaPageFragmentEvent(ArrayList mediaBeanList, int position) { 17 | this.mediaBeanList = mediaBeanList; 18 | this.position = position; 19 | } 20 | 21 | public ArrayList getMediaBeanList() { 22 | return mediaBeanList; 23 | } 24 | 25 | public int getPosition() { 26 | return position; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxbus/event/OpenMediaPreviewFragmentEvent.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.rxbus.event; 2 | 3 | /** 4 | * Desction: 5 | * Author:pengjianbo Dujinyang 6 | * Date:16/7/23 下午3:49 7 | */ 8 | public class OpenMediaPreviewFragmentEvent { 9 | } 10 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxbus/event/RequestStorageReadAccessPermissionEvent.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.rxbus.event; 2 | 3 | /** 4 | * Desction: 5 | * Author:pengjianbo Dujinyang 6 | * Date:16/7/30 下午11:23 7 | */ 8 | public class RequestStorageReadAccessPermissionEvent { 9 | 10 | public static final int TYPE_CAMERA = 0; 11 | public static final int TYPE_WRITE = 1; 12 | 13 | private final boolean success; 14 | private final int type; 15 | 16 | public RequestStorageReadAccessPermissionEvent(boolean success, int type) { 17 | this.success = success; 18 | this.type = type; 19 | } 20 | 21 | public boolean isSuccess() { 22 | return success; 23 | } 24 | 25 | public int getType() { 26 | return type; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxbus/event/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 事件包 3 | */ 4 | package cn.finalteam.rxgalleryfinal.rxbus.event; -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxbus/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * rxjava实现事件总线 3 | */ 4 | package cn.finalteam.rxgalleryfinal.rxbus; -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxjob/Job.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.rxjob; 2 | 3 | 4 | import androidx.annotation.NonNull; 5 | 6 | /** 7 | * Desction: 8 | * Author:pengjianbo Dujinyang 9 | * Date:16/7/31 上午9:15 10 | */ 11 | public interface Job { 12 | Result onRunJob(); 13 | 14 | enum Result { 15 | 16 | SUCCESS(), FAILURE(); 17 | 18 | private Object data; 19 | 20 | Result() { 21 | } 22 | 23 | public Object getResultData() { 24 | return data; 25 | } 26 | 27 | public void setResultData(Object data) { 28 | this.data = data; 29 | } 30 | } 31 | 32 | class Params { 33 | private final Object data; 34 | private final String tag; 35 | 36 | public Params(@NonNull String tag, Object requestData) { 37 | this.tag = tag; 38 | this.data = requestData; 39 | } 40 | 41 | public String getTag() { 42 | return tag; 43 | } 44 | 45 | public Object getRequestData() { 46 | return data; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxjob/JobCreator.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.rxjob; 2 | 3 | /** 4 | * Desction: 5 | * Author:pengjianbo Dujinyang 6 | * Date:16/7/31 上午9:10 7 | */ 8 | public interface JobCreator { 9 | Job create(); 10 | } 11 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxjob/JobManager.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.rxjob; 2 | 3 | import java.util.Queue; 4 | import java.util.concurrent.LinkedBlockingQueue; 5 | 6 | import io.reactivex.Observable; 7 | import io.reactivex.ObservableOnSubscribe; 8 | import io.reactivex.android.schedulers.AndroidSchedulers; 9 | import io.reactivex.observers.DisposableObserver; 10 | import io.reactivex.schedulers.Schedulers; 11 | 12 | 13 | /** 14 | * Desction: 15 | * Author:pengjianbo Dujinyang 16 | * Date:16/7/31 上午9:12 17 | */ 18 | class JobManager { 19 | 20 | private final Queue jobQueue; 21 | private boolean queueFree = true; 22 | 23 | JobManager() { 24 | jobQueue = new LinkedBlockingQueue<>(); 25 | } 26 | 27 | void addJob(Job job) { 28 | if (jobQueue.isEmpty() && queueFree) { 29 | jobQueue.offer(job); 30 | start(); 31 | } else { 32 | jobQueue.offer(job); 33 | } 34 | } 35 | 36 | private void start() { 37 | Observable.create((ObservableOnSubscribe) subscriber -> { 38 | queueFree = false; 39 | Job job; 40 | while ((job = jobQueue.poll()) != null) { 41 | job.onRunJob(); 42 | } 43 | subscriber.onComplete(); 44 | }) 45 | .subscribeOn(Schedulers.newThread()) 46 | .observeOn(AndroidSchedulers.mainThread()) 47 | .subscribe(new DisposableObserver() { 48 | @Override 49 | public void onComplete() { 50 | queueFree = true; 51 | } 52 | 53 | @Override 54 | public void onError(Throwable e) { 55 | } 56 | 57 | @Override 58 | public void onNext(Job job) { 59 | } 60 | }); 61 | } 62 | 63 | public void clear() { 64 | jobQueue.clear(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxjob/RxJob.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.rxjob; 2 | 3 | /** 4 | * Desction: 5 | * Author:pengjianbo Dujinyang 6 | * Date:16/7/31 上午9:09 7 | */ 8 | public class RxJob { 9 | 10 | private static RxJob rxJob; 11 | private final JobManager jobManager; 12 | 13 | private RxJob() { 14 | jobManager = new JobManager(); 15 | } 16 | 17 | public static RxJob getDefault() { 18 | if (rxJob == null) { 19 | rxJob = new RxJob(); 20 | } 21 | return rxJob; 22 | } 23 | 24 | public void addJob(Job job) { 25 | jobManager.addJob(job); 26 | } 27 | 28 | public void clearJob() { 29 | jobManager.clear(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxjob/job/ImageThmbnailJob.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.rxjob.job; 2 | 3 | import android.content.Context; 4 | 5 | import java.io.File; 6 | 7 | import cn.finalteam.rxgalleryfinal.bean.MediaBean; 8 | import cn.finalteam.rxgalleryfinal.rxjob.Job; 9 | import cn.finalteam.rxgalleryfinal.utils.BitmapUtils; 10 | import cn.finalteam.rxgalleryfinal.utils.MediaUtils; 11 | 12 | /** 13 | * Desction: 14 | * Author:pengjianbo Dujinyang 15 | * Date:16/7/31 上午11:46 16 | */ 17 | public class ImageThmbnailJob implements Job { 18 | 19 | private final MediaBean mediaBean; 20 | private final Context context; 21 | 22 | public ImageThmbnailJob(Context context, Params params) { 23 | this.context = context; 24 | this.mediaBean = (MediaBean) params.getRequestData(); 25 | } 26 | 27 | @Override 28 | public Result onRunJob() { 29 | String originalPath = mediaBean.getOriginalPath(); 30 | File bigThumFile = MediaUtils.createThumbnailBigFileName(context, originalPath); 31 | File smallThumFile = MediaUtils.createThumbnailSmallFileName(context, originalPath); 32 | if (!bigThumFile.exists()) { 33 | BitmapUtils.createThumbnailBig(bigThumFile, originalPath); 34 | } 35 | if (!smallThumFile.exists()) { 36 | BitmapUtils.createThumbnailSmall(smallThumFile, originalPath); 37 | } 38 | Result result = Result.SUCCESS; 39 | result.setResultData(mediaBean); 40 | return result; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxjob/job/ImageThmbnailJobCreate.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.rxjob.job; 2 | 3 | import android.content.Context; 4 | 5 | import cn.finalteam.rxgalleryfinal.bean.MediaBean; 6 | import cn.finalteam.rxgalleryfinal.rxjob.Job; 7 | import cn.finalteam.rxgalleryfinal.rxjob.JobCreator; 8 | 9 | /** 10 | * Desction: 11 | * Author:pengjianbo Dujinyang 12 | * Date:16/7/31 上午11:46 13 | */ 14 | public class ImageThmbnailJobCreate implements JobCreator { 15 | 16 | private final MediaBean mediaBean; 17 | private final Context context; 18 | 19 | public ImageThmbnailJobCreate(Context context, MediaBean mediaBean) { 20 | this.context = context; 21 | this.mediaBean = mediaBean; 22 | } 23 | 24 | @Override 25 | public Job create() { 26 | Job.Params params = new Job.Params(mediaBean.getOriginalPath(), mediaBean); 27 | return new ImageThmbnailJob(context, params); 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxjob/job/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 队列包 3 | */ 4 | package cn.finalteam.rxgalleryfinal.rxjob.job; -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/rxjob/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * rxjava实现queue 3 | */ 4 | package cn.finalteam.rxgalleryfinal.rxjob; -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/ui/RxGalleryListener.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.ui; 2 | 3 | import cn.finalteam.rxgalleryfinal.ui.adapter.MediaGridAdapter; 4 | import cn.finalteam.rxgalleryfinal.ui.base.IMultiImageCheckedListener; 5 | import cn.finalteam.rxgalleryfinal.ui.base.IRadioImageCheckedListener; 6 | import cn.finalteam.rxgalleryfinal.ui.fragment.MediaGridFragment; 7 | 8 | /** 9 | * 处理回调监听 10 | * Created by KARL on 2017-03-17 04-42-25. 11 | */ 12 | public class RxGalleryListener { 13 | 14 | private static final class RxGalleryListenerHolder { 15 | private static final RxGalleryListener RX_GALLERY_LISTENER = new RxGalleryListener(); 16 | } 17 | 18 | public static RxGalleryListener getInstance() { 19 | return RxGalleryListenerHolder.RX_GALLERY_LISTENER; 20 | } 21 | 22 | /** 23 | * 图片多选的事件 24 | */ 25 | public void setMultiImageCheckedListener(IMultiImageCheckedListener checkedImageListener) { 26 | MediaGridAdapter.setCheckedListener(checkedImageListener); 27 | } 28 | 29 | 30 | /** 31 | * 图片单选的事件 32 | */ 33 | public void setRadioImageCheckedListener(IRadioImageCheckedListener checkedImageListener) { 34 | MediaGridFragment.setRadioListener(checkedImageListener); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/ui/activity/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.ui.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | 6 | import androidx.annotation.LayoutRes; 7 | import androidx.annotation.Nullable; 8 | import androidx.appcompat.app.AppCompatActivity; 9 | 10 | import cn.finalteam.rxgalleryfinal.BuildConfig; 11 | import cn.finalteam.rxgalleryfinal.Configuration; 12 | import cn.finalteam.rxgalleryfinal.utils.Logger; 13 | 14 | /** 15 | * Desction: 16 | * Author:pengjianbo Dujinyang 17 | * Date:16/5/16 下午7:36 18 | */ 19 | public abstract class BaseActivity extends AppCompatActivity { 20 | 21 | public static final String EXTRA_PREFIX = BuildConfig.APPLICATION_ID; 22 | public static final String EXTRA_CONFIGURATION = EXTRA_PREFIX + ".Configuration"; 23 | 24 | private final String CLASS_NAME = getClass().getSimpleName(); 25 | 26 | public Configuration mConfiguration; 27 | 28 | @Override 29 | protected void onCreate(@Nullable Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | printActivityLife("onCreate"); 32 | Intent intent = getIntent(); 33 | Bundle bundle = null; 34 | if (intent != null) { 35 | bundle = intent.getExtras(); 36 | } 37 | 38 | 39 | if (savedInstanceState != null) { 40 | mConfiguration = savedInstanceState.getParcelable(EXTRA_CONFIGURATION); 41 | } 42 | if (mConfiguration == null && bundle != null) { 43 | mConfiguration = bundle.getParcelable(EXTRA_CONFIGURATION); 44 | } 45 | 46 | if (mConfiguration == null) { 47 | finish(); 48 | } else { 49 | if (bundle == null) { 50 | bundle = savedInstanceState; 51 | } 52 | setContentView(getContentView()); 53 | findViews(); 54 | setTheme(); 55 | onCreateOk(bundle); 56 | } 57 | } 58 | 59 | @LayoutRes 60 | public abstract int getContentView(); 61 | 62 | protected abstract void onCreateOk(@Nullable Bundle savedInstanceState); 63 | 64 | @Override 65 | protected void onStart() { 66 | super.onStart(); 67 | printActivityLife("onStart"); 68 | } 69 | 70 | @Override 71 | protected void onRestart() { 72 | super.onRestart(); 73 | printActivityLife("onRestart"); 74 | } 75 | 76 | @Override 77 | protected void onResume() { 78 | super.onResume(); 79 | printActivityLife("onRestart"); 80 | } 81 | 82 | @Override 83 | protected void onPause() { 84 | super.onPause(); 85 | printActivityLife("onPause"); 86 | } 87 | 88 | @Override 89 | protected void onDestroy() { 90 | super.onDestroy(); 91 | printActivityLife("onDestroy"); 92 | } 93 | 94 | @Override 95 | protected void onSaveInstanceState(Bundle outState) { 96 | super.onSaveInstanceState(outState); 97 | printActivityLife("onSaveInstanceState"); 98 | outState.putParcelable(EXTRA_CONFIGURATION, mConfiguration); 99 | } 100 | 101 | @Override 102 | protected void onRestoreInstanceState(Bundle savedInstanceState) { 103 | super.onRestoreInstanceState(savedInstanceState); 104 | printActivityLife("onRestoreInstanceState"); 105 | mConfiguration = savedInstanceState.getParcelable(EXTRA_CONFIGURATION); 106 | } 107 | 108 | public abstract void findViews(); 109 | 110 | protected abstract void setTheme(); 111 | 112 | private void printActivityLife(String method) { 113 | Logger.i(String.format("Activity:%s Method:%s", CLASS_NAME, method)); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/ui/activity/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * activity包 3 | */ 4 | package cn.finalteam.rxgalleryfinal.ui.activity; -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/ui/adapter/BucketAdapter.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.ui.adapter; 2 | 3 | import android.content.res.ColorStateList; 4 | import android.graphics.Color; 5 | import android.graphics.drawable.ColorDrawable; 6 | import android.graphics.drawable.Drawable; 7 | import android.text.SpannableString; 8 | import android.text.Spanned; 9 | import android.text.TextUtils; 10 | import android.text.style.ForegroundColorSpan; 11 | import android.text.style.RelativeSizeSpan; 12 | import android.view.LayoutInflater; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | import android.widget.RadioButton; 16 | import android.widget.TextView; 17 | 18 | import androidx.annotation.ColorInt; 19 | import androidx.annotation.NonNull; 20 | import androidx.appcompat.widget.AppCompatRadioButton; 21 | import androidx.core.widget.CompoundButtonCompat; 22 | import androidx.recyclerview.widget.RecyclerView; 23 | 24 | import java.util.List; 25 | 26 | import cn.finalteam.rxgalleryfinal.Configuration; 27 | import cn.finalteam.rxgalleryfinal.R; 28 | import cn.finalteam.rxgalleryfinal.bean.BucketBean; 29 | import cn.finalteam.rxgalleryfinal.ui.widget.SquareImageView; 30 | import cn.finalteam.rxgalleryfinal.utils.ThemeUtils; 31 | 32 | /** 33 | * Desction: 34 | * Author:pengjianbo Dujinyang 35 | * Date:16/7/4 下午5:40 36 | */ 37 | public class BucketAdapter extends RecyclerView.Adapter { 38 | 39 | private final List mBucketList; 40 | private final Drawable mDefaultImage; 41 | private final Configuration mConfiguration; 42 | private OnRecyclerViewItemClickListener mOnRecyclerViewItemClickListener; 43 | private BucketBean mSelectedBucket; 44 | 45 | public BucketAdapter( 46 | List bucketList, 47 | Configuration configuration, 48 | @ColorInt int color) { 49 | this.mBucketList = bucketList; 50 | this.mConfiguration = configuration; 51 | this.mDefaultImage = new ColorDrawable(color); 52 | } 53 | 54 | @NonNull 55 | @Override 56 | public BucketViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 57 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.gallery_adapter_bucket_item, parent, false); 58 | return new BucketViewHolder(parent, view); 59 | } 60 | 61 | @Override 62 | public void onBindViewHolder(BucketViewHolder holder, int position) { 63 | BucketBean bucketBean = mBucketList.get(position); 64 | String bucketName = bucketBean.getBucketName(); 65 | if (position != 0) { 66 | SpannableString nameSpannable = new SpannableString(bucketName + "\n" + bucketBean.getImageCount() + "张"); 67 | nameSpannable.setSpan(new ForegroundColorSpan(Color.GRAY), bucketName.length(), nameSpannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 68 | nameSpannable.setSpan(new RelativeSizeSpan(0.8f), bucketName.length(), nameSpannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 69 | holder.mTvBucketName.setText(nameSpannable); 70 | } else { 71 | holder.mTvBucketName.setText(bucketName); 72 | } 73 | if (mSelectedBucket != null && TextUtils.equals(mSelectedBucket.getBucketId(), bucketBean.getBucketId())) { 74 | holder.mRbSelected.setVisibility(View.VISIBLE); 75 | holder.mRbSelected.setChecked(true); 76 | } else { 77 | holder.mRbSelected.setVisibility(View.GONE); 78 | } 79 | 80 | String path = bucketBean.getCover(); 81 | mConfiguration.getImageLoader() 82 | .displayImage(holder.itemView.getContext(), path, holder.mIvBucketCover, mDefaultImage, mConfiguration.getImageConfig(), 83 | true, mConfiguration.isPlayGif(), 100, 100, bucketBean.getOrientation()); 84 | } 85 | 86 | public void setSelectedBucket(BucketBean bucketBean) { 87 | this.mSelectedBucket = bucketBean; 88 | notifyDataSetChanged(); 89 | } 90 | 91 | @Override 92 | public int getItemCount() { 93 | return mBucketList.size(); 94 | } 95 | 96 | public void setOnRecyclerViewItemClickListener(OnRecyclerViewItemClickListener listener) { 97 | this.mOnRecyclerViewItemClickListener = listener; 98 | } 99 | 100 | public interface OnRecyclerViewItemClickListener { 101 | void onItemClick(View view, int position); 102 | } 103 | 104 | class BucketViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 105 | 106 | final TextView mTvBucketName; 107 | final SquareImageView mIvBucketCover; 108 | final AppCompatRadioButton mRbSelected; 109 | 110 | private final ViewGroup mParentView; 111 | 112 | BucketViewHolder(ViewGroup parent, View itemView) { 113 | super(itemView); 114 | this.mParentView = parent; 115 | mTvBucketName = (TextView) itemView.findViewById(R.id.tv_bucket_name); 116 | mIvBucketCover = (SquareImageView) itemView.findViewById(R.id.iv_bucket_cover); 117 | mRbSelected = (AppCompatRadioButton) itemView.findViewById(R.id.rb_selected); 118 | 119 | itemView.setOnClickListener(this); 120 | 121 | int checkTint = ThemeUtils.resolveColor(itemView.getContext(), R.attr.gallery_checkbox_button_tint_color, R.color.gallery_default_checkbox_button_tint_color); 122 | CompoundButtonCompat.setButtonTintList(mRbSelected, ColorStateList.valueOf(checkTint)); 123 | } 124 | 125 | @Override 126 | public void onClick(View v) { 127 | if (mOnRecyclerViewItemClickListener != null) { 128 | mOnRecyclerViewItemClickListener.onItemClick(v, getLayoutPosition()); 129 | } 130 | 131 | setRadioDisChecked(mParentView); 132 | mRbSelected.setVisibility(View.VISIBLE); 133 | mRbSelected.setChecked(true); 134 | } 135 | 136 | /** 137 | * 设置未所有Item为未选中 138 | */ 139 | private void setRadioDisChecked(ViewGroup parentView) { 140 | if (parentView == null || parentView.getChildCount() < 1) { 141 | return; 142 | } 143 | 144 | for (int i = 0; i < parentView.getChildCount(); i++) { 145 | View itemView = parentView.getChildAt(i); 146 | RadioButton rbSelect = (RadioButton) itemView.findViewById(R.id.rb_selected); 147 | if (rbSelect != null) { 148 | rbSelect.setVisibility(View.GONE); 149 | rbSelect.setChecked(false); 150 | } 151 | } 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/ui/adapter/MediaPreviewAdapter.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.ui.adapter; 2 | 3 | import android.graphics.drawable.Drawable; 4 | import android.text.TextUtils; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import java.util.List; 9 | 10 | import cn.finalteam.rxgalleryfinal.Configuration; 11 | import cn.finalteam.rxgalleryfinal.R; 12 | import cn.finalteam.rxgalleryfinal.bean.MediaBean; 13 | import uk.co.senab.photoview.PhotoView; 14 | 15 | /** 16 | * Desction: 17 | * Author:pengjianbo Dujinyang 18 | * Date:16/7/21 下午10:12 19 | */ 20 | public class MediaPreviewAdapter extends RecyclingPagerAdapter { 21 | 22 | private final List mMediaList; 23 | private final Configuration mConfiguration; 24 | private final Drawable mDefaultImage; 25 | private final int mScreenWidth; 26 | private final int mScreenHeight; 27 | private final int mPageColor; 28 | 29 | public MediaPreviewAdapter(List list, 30 | int screenWidth, 31 | int screenHeight, 32 | Configuration configuration, 33 | int pageColor, 34 | Drawable drawable) { 35 | this.mMediaList = list; 36 | this.mScreenWidth = screenWidth; 37 | this.mScreenHeight = screenHeight; 38 | this.mConfiguration = configuration; 39 | this.mPageColor = pageColor; 40 | this.mDefaultImage = drawable; 41 | } 42 | 43 | @Override 44 | public View getView(int position, View convertView, ViewGroup container) { 45 | MediaBean mediaBean = mMediaList.get(position); 46 | if (convertView == null) { 47 | convertView = View.inflate(container.getContext(), R.layout.gallery_media_image_preview_item, null); 48 | } 49 | PhotoView ivImage = (PhotoView) convertView.findViewById(R.id.iv_media_image); 50 | String path = null; 51 | if (mediaBean.getWidth() > 1200 || mediaBean.getHeight() > 1200) { 52 | path = mediaBean.getThumbnailBigPath(); 53 | } 54 | if (TextUtils.isEmpty(path)) { 55 | path = mediaBean.getOriginalPath(); 56 | } 57 | ivImage.setBackgroundColor(mPageColor); 58 | mConfiguration.getImageLoader().displayImage(container.getContext(), path, ivImage, mDefaultImage, mConfiguration.getImageConfig(), 59 | false, mConfiguration.isPlayGif(), mScreenWidth, mScreenHeight, mediaBean.getOrientation()); 60 | return convertView; 61 | } 62 | 63 | @Override 64 | public int getCount() { 65 | return mMediaList.size(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/ui/adapter/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * adapter包 3 | */ 4 | package cn.finalteam.rxgalleryfinal.ui.adapter; -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/ui/base/IMultiImageCheckedListener.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.ui.base; 2 | 3 | /** 4 | * 复选 5 | * Created by KARL on 2017-03-17 04-22-30. 6 | */ 7 | public interface IMultiImageCheckedListener { 8 | void selectedImg(Object t, boolean isChecked); 9 | 10 | void selectedImgMax(Object t, boolean isChecked, int maxSize); 11 | } 12 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/ui/base/IRadioImageCheckedListener.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.ui.base; 2 | 3 | /** 4 | * 单选裁剪 5 | * Created by KARL on 2017-05-31. 6 | */ 7 | public interface IRadioImageCheckedListener { 8 | 9 | /** 10 | * 裁剪之后 11 | */ 12 | void cropAfter(Object t); 13 | 14 | /** 15 | * 返回true则关闭,false默认不关闭 16 | */ 17 | boolean isActivityFinish(); 18 | } 19 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/ui/fragment/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * fragment包 3 | */ 4 | package cn.finalteam.rxgalleryfinal.ui.fragment; -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/ui/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * UI展示包 3 | */ 4 | package cn.finalteam.rxgalleryfinal.ui; -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/ui/widget/FixImageView.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.ui.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.drawable.Drawable; 6 | import android.util.AttributeSet; 7 | import android.view.MotionEvent; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.appcompat.widget.AppCompatImageView; 11 | 12 | /** 13 | * Desction:为了兼容fresco框架而自定义的ImageView 14 | * Author:pengjianbo Dujinyang 15 | * Date:2015/12/24 0024 20:14 16 | */ 17 | public class FixImageView extends AppCompatImageView { 18 | 19 | private OnImageViewListener mOnImageViewListener; 20 | 21 | public FixImageView(Context context) { 22 | super(context); 23 | } 24 | 25 | public FixImageView(Context context, AttributeSet attrs) { 26 | super(context, attrs); 27 | } 28 | 29 | public FixImageView(Context context, AttributeSet attrs, int defStyleAttr) { 30 | super(context, attrs, defStyleAttr); 31 | } 32 | 33 | public void setOnImageViewListener(OnImageViewListener listener) { 34 | mOnImageViewListener = listener; 35 | } 36 | 37 | @Override 38 | protected void onDetachedFromWindow() { 39 | super.onDetachedFromWindow(); 40 | if (mOnImageViewListener != null) { 41 | mOnImageViewListener.onDetach(); 42 | } 43 | } 44 | 45 | @Override 46 | protected void onAttachedToWindow() { 47 | super.onAttachedToWindow(); 48 | if (mOnImageViewListener != null) { 49 | mOnImageViewListener.onAttach(); 50 | } 51 | } 52 | 53 | @Override 54 | protected boolean verifyDrawable(@NonNull Drawable dr) { 55 | if (mOnImageViewListener != null) { 56 | if (mOnImageViewListener.verifyDrawable(dr)) { 57 | return true; 58 | } 59 | } 60 | return super.verifyDrawable(dr); 61 | } 62 | 63 | @Override 64 | public void onStartTemporaryDetach() { 65 | super.onStartTemporaryDetach(); 66 | if (mOnImageViewListener != null) { 67 | mOnImageViewListener.onDetach(); 68 | } 69 | } 70 | 71 | @Override 72 | public void onFinishTemporaryDetach() { 73 | super.onFinishTemporaryDetach(); 74 | if (mOnImageViewListener != null) { 75 | mOnImageViewListener.onAttach(); 76 | } 77 | } 78 | 79 | @Override 80 | protected void onDraw(Canvas canvas) { 81 | super.onDraw(canvas); 82 | if (mOnImageViewListener != null) { 83 | 84 | mOnImageViewListener.onDraw(canvas); 85 | } 86 | } 87 | 88 | @Override 89 | public boolean onTouchEvent(MotionEvent event) { 90 | if (mOnImageViewListener == null) { 91 | return super.onTouchEvent(event); 92 | } 93 | return mOnImageViewListener.onTouchEvent(event) || super.onTouchEvent(event); 94 | } 95 | 96 | public interface OnImageViewListener { 97 | void onDetach(); 98 | 99 | void onAttach(); 100 | 101 | boolean verifyDrawable(Drawable dr); 102 | 103 | void onDraw(Canvas canvas); 104 | 105 | boolean onTouchEvent(MotionEvent event); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/ui/widget/FixViewPager.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.ui.widget; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.MotionEvent; 6 | 7 | import androidx.viewpager.widget.ViewPager; 8 | 9 | /** 10 | * Desction: 11 | * Author:pengjianbo Dujinyang 12 | * Date:2015/12/29 0029 19:29 13 | */ 14 | public class FixViewPager extends ViewPager { 15 | public FixViewPager(Context context) { 16 | super(context); 17 | } 18 | 19 | public FixViewPager(Context context, AttributeSet attrs) { 20 | super(context, attrs); 21 | } 22 | 23 | @Override 24 | public boolean dispatchTouchEvent(MotionEvent ev) { 25 | try { 26 | return super.dispatchTouchEvent(ev); 27 | } catch (IllegalArgumentException ignored) { 28 | } 29 | return false; 30 | } 31 | } -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/ui/widget/FooterAdapter.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.ui.widget; 2 | 3 | import android.view.View; 4 | import android.view.ViewGroup; 5 | 6 | import androidx.recyclerview.widget.RecyclerView; 7 | 8 | 9 | /** 10 | * Desction:footer适配器 11 | * Author:pengjianbo Dujinyang 12 | * Date:16/5/21 下午3:59 13 | */ 14 | public class FooterAdapter extends RecyclerView.Adapter { 15 | private static final int ITEM_VIEW_TYPE_FOOTER = 0; 16 | private static final int ITEM_VIEW_TYPE_ITEM = 1; 17 | 18 | private final RecyclerView.Adapter mAdapter; 19 | private final View mFooterView; 20 | private OnItemClickListener mOnItemClickListener; 21 | 22 | public FooterAdapter(RecyclerView.Adapter adapter, View footerView) { 23 | this.mAdapter = adapter; 24 | this.mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { 25 | @Override 26 | public void onChanged() { 27 | super.onChanged(); 28 | notifyDataSetChanged(); 29 | } 30 | }); 31 | this.mFooterView = footerView; 32 | } 33 | 34 | @Override 35 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 36 | if (viewType == ITEM_VIEW_TYPE_FOOTER) { 37 | return new FooterViewHolder(mFooterView); 38 | } 39 | return mAdapter.onCreateViewHolder(parent, viewType); 40 | } 41 | 42 | @Override 43 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 44 | if (!isFooter(position)) { 45 | if (mOnItemClickListener != null) { 46 | holder.itemView.setOnClickListener(v -> mOnItemClickListener.onItemClick(holder, position)); 47 | } 48 | mAdapter.onBindViewHolder(holder, position); 49 | } 50 | } 51 | 52 | /** 53 | * 设置Item点击事件 54 | */ 55 | public void setOnItemClickListener(OnItemClickListener listener) { 56 | this.mOnItemClickListener = listener; 57 | } 58 | 59 | @Override 60 | public int getItemCount() { 61 | return mAdapter.getItemCount() + 1; 62 | } 63 | 64 | @Override 65 | public int getItemViewType(int position) { 66 | return isFooter(position) ? ITEM_VIEW_TYPE_FOOTER : ITEM_VIEW_TYPE_ITEM; 67 | } 68 | 69 | public boolean isFooter(int position) { 70 | return position == getItemCount() - 1; 71 | } 72 | 73 | public interface OnItemClickListener { 74 | void onItemClick(RecyclerView.ViewHolder holder, int position); 75 | } 76 | 77 | class FooterViewHolder extends RecyclerView.ViewHolder { 78 | 79 | public FooterViewHolder(View itemView) { 80 | super(itemView); 81 | } 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/ui/widget/MarginDecoration.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.ui.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Rect; 5 | import android.view.View; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.recyclerview.widget.RecyclerView; 9 | 10 | import cn.finalteam.rxgalleryfinal.R; 11 | 12 | public class MarginDecoration extends RecyclerView.ItemDecoration { 13 | private final int margin; 14 | 15 | public MarginDecoration(Context context) { 16 | margin = context.getResources().getDimensionPixelSize(R.dimen.gallery_grid_item_margin); 17 | } 18 | 19 | @Override 20 | public void getItemOffsets(Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { 21 | outRect.set(margin, margin, margin, margin); 22 | } 23 | } -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/ui/widget/SquareImageView.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.ui.widget; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | 6 | /** 7 | * Desction: 8 | * Author:pengjianbo Dujinyang 9 | * Date:16/7/9 上午12:53 10 | */ 11 | public class SquareImageView extends FixImageView { 12 | public SquareImageView(Context context) { 13 | super(context); 14 | } 15 | 16 | public SquareImageView(Context context, AttributeSet attrs) { 17 | super(context, attrs); 18 | } 19 | 20 | public SquareImageView(Context context, AttributeSet attrs, int defStyleAttr) { 21 | super(context, attrs, defStyleAttr); 22 | } 23 | 24 | @Override 25 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 26 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 27 | setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth()); //Snap to width 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/ui/widget/SquareLinearLayout.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.ui.widget; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.LinearLayout; 6 | 7 | /** 8 | * Desction: 9 | * Author:pengjianbo Dujinyang 10 | * Date:16/6/17 下午1:48 11 | */ 12 | public class SquareLinearLayout extends LinearLayout { 13 | 14 | public SquareLinearLayout(Context context) { 15 | super(context); 16 | } 17 | 18 | public SquareLinearLayout(Context context, AttributeSet attrs) { 19 | super(context, attrs); 20 | } 21 | 22 | @Override 23 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 24 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 25 | setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth()); //Snap to width 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/ui/widget/SquareRelativeLayout.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.ui.widget; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.RelativeLayout; 6 | 7 | /** 8 | * Desction: 9 | * Author:pengjianbo Dujinyang 10 | * Date:16/6/8 下午4:07 11 | */ 12 | public class SquareRelativeLayout extends RelativeLayout { 13 | 14 | public SquareRelativeLayout(Context context) { 15 | super(context); 16 | } 17 | 18 | public SquareRelativeLayout(Context context, AttributeSet attrs) { 19 | super(context, attrs); 20 | } 21 | 22 | public SquareRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) { 23 | super(context, attrs, defStyleAttr); 24 | } 25 | 26 | @Override 27 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 28 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 29 | setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth()); //Snap to width 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/ui/widget/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 控件包 3 | */ 4 | package cn.finalteam.rxgalleryfinal.ui.widget; -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/utils/CameraUtils.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.utils; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageManager; 5 | 6 | /** 7 | * Desction: 8 | * Author:pengjianbo Dujinyang 9 | * Date:16/6/3 下午8:28 10 | */ 11 | public class CameraUtils { 12 | 13 | /** 14 | * 判断设备是否有摄像头 15 | */ 16 | public static boolean hasCamera(Context context) { 17 | PackageManager packageManager = context.getPackageManager(); 18 | return packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY); 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/utils/DeviceUtils.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.utils; 2 | 3 | import android.content.Context; 4 | import android.util.DisplayMetrics; 5 | import android.view.WindowManager; 6 | 7 | /** 8 | * Desction: 9 | * Author:pengjianbo Dujinyang 10 | * Date:16/8/8 下午11:05 11 | */ 12 | public class DeviceUtils { 13 | 14 | public static DisplayMetrics getScreenSize(Context context) { 15 | DisplayMetrics displaysMetrics = new DisplayMetrics(); 16 | context.getResources().getDisplayMetrics(); 17 | WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 18 | wm.getDefaultDisplay().getMetrics(displaysMetrics); 19 | return displaysMetrics; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/utils/EmptyViewUtils.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.utils; 2 | 3 | import android.view.View; 4 | import android.view.ViewGroup; 5 | import android.widget.ProgressBar; 6 | import android.widget.TextView; 7 | 8 | /** 9 | * Desction: 10 | * Author:pengjianbo Dujinyang 11 | * Date:16/5/14 下午7:26 12 | */ 13 | public class EmptyViewUtils { 14 | 15 | public static void showLoading(ViewGroup emptyView) { 16 | if (emptyView == null) { 17 | return; 18 | } 19 | ProgressBar pbLoading = (ProgressBar) emptyView.getChildAt(0); 20 | pbLoading.setVisibility(View.VISIBLE); 21 | TextView tvEmptyMsg = (TextView) emptyView.getChildAt(1); 22 | tvEmptyMsg.setVisibility(View.GONE); 23 | } 24 | 25 | public static void showMessage(ViewGroup emptyView, String msg) { 26 | if (emptyView == null) { 27 | return; 28 | } 29 | ProgressBar pbLoading = (ProgressBar) emptyView.getChildAt(0); 30 | pbLoading.setVisibility(View.GONE); 31 | TextView tvEmptyMsg = (TextView) emptyView.getChildAt(1); 32 | tvEmptyMsg.setVisibility(View.VISIBLE); 33 | tvEmptyMsg.setText(msg); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.utils; 2 | 3 | /** 4 | * Desction:文件工具类 5 | * Author:dujinyang 6 | */ 7 | public class FileUtils { 8 | 9 | /** 10 | * 验证是否是图片路径 11 | */ 12 | public static int existImageDir(String dir) { 13 | return dir.trim().lastIndexOf("."); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/utils/IOUtils.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.utils; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | 7 | /** 8 | * Desction: 9 | * Author:pengjianbo Dujinyang 10 | * Date:16/5/7 上午9:45 11 | */ 12 | public class IOUtils { 13 | 14 | public static void close(OutputStream stream) { 15 | if (stream != null) { 16 | try { 17 | stream.close(); 18 | } catch (IOException e) { 19 | e.printStackTrace(); 20 | } 21 | } 22 | } 23 | 24 | public static void close(InputStream stream) { 25 | if (stream != null) { 26 | try { 27 | stream.close(); 28 | } catch (IOException e) { 29 | e.printStackTrace(); 30 | } 31 | } 32 | } 33 | 34 | public static void flush(OutputStream stream) { 35 | if (stream != null) { 36 | try { 37 | stream.flush(); 38 | } catch (IOException e) { 39 | e.printStackTrace(); 40 | } 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/utils/Logger.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.utils; 2 | 3 | import android.util.Log; 4 | 5 | import cn.finalteam.rxgalleryfinal.BuildConfig; 6 | 7 | /** 8 | * Desction:日志工具 9 | * Author:pengjianbo Dujinyang 10 | * Date:16/5/23 下午3:12 11 | */ 12 | public class Logger { 13 | 14 | public static final String TAG = "RxGalleryFinal"; 15 | public static boolean DEBUG = BuildConfig.DEBUG; 16 | 17 | public static void d(String value) { 18 | if (DEBUG) { 19 | Log.d(TAG, value); 20 | } 21 | } 22 | 23 | public static void e(String value) { 24 | if (DEBUG) { 25 | Log.e(TAG, value); 26 | } 27 | } 28 | 29 | public static void e(Exception value) { 30 | if (DEBUG && value != null) { 31 | Log.e(TAG, value.getMessage()); 32 | } 33 | } 34 | 35 | public static void i(String value) { 36 | if (DEBUG) { 37 | Log.i(TAG, value); 38 | } 39 | } 40 | 41 | public static void w(String value) { 42 | if (DEBUG) { 43 | Log.w(TAG, value); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/utils/MediaScanner.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.utils; 2 | 3 | import android.content.Context; 4 | import android.media.MediaScannerConnection; 5 | import android.net.Uri; 6 | 7 | /** 8 | * Desction:媒体扫描工具类 9 | * Author:pengjianbo Dujinyang 10 | * Date:16/6/8 上午11:36 11 | */ 12 | public class MediaScanner { 13 | private MediaScannerConnection mediaScanConn = null; 14 | private String fileType = null; 15 | private String[] filePaths = null; 16 | private ScanCallback scanCallback; 17 | 18 | /** 19 | * 然后调用MediaScanner.scanFile("/sdcard/2.mp3"); 20 | */ 21 | public MediaScanner(Context context) { 22 | MusicSannerClient client; 23 | client = new MusicSannerClient(); 24 | 25 | if (mediaScanConn == null) { 26 | mediaScanConn = new MediaScannerConnection(context, client); 27 | } 28 | } 29 | 30 | /** 31 | * 扫描文件标签信息 32 | * 33 | * @param filePath 文件路径 34 | * @param fileType 文件类型 35 | */ 36 | 37 | public void scanFile(String filePath, String fileType, ScanCallback callback) { 38 | this.filePaths = new String[]{filePath}; 39 | this.fileType = fileType; 40 | this.scanCallback = callback; 41 | //连接之后调用MusicSannerClient的onMediaScannerConnected()方法 42 | mediaScanConn.connect(); 43 | } 44 | 45 | /** 46 | * @param filePaths 文件路径 47 | * @param fileType 文件类型 48 | */ 49 | public void scanFile(String[] filePaths, String fileType, ScanCallback callback) { 50 | this.filePaths = filePaths; 51 | this.fileType = fileType; 52 | this.scanCallback = callback; 53 | mediaScanConn.connect(); 54 | } 55 | 56 | public void unScanFile() { 57 | mediaScanConn.disconnect(); 58 | } 59 | 60 | public interface ScanCallback { 61 | void onScanCompleted(String[] images); 62 | } 63 | 64 | private class MusicSannerClient implements MediaScannerConnection.MediaScannerConnectionClient { 65 | @Override 66 | public void onMediaScannerConnected() { 67 | Logger.i("onMediaScannerConnected"); 68 | if (filePaths != null) { 69 | for (String file : filePaths) { 70 | mediaScanConn.scanFile(file, fileType); 71 | } 72 | } 73 | } 74 | 75 | @Override 76 | public void onScanCompleted(String path, Uri uri) { 77 | Logger.i("onScanCompleted"); 78 | mediaScanConn.disconnect(); 79 | if (scanCallback != null) { 80 | scanCallback.onScanCompleted(filePaths); 81 | } 82 | fileType = null; 83 | filePaths = null; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/utils/MediaType.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.utils; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Desction:支持的Media类型 7 | * Author:pengjianbo Dujinyang 8 | * Date:16/5/5 下午5:03 9 | */ 10 | public enum MediaType implements Serializable { 11 | JPG, PNG, WEBP, GIF, MP4; 12 | 13 | public boolean hasVideo() { 14 | return this == MP4; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/utils/ModelUtils.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.utils; 2 | 3 | 4 | import android.util.Log; 5 | 6 | import cn.finalteam.rxgalleryfinal.BuildConfig; 7 | 8 | /** 9 | * 模式 10 | * Created by KARL-dujinyang on 2017-03-17 02-24-08. 11 | */ 12 | public class ModelUtils { 13 | private static final String TAG = "Test"; 14 | 15 | public static void logDebug() { 16 | Log.w(TAG, "BuildConfig.DEBUG:--" + BuildConfig.DEBUG + "--"); 17 | if (BuildConfig.DEBUG) 18 | Logger.w("is debug mode"); 19 | else 20 | Logger.w("not debug mode"); 21 | } 22 | 23 | /** 24 | * 多层依赖时DEBUGCONFIG会出错,所以提供了内部接口更改 25 | * 26 | * @param f 是否打开 27 | */ 28 | public static void setDebugModel(boolean f) { 29 | Logger.DEBUG = f; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/utils/OsCompat.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.utils; 2 | 3 | import android.graphics.drawable.Drawable; 4 | import android.os.Build; 5 | import android.view.View; 6 | 7 | /** 8 | * Desction: 9 | * Author:pengjianbo Dujinyang 10 | * Date:16/7/20 下午4:23 11 | */ 12 | public class OsCompat { 13 | 14 | public static void setBackgroundDrawableCompat(View view, Drawable drawable) { 15 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 16 | view.setBackground(drawable); 17 | } else { 18 | //noinspection deprecation 19 | view.setBackgroundDrawable(drawable); 20 | } 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/utils/PermissionCheckUtils.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.utils; 2 | 3 | import android.Manifest; 4 | import android.annotation.TargetApi; 5 | import android.app.Activity; 6 | import android.content.pm.PackageManager; 7 | import android.os.Build; 8 | 9 | import androidx.appcompat.app.AlertDialog; 10 | import androidx.core.app.ActivityCompat; 11 | import androidx.core.content.ContextCompat; 12 | 13 | /** 14 | * Desction:权限检查工具 15 | * Author:pengjianbo Dujinyang 16 | * Author:KARL-dujinyang 17 | * Date:16/6/1 下午7:40 18 | */ 19 | public class PermissionCheckUtils { 20 | 21 | /** 22 | * 数组 23 | */ 24 | public static boolean checkPermission(Activity activity, String permission, String permissionDesc, int requestCode) { 25 | int currentAPIVersion = Build.VERSION.SDK_INT; 26 | if (currentAPIVersion >= android.os.Build.VERSION_CODES.M) { 27 | if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) { 28 | Logger.i("ContextCompat.checkSelfPermission(activity, permission):" + ContextCompat.checkSelfPermission(activity, permission)); 29 | Logger.i("PackageManager.PERMISSION_GRANTED:" + PackageManager.PERMISSION_GRANTED); 30 | Logger.i("permission:" + permission); 31 | if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) { 32 | AlertDialog.Builder alertBuilder = new AlertDialog.Builder(activity); 33 | alertBuilder.setCancelable(false); 34 | alertBuilder.setTitle("授权对话框"); 35 | alertBuilder.setMessage(permissionDesc); 36 | alertBuilder.setPositiveButton(android.R.string.yes, (dialog, which) -> ActivityCompat.requestPermissions(activity, new String[]{permission}, requestCode)); 37 | AlertDialog alert = alertBuilder.create(); 38 | alert.show(); 39 | } else { 40 | ActivityCompat.requestPermissions(activity, new String[]{permission}, requestCode); 41 | } 42 | return false; 43 | } else { 44 | return true; 45 | } 46 | } else { 47 | return true; 48 | } 49 | } 50 | 51 | 52 | /** 53 | * 检查是否对sd卡读取授权 54 | */ 55 | @TargetApi(16) 56 | public static boolean checkReadExternalPermission(Activity activity, String permissionDesc, int requestCode) { 57 | return checkPermission(activity, Manifest.permission.READ_EXTERNAL_STORAGE, permissionDesc, requestCode); 58 | } 59 | 60 | 61 | /** 62 | * 检查是否对sd卡读取授权 63 | */ 64 | @TargetApi(16) 65 | public static boolean checkWriteExternalPermission(Activity activity, String permissionDesc, int requestCode) { 66 | return checkPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE, permissionDesc, requestCode); 67 | } 68 | 69 | /** 70 | * 检查是否对相机读取授权 71 | */ 72 | @TargetApi(16) 73 | public static boolean checkCameraPermission(Activity activity, String permissionDesc, int requestCode) { 74 | return checkPermission(activity, Manifest.permission.CAMERA, permissionDesc, requestCode); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/utils/SimpleDateUtils.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.utils; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | import java.util.Locale; 6 | 7 | /** 8 | * 时间工具类 9 | * Created by KARL-dujinyang on 2017-04-13. 10 | */ 11 | public class SimpleDateUtils { 12 | 13 | public static String getNowTime() { 14 | SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss", Locale.CHINA); 15 | return dateFormat.format(new Date()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/utils/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 工具包 3 | */ 4 | package cn.finalteam.rxgalleryfinal.utils; -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/view/ActivityFragmentView.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.view; 2 | 3 | import java.util.ArrayList; 4 | 5 | import cn.finalteam.rxgalleryfinal.bean.MediaBean; 6 | 7 | /** 8 | * Desction: 9 | * Author:pengjianbo Dujinyang 10 | * Date:16/5/14 下午9:56 11 | */ 12 | public interface ActivityFragmentView { 13 | 14 | void showMediaGridFragment(); 15 | 16 | void showMediaPageFragment(ArrayList list, int position); 17 | 18 | void showMediaPreviewFragment(); 19 | } 20 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/view/MediaGridView.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.view; 2 | 3 | import java.util.List; 4 | 5 | import cn.finalteam.rxgalleryfinal.bean.BucketBean; 6 | import cn.finalteam.rxgalleryfinal.bean.MediaBean; 7 | 8 | /** 9 | * Desction: 10 | * Author:pengjianbo Dujinyang 11 | * Date:16/5/14 上午11:00 12 | */ 13 | public interface MediaGridView { 14 | void onRequestMediaCallback(List list); 15 | 16 | void onRequestBucketCallback(List list); 17 | } 18 | -------------------------------------------------------------------------------- /library/src/main/java/cn/finalteam/rxgalleryfinal/view/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MVP V接口 3 | */ 4 | package cn.finalteam.rxgalleryfinal.view; -------------------------------------------------------------------------------- /library/src/main/java/uk/co/senab/photoview/Compat.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package uk.co.senab.photoview; 17 | 18 | import android.annotation.TargetApi; 19 | import android.os.Build.VERSION; 20 | import android.os.Build.VERSION_CODES; 21 | import android.view.MotionEvent; 22 | import android.view.View; 23 | 24 | public class Compat { 25 | 26 | private static final int SIXTY_FPS_INTERVAL = 1000 / 60; 27 | 28 | public static void postOnAnimation(View view, Runnable runnable) { 29 | if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) { 30 | postOnAnimationJellyBean(view, runnable); 31 | } else { 32 | view.postDelayed(runnable, SIXTY_FPS_INTERVAL); 33 | } 34 | } 35 | 36 | @TargetApi(16) 37 | private static void postOnAnimationJellyBean(View view, Runnable runnable) { 38 | view.postOnAnimation(runnable); 39 | } 40 | 41 | public static int getPointerIndex(int action) { 42 | return getPointerIndexHoneyComb(action); 43 | } 44 | 45 | @SuppressWarnings("deprecation") 46 | @TargetApi(VERSION_CODES.ECLAIR) 47 | private static int getPointerIndexEclair(int action) { 48 | return (action & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT; 49 | } 50 | 51 | @TargetApi(VERSION_CODES.HONEYCOMB) 52 | private static int getPointerIndexHoneyComb(int action) { 53 | return (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /library/src/main/java/uk/co/senab/photoview/DefaultOnDoubleTapListener.java: -------------------------------------------------------------------------------- 1 | package uk.co.senab.photoview; 2 | 3 | import android.graphics.RectF; 4 | import android.view.GestureDetector; 5 | import android.view.MotionEvent; 6 | import android.widget.ImageView; 7 | 8 | /** 9 | * Provided default implementation of GestureDetector.OnDoubleTapListener, to be overriden with custom behavior, if needed 10 | *

 

11 | * To be used via {@link PhotoViewAttacher#setOnDoubleTapListener(GestureDetector.OnDoubleTapListener)} 12 | */ 13 | public class DefaultOnDoubleTapListener implements GestureDetector.OnDoubleTapListener { 14 | 15 | private PhotoViewAttacher photoViewAttacher; 16 | 17 | /** 18 | * Default constructor 19 | * 20 | * @param photoViewAttacher PhotoViewAttacher to bind to 21 | */ 22 | public DefaultOnDoubleTapListener(PhotoViewAttacher photoViewAttacher) { 23 | setPhotoViewAttacher(photoViewAttacher); 24 | } 25 | 26 | /** 27 | * Allows to change PhotoViewAttacher within range of single instance 28 | * 29 | * @param newPhotoViewAttacher PhotoViewAttacher to bind to 30 | */ 31 | public void setPhotoViewAttacher(PhotoViewAttacher newPhotoViewAttacher) { 32 | this.photoViewAttacher = newPhotoViewAttacher; 33 | } 34 | 35 | @Override 36 | public boolean onSingleTapConfirmed(MotionEvent e) { 37 | if (this.photoViewAttacher == null) 38 | return false; 39 | 40 | ImageView imageView = photoViewAttacher.getImageView(); 41 | 42 | if (null != photoViewAttacher.getOnPhotoTapListener()) { 43 | final RectF displayRect = photoViewAttacher.getDisplayRect(); 44 | 45 | if (null != displayRect) { 46 | final float x = e.getX(), y = e.getY(); 47 | 48 | // Check to see if the user tapped on the photo 49 | if (displayRect.contains(x, y)) { 50 | 51 | float xResult = (x - displayRect.left) 52 | / displayRect.width(); 53 | float yResult = (y - displayRect.top) 54 | / displayRect.height(); 55 | 56 | photoViewAttacher.getOnPhotoTapListener().onPhotoTap(imageView, xResult, yResult); 57 | return true; 58 | } else { 59 | photoViewAttacher.getOnPhotoTapListener().onOutsidePhotoTap(); 60 | } 61 | } 62 | } 63 | if (null != photoViewAttacher.getOnViewTapListener()) { 64 | photoViewAttacher.getOnViewTapListener().onViewTap(imageView, e.getX(), e.getY()); 65 | } 66 | 67 | return false; 68 | } 69 | 70 | @Override 71 | public boolean onDoubleTap(MotionEvent ev) { 72 | if (photoViewAttacher == null) 73 | return false; 74 | 75 | try { 76 | float scale = photoViewAttacher.getScale(); 77 | float x = ev.getX(); 78 | float y = ev.getY(); 79 | 80 | if (scale < photoViewAttacher.getMediumScale()) { 81 | photoViewAttacher.setScale(photoViewAttacher.getMediumScale(), x, y, true); 82 | } else if (scale >= photoViewAttacher.getMediumScale() && scale < photoViewAttacher.getMaximumScale()) { 83 | photoViewAttacher.setScale(photoViewAttacher.getMaximumScale(), x, y, true); 84 | } else { 85 | photoViewAttacher.setScale(photoViewAttacher.getMinimumScale(), x, y, true); 86 | } 87 | } catch (ArrayIndexOutOfBoundsException e) { 88 | // Can sometimes happen when getX() and getY() is called 89 | } 90 | 91 | return true; 92 | } 93 | 94 | @Override 95 | public boolean onDoubleTapEvent(MotionEvent e) { 96 | // Wait for the confirmed onDoubleTap() instead 97 | return false; 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /library/src/main/java/uk/co/senab/photoview/gestures/CupcakeGestureDetector.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package uk.co.senab.photoview.gestures; 17 | 18 | import android.content.Context; 19 | import android.view.MotionEvent; 20 | import android.view.VelocityTracker; 21 | import android.view.ViewConfiguration; 22 | 23 | import cn.finalteam.rxgalleryfinal.utils.Logger; 24 | 25 | public class CupcakeGestureDetector implements GestureDetector { 26 | 27 | private static final String LOG_TAG = "CupcakeGestureDetector"; 28 | final float mTouchSlop; 29 | final float mMinimumVelocity; 30 | protected OnGestureListener mListener; 31 | float mLastTouchX; 32 | float mLastTouchY; 33 | private VelocityTracker mVelocityTracker; 34 | private boolean mIsDragging; 35 | 36 | public CupcakeGestureDetector(Context context) { 37 | final ViewConfiguration configuration = ViewConfiguration 38 | .get(context); 39 | mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); 40 | mTouchSlop = configuration.getScaledTouchSlop(); 41 | } 42 | 43 | @Override 44 | public void setOnGestureListener(OnGestureListener listener) { 45 | this.mListener = listener; 46 | } 47 | 48 | float getActiveX(MotionEvent ev) { 49 | return ev.getX(); 50 | } 51 | 52 | float getActiveY(MotionEvent ev) { 53 | return ev.getY(); 54 | } 55 | 56 | @Override 57 | public boolean isScaling() { 58 | return false; 59 | } 60 | 61 | @Override 62 | public boolean isDragging() { 63 | return mIsDragging; 64 | } 65 | 66 | @Override 67 | public boolean onTouchEvent(MotionEvent ev) { 68 | switch (ev.getAction()) { 69 | case MotionEvent.ACTION_DOWN: { 70 | mVelocityTracker = VelocityTracker.obtain(); 71 | if (null != mVelocityTracker) { 72 | mVelocityTracker.addMovement(ev); 73 | } else { 74 | Logger.i("Velocity tracker is null"); 75 | } 76 | 77 | mLastTouchX = getActiveX(ev); 78 | mLastTouchY = getActiveY(ev); 79 | mIsDragging = false; 80 | break; 81 | } 82 | 83 | case MotionEvent.ACTION_MOVE: { 84 | final float x = getActiveX(ev); 85 | final float y = getActiveY(ev); 86 | final float dx = x - mLastTouchX, dy = y - mLastTouchY; 87 | 88 | if (!mIsDragging) { 89 | // Use Pythagoras to see if drag length is larger than 90 | // touch slop 91 | mIsDragging = Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop; 92 | } 93 | 94 | if (mIsDragging) { 95 | mListener.onDrag(dx, dy); 96 | mLastTouchX = x; 97 | mLastTouchY = y; 98 | 99 | if (null != mVelocityTracker) { 100 | mVelocityTracker.addMovement(ev); 101 | } 102 | } 103 | break; 104 | } 105 | 106 | case MotionEvent.ACTION_CANCEL: { 107 | // Recycle Velocity Tracker 108 | if (null != mVelocityTracker) { 109 | mVelocityTracker.recycle(); 110 | mVelocityTracker = null; 111 | } 112 | break; 113 | } 114 | 115 | case MotionEvent.ACTION_UP: { 116 | if (mIsDragging) { 117 | if (null != mVelocityTracker) { 118 | mLastTouchX = getActiveX(ev); 119 | mLastTouchY = getActiveY(ev); 120 | 121 | // Compute velocity within the last 1000ms 122 | mVelocityTracker.addMovement(ev); 123 | mVelocityTracker.computeCurrentVelocity(1000); 124 | 125 | final float vX = mVelocityTracker.getXVelocity(), vY = mVelocityTracker 126 | .getYVelocity(); 127 | 128 | // If the velocity is greater than minVelocity, call 129 | // listener 130 | if (Math.max(Math.abs(vX), Math.abs(vY)) >= mMinimumVelocity) { 131 | mListener.onFling(mLastTouchX, mLastTouchY, -vX, 132 | -vY); 133 | } 134 | } 135 | } 136 | 137 | // Recycle Velocity Tracker 138 | if (null != mVelocityTracker) { 139 | mVelocityTracker.recycle(); 140 | mVelocityTracker = null; 141 | } 142 | break; 143 | } 144 | } 145 | 146 | return true; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /library/src/main/java/uk/co/senab/photoview/gestures/EclairGestureDetector.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package uk.co.senab.photoview.gestures; 17 | 18 | import android.annotation.TargetApi; 19 | import android.content.Context; 20 | import android.view.MotionEvent; 21 | 22 | import uk.co.senab.photoview.Compat; 23 | 24 | @TargetApi(5) 25 | public class EclairGestureDetector extends CupcakeGestureDetector { 26 | 27 | private static final int INVALID_POINTER_ID = -1; 28 | private int mActivePointerId = INVALID_POINTER_ID; 29 | private int mActivePointerIndex = 0; 30 | 31 | public EclairGestureDetector(Context context) { 32 | super(context); 33 | } 34 | 35 | @Override 36 | float getActiveX(MotionEvent ev) { 37 | try { 38 | return ev.getX(mActivePointerIndex); 39 | } catch (Exception e) { 40 | return ev.getX(); 41 | } 42 | } 43 | 44 | @Override 45 | float getActiveY(MotionEvent ev) { 46 | try { 47 | return ev.getY(mActivePointerIndex); 48 | } catch (Exception e) { 49 | return ev.getY(); 50 | } 51 | } 52 | 53 | @Override 54 | public boolean onTouchEvent(MotionEvent ev) { 55 | final int action = ev.getAction(); 56 | switch (action & MotionEvent.ACTION_MASK) { 57 | case MotionEvent.ACTION_DOWN: 58 | mActivePointerId = ev.getPointerId(0); 59 | break; 60 | case MotionEvent.ACTION_CANCEL: 61 | case MotionEvent.ACTION_UP: 62 | mActivePointerId = INVALID_POINTER_ID; 63 | break; 64 | case MotionEvent.ACTION_POINTER_UP: 65 | // Ignore deprecation, ACTION_POINTER_ID_MASK and 66 | // ACTION_POINTER_ID_SHIFT has same value and are deprecated 67 | // You can have either deprecation or lint target api warning 68 | final int pointerIndex = Compat.getPointerIndex(ev.getAction()); 69 | final int pointerId = ev.getPointerId(pointerIndex); 70 | if (pointerId == mActivePointerId) { 71 | // This was our active pointer going up. Choose a new 72 | // active pointer and adjust accordingly. 73 | final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 74 | mActivePointerId = ev.getPointerId(newPointerIndex); 75 | mLastTouchX = ev.getX(newPointerIndex); 76 | mLastTouchY = ev.getY(newPointerIndex); 77 | } 78 | break; 79 | } 80 | 81 | mActivePointerIndex = ev 82 | .findPointerIndex(mActivePointerId != INVALID_POINTER_ID ? mActivePointerId 83 | : 0); 84 | try { 85 | return super.onTouchEvent(ev); 86 | } catch (IllegalArgumentException e) { 87 | // Fix for support lib bug, happening when onDestroy is 88 | return true; 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /library/src/main/java/uk/co/senab/photoview/gestures/FroyoGestureDetector.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package uk.co.senab.photoview.gestures; 17 | 18 | import android.annotation.TargetApi; 19 | import android.content.Context; 20 | import android.view.MotionEvent; 21 | import android.view.ScaleGestureDetector; 22 | 23 | @TargetApi(8) 24 | public class FroyoGestureDetector extends EclairGestureDetector { 25 | 26 | protected final ScaleGestureDetector mDetector; 27 | 28 | public FroyoGestureDetector(Context context) { 29 | super(context); 30 | ScaleGestureDetector.OnScaleGestureListener mScaleListener = new ScaleGestureDetector.OnScaleGestureListener() { 31 | 32 | @Override 33 | public boolean onScale(ScaleGestureDetector detector) { 34 | float scaleFactor = detector.getScaleFactor(); 35 | 36 | if (Float.isNaN(scaleFactor) || Float.isInfinite(scaleFactor)) 37 | return false; 38 | 39 | mListener.onScale(scaleFactor, 40 | detector.getFocusX(), detector.getFocusY()); 41 | return true; 42 | } 43 | 44 | @Override 45 | public boolean onScaleBegin(ScaleGestureDetector detector) { 46 | return true; 47 | } 48 | 49 | @Override 50 | public void onScaleEnd(ScaleGestureDetector detector) { 51 | // NO-OP 52 | } 53 | }; 54 | mDetector = new ScaleGestureDetector(context, mScaleListener); 55 | } 56 | 57 | @Override 58 | public boolean isScaling() { 59 | return mDetector.isInProgress(); 60 | } 61 | 62 | @Override 63 | public boolean onTouchEvent(MotionEvent ev) { 64 | try { 65 | mDetector.onTouchEvent(ev); 66 | return super.onTouchEvent(ev); 67 | } catch (IllegalArgumentException e) { 68 | // Fix for support lib bug, happening when onDestroy is 69 | return true; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /library/src/main/java/uk/co/senab/photoview/gestures/GestureDetector.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package uk.co.senab.photoview.gestures; 17 | 18 | import android.view.MotionEvent; 19 | 20 | public interface GestureDetector { 21 | 22 | boolean onTouchEvent(MotionEvent ev); 23 | 24 | boolean isScaling(); 25 | 26 | boolean isDragging(); 27 | 28 | void setOnGestureListener(OnGestureListener listener); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /library/src/main/java/uk/co/senab/photoview/gestures/OnGestureListener.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package uk.co.senab.photoview.gestures; 17 | 18 | public interface OnGestureListener { 19 | 20 | void onDrag(float dx, float dy); 21 | 22 | void onFling(float startX, float startY, float velocityX, 23 | float velocityY); 24 | 25 | void onScale(float scaleFactor, float focusX, float focusY); 26 | 27 | } -------------------------------------------------------------------------------- /library/src/main/java/uk/co/senab/photoview/gestures/VersionedGestureDetector.java: -------------------------------------------------------------------------------- 1 | package uk.co.senab.photoview.gestures; 2 | 3 | /******************************************************************************* 4 | * Copyright 2011, 2012 Chris Banes. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | *******************************************************************************/ 18 | 19 | import android.content.Context; 20 | import android.os.Build; 21 | 22 | public final class VersionedGestureDetector { 23 | 24 | public static GestureDetector newInstance(Context context, 25 | OnGestureListener listener) { 26 | final int sdkVersion = Build.VERSION.SDK_INT; 27 | GestureDetector detector; 28 | 29 | if (sdkVersion < Build.VERSION_CODES.ECLAIR) { 30 | detector = new CupcakeGestureDetector(context); 31 | } else if (sdkVersion < Build.VERSION_CODES.FROYO) { 32 | detector = new EclairGestureDetector(context); 33 | } else { 34 | detector = new FroyoGestureDetector(context); 35 | } 36 | 37 | detector.setOnGestureListener(listener); 38 | 39 | return detector; 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /library/src/main/java/uk/co/senab/photoview/scrollerproxy/GingerScroller.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package uk.co.senab.photoview.scrollerproxy; 17 | 18 | import android.annotation.TargetApi; 19 | import android.content.Context; 20 | import android.widget.OverScroller; 21 | 22 | @TargetApi(9) 23 | public class GingerScroller extends ScrollerProxy { 24 | 25 | protected final OverScroller mScroller; 26 | private boolean mFirstScroll = false; 27 | 28 | public GingerScroller(Context context) { 29 | mScroller = new OverScroller(context); 30 | } 31 | 32 | @Override 33 | public boolean computeScrollOffset() { 34 | // Workaround for first scroll returning 0 for the direction of the edge it hits. 35 | // Simply recompute values. 36 | if (mFirstScroll) { 37 | mScroller.computeScrollOffset(); 38 | mFirstScroll = false; 39 | } 40 | return mScroller.computeScrollOffset(); 41 | } 42 | 43 | @Override 44 | public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY, 45 | int overX, int overY) { 46 | mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, overX, overY); 47 | } 48 | 49 | @Override 50 | public void forceFinished(boolean finished) { 51 | mScroller.forceFinished(finished); 52 | } 53 | 54 | @Override 55 | public boolean isFinished() { 56 | return mScroller.isFinished(); 57 | } 58 | 59 | @Override 60 | public int getCurrX() { 61 | return mScroller.getCurrX(); 62 | } 63 | 64 | @Override 65 | public int getCurrY() { 66 | return mScroller.getCurrY(); 67 | } 68 | } -------------------------------------------------------------------------------- /library/src/main/java/uk/co/senab/photoview/scrollerproxy/IcsScroller.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package uk.co.senab.photoview.scrollerproxy; 17 | 18 | import android.annotation.TargetApi; 19 | import android.content.Context; 20 | 21 | @TargetApi(14) 22 | public class IcsScroller extends GingerScroller { 23 | 24 | public IcsScroller(Context context) { 25 | super(context); 26 | } 27 | 28 | @Override 29 | public boolean computeScrollOffset() { 30 | return mScroller.computeScrollOffset(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /library/src/main/java/uk/co/senab/photoview/scrollerproxy/PreGingerScroller.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package uk.co.senab.photoview.scrollerproxy; 17 | 18 | import android.content.Context; 19 | import android.widget.Scroller; 20 | 21 | public class PreGingerScroller extends ScrollerProxy { 22 | 23 | private final Scroller mScroller; 24 | 25 | public PreGingerScroller(Context context) { 26 | mScroller = new Scroller(context); 27 | } 28 | 29 | @Override 30 | public boolean computeScrollOffset() { 31 | return mScroller.computeScrollOffset(); 32 | } 33 | 34 | @Override 35 | public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY, 36 | int overX, int overY) { 37 | mScroller.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY); 38 | } 39 | 40 | @Override 41 | public void forceFinished(boolean finished) { 42 | mScroller.forceFinished(finished); 43 | } 44 | 45 | public boolean isFinished() { 46 | return mScroller.isFinished(); 47 | } 48 | 49 | @Override 50 | public int getCurrX() { 51 | return mScroller.getCurrX(); 52 | } 53 | 54 | @Override 55 | public int getCurrY() { 56 | return mScroller.getCurrY(); 57 | } 58 | } -------------------------------------------------------------------------------- /library/src/main/java/uk/co/senab/photoview/scrollerproxy/ScrollerProxy.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011, 2012 Chris Banes. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package uk.co.senab.photoview.scrollerproxy; 17 | 18 | import android.content.Context; 19 | import android.os.Build.VERSION; 20 | import android.os.Build.VERSION_CODES; 21 | 22 | public abstract class ScrollerProxy { 23 | 24 | public static ScrollerProxy getScroller(Context context) { 25 | if (VERSION.SDK_INT < VERSION_CODES.GINGERBREAD) { 26 | return new PreGingerScroller(context); 27 | } else if (VERSION.SDK_INT < VERSION_CODES.ICE_CREAM_SANDWICH) { 28 | return new GingerScroller(context); 29 | } else { 30 | return new IcsScroller(context); 31 | } 32 | } 33 | 34 | public abstract boolean computeScrollOffset(); 35 | 36 | public abstract void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, 37 | int maxY, int overX, int overY); 38 | 39 | public abstract void forceFinished(boolean finished); 40 | 41 | public abstract boolean isFinished(); 42 | 43 | public abstract int getCurrX(); 44 | 45 | public abstract int getCurrY(); 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /library/src/main/res/color/gallery_text_color_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /library/src/main/res/drawable-hdpi/gallery_ic_cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FinalTeam/RxGalleryFinal/e61b3085605fdf5125ce9ef2d02f13720aa64702/library/src/main/res/drawable-hdpi/gallery_ic_cross.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-ldpi/gallery_ic_cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FinalTeam/RxGalleryFinal/e61b3085605fdf5125ce9ef2d02f13720aa64702/library/src/main/res/drawable-ldpi/gallery_ic_cross.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-mdpi/gallery_ic_cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FinalTeam/RxGalleryFinal/e61b3085605fdf5125ce9ef2d02f13720aa64702/library/src/main/res/drawable-mdpi/gallery_ic_cross.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xhdpi/gallery_ic_cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FinalTeam/RxGalleryFinal/e61b3085605fdf5125ce9ef2d02f13720aa64702/library/src/main/res/drawable-xhdpi/gallery_ic_cross.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xxhdpi-v4/gallery_ic_corner_gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FinalTeam/RxGalleryFinal/e61b3085605fdf5125ce9ef2d02f13720aa64702/library/src/main/res/drawable-xxhdpi-v4/gallery_ic_corner_gray.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xxhdpi/gallery_bg_bucket.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FinalTeam/RxGalleryFinal/e61b3085605fdf5125ce9ef2d02f13720aa64702/library/src/main/res/drawable-xxhdpi/gallery_bg_bucket.9.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xxhdpi/gallery_ic_camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FinalTeam/RxGalleryFinal/e61b3085605fdf5125ce9ef2d02f13720aa64702/library/src/main/res/drawable-xxhdpi/gallery_ic_camera.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xxhdpi/gallery_ic_cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FinalTeam/RxGalleryFinal/e61b3085605fdf5125ce9ef2d02f13720aa64702/library/src/main/res/drawable-xxhdpi/gallery_ic_cross.png -------------------------------------------------------------------------------- /library/src/main/res/drawable-xxxhdpi/gallery_ic_corner_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /library/src/main/res/drawable-xxxhdpi/gallery_ic_cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FinalTeam/RxGalleryFinal/e61b3085605fdf5125ce9ef2d02f13720aa64702/library/src/main/res/drawable-xxxhdpi/gallery_ic_cross.png -------------------------------------------------------------------------------- /library/src/main/res/drawable/gallery_bucket_item_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /library/src/main/res/drawable/gallery_button_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /library/src/main/res/drawable/gallery_default_image.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /library/src/main/res/layout/gallery_activity_media.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 19 | 20 | 27 | 28 | 29 | 33 | 34 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /library/src/main/res/layout/gallery_adapter_bucket_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 28 | 29 | 39 | -------------------------------------------------------------------------------- /library/src/main/res/layout/gallery_fragment_media_grid.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 22 | 23 | 37 | 38 | 54 | 55 | 62 | 63 | 64 | 65 | 74 | 75 | 80 | 81 | 82 | 88 | 89 | 93 | 94 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /library/src/main/res/layout/gallery_fragment_media_page.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 20 | 21 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /library/src/main/res/layout/gallery_fragment_media_preview.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 12 | 13 | 20 | 21 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /library/src/main/res/layout/gallery_loading_view_final_footer_default.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 23 | 24 | -------------------------------------------------------------------------------- /library/src/main/res/layout/gallery_media_image_preview_item.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /library/src/main/res/layout/item_gallery_media_grid.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 21 | 22 | 27 | 28 | 29 | 34 | 35 | 44 | -------------------------------------------------------------------------------- /library/src/main/res/layout/item_gallery_media_grid_fresco.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 20 | 21 | 26 | 27 | 28 | 29 | 33 | 34 | 35 | 44 | -------------------------------------------------------------------------------- /library/src/main/res/values/gallery_default_theme.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #2A2A2F 5 | @dimen/abc_action_bar_default_height_material 6 | 7 | @drawable/gallery_ic_cross 8 | #ffffff 9 | 12sp 10 | #ffffff 11 | @dimen/abc_text_size_title_material_toolbar 12 | 13 | 0.3dp 14 | 1dp 15 | #151515 16 | #ffffff 17 | #fff 18 | #fff 19 | #151515 20 | #FF6E40 21 | #ffffff 22 | #CC5833 23 | #FF6E40 24 | #151515 25 | #282829 26 | #F2F2F2 27 | #D8D8D8 28 | #D8D8D8 29 | #D9000000 30 | #E2E2E2 31 | #E2E2E2 32 | 33 | 34 | #FF6E40 35 | #fff 36 | #000 37 | #000 38 | #808080 39 | #000 40 | 41 | #80ffffff 42 | #ffffff 43 | #8c000000 44 | #4f212121 45 | true 46 | true 47 | 2 48 | 2 49 | 0x11 50 | 51 | -------------------------------------------------------------------------------- /library/src/main/res/values/gallery_dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 1dp 3 | 0.5dp 4 | 10dp 5 | 10dp 6 | 7 | -------------------------------------------------------------------------------- /library/src/main/res/values/gallery_strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 加载更多 3 | 没有更多了 4 | 加载中… 5 | 6 | 完成 7 | 完成(%1$d/%2$d) 8 | 你最多只能选择%1$d张照片 9 | %1$d/%2$d 10 | 图片 11 | 视频 12 | App请求读取你的相册 13 | App请求拍照权限,否则无法拍照 14 | App请求写入你的相册 15 | 空空如也 16 | 该设备无摄像头 17 | 相机不可用 18 | 预览 19 | 裁剪 20 | 所有图片 21 | 所有视频 22 | 拍摄照片 23 | 录制视频 24 | 25 | -------------------------------------------------------------------------------- /sample/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /sample/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | android { 3 | compileSdkVersion 28 4 | defaultConfig { 5 | applicationId "cn.finalteam.rxgalleryfinal.sample" 6 | minSdkVersion 14 7 | //noinspection OldTargetApi 8 | targetSdkVersion 28 9 | versionCode 1 10 | versionName "1.0" 11 | } 12 | buildTypes { 13 | release { 14 | minifyEnabled false 15 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 16 | } 17 | debug { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | lintOptions { 23 | abortOnError false 24 | } 25 | compileOptions { 26 | sourceCompatibility JavaVersion.VERSION_1_8 27 | targetCompatibility JavaVersion.VERSION_1_8 28 | } 29 | } 30 | dependencies { 31 | implementation fileTree(include: ['*.jar'], dir: 'libs') 32 | 33 | implementation 'androidx.appcompat:appcompat:1.1.0' 34 | implementation 'androidx.recyclerview:recyclerview:1.1.0' 35 | implementation 'androidx.exifinterface:exifinterface:1.1.0' 36 | 37 | implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' 38 | implementation 'io.reactivex.rxjava2:rxjava:2.2.15' 39 | implementation 'com.github.yalantis:ucrop:2.2.4' 40 | implementation 'com.squareup.picasso:picasso:2.71828' 41 | implementation 'com.facebook.fresco:fresco:2.0.0' 42 | implementation 'com.facebook.fresco:animated-gif:2.0.0' 43 | implementation 'com.github.bumptech.glide:glide:4.10.0' 44 | implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' 45 | 46 | debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.3' 47 | releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3' 48 | testImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3' 49 | implementation project(':library') 50 | } -------------------------------------------------------------------------------- /sample/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/pengjianbo Dujinyang/Documents/dev/android_dev/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | #1.support-v7-appcompat 20 | -keep public class android.support.v7.widget.** { *; } 21 | -keep public class android.support.v7.internal.widget.** { *; } 22 | -keep public class android.support.v7.internal.view.menu.** { *; } 23 | 24 | -keep public class * extends android.support.v4.view.ActionProvider { 25 | public (android.content.Context); 26 | } 27 | 28 | #2.rxjava 29 | -keep class rx.schedulers.Schedulers { 30 | public static ; 31 | } 32 | -keep class rx.schedulers.ImmediateScheduler { 33 | public ; 34 | } 35 | -keep class rx.schedulers.TestScheduler { 36 | public ; 37 | } 38 | -keep class rx.schedulers.Schedulers { 39 | public static ** test(); 40 | } 41 | -dontwarn sun.misc.** 42 | -keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* { 43 | long producerIndex; 44 | long consumerIndex; 45 | } 46 | -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef { 47 | rx.internal.util.atomic.LinkedQueueNode producerNode; 48 | } 49 | -keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef { 50 | rx.internal.util.atomic.LinkedQueueNode consumerNode; 51 | } 52 | 53 | #3.retrolambda 54 | -dontwarn java.lang.invoke.* 55 | 56 | #4.support-v4 57 | -keep class android.support.v4.** { *; } 58 | -keep interface android.support.v4.** { *; } 59 | 60 | #5.ucrop 61 | -dontwarn com.yalantis.ucrop** 62 | -keep class com.yalantis.ucrop** { *; } 63 | -keep interface com.yalantis.ucrop** { *; } 64 | 65 | #6.photoview 66 | -keep class uk.co.senab.photoview** { *; } 67 | -keep interface uk.co.senab.photoview** { *; } 68 | 69 | #7.rxgalleryfinal 70 | -keep class cn.finalteam.rxgalleryfinal.ui.widget** { *; } 71 | 72 | -keepclassmembers class * extends android.app.Activity { 73 | public void *(android.view.View); 74 | } 75 | -keepclassmembers enum * { 76 | public static **[] values(); 77 | public static ** valueOf(java.lang.String); 78 | } 79 | -keep class * implements android.os.Parcelable { 80 | public static final android.os.Parcelable$Creator *; 81 | } 82 | -keepclassmembers class **.R$* { 83 | public static ; 84 | } 85 | 86 | -keepattributes *Annotation* 87 | -keepclasseswithmembernames class * { 88 | native ; 89 | } 90 | -keepclassmembers public class * extends android.view.View { 91 | void set*(***); 92 | *** get*(); 93 | } 94 | 95 | #8.support-design 96 | -dontwarn android.support.design.** 97 | -keep class android.support.design.** { *; } 98 | -keep interface android.support.design.** { *; } 99 | -keep public class android.support.design.R$* { *; } 100 | 101 | #9.picasso 102 | -dontwarn com.squareup.okhttp.** 103 | -keep class com.squareup.okhttp.**{*;} 104 | # okhttp 105 | -keep class okhttp3.** { *; } 106 | -keep interface okhttp3.** { *; } 107 | -dontwarn okhttp3.** 108 | 109 | # okio 110 | -keep class sun.misc.Unsafe { *; } 111 | -dontwarn java.nio.file.* 112 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 113 | -keep class okio.**{*;} 114 | -dontwarn okio.** -------------------------------------------------------------------------------- /sample/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 31 | 32 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /sample/src/main/java/cn/finalteam/rxgalleryfinal/sample/IApplication.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.sample; 2 | 3 | import android.app.Application; 4 | 5 | import com.facebook.drawee.backends.pipeline.Fresco; 6 | import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator; 7 | import com.nostra13.universalimageloader.core.ImageLoader; 8 | import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; 9 | import com.nostra13.universalimageloader.core.assist.QueueProcessingType; 10 | import com.squareup.leakcanary.LeakCanary; 11 | 12 | import cn.finalteam.rxgalleryfinal.utils.ModelUtils; 13 | 14 | /** 15 | * Desction: 16 | * Author:pengjianbo Dujinyang 17 | * Date:16/5/16 上午9:17 18 | */ 19 | public class IApplication extends Application { 20 | 21 | @Override 22 | public void onCreate() { 23 | super.onCreate(); 24 | //打开日志 25 | ModelUtils.setDebugModel(true); 26 | Fresco.initialize(this); 27 | ImageLoaderConfiguration.Builder config = new ImageLoaderConfiguration.Builder(this); 28 | config.threadPriority(Thread.NORM_PRIORITY - 2); 29 | config.denyCacheImageMultipleSizesInMemory(); 30 | config.diskCacheFileNameGenerator(new Md5FileNameGenerator()); 31 | config.diskCacheSize(50 * 1024 * 1024); // 50 MiB 32 | config.tasksProcessingOrder(QueueProcessingType.LIFO); 33 | ImageLoader.getInstance().init(config.build()); 34 | 35 | if (LeakCanary.isInAnalyzerProcess(this)) { 36 | return; 37 | } 38 | LeakCanary.install(this); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /sample/src/main/java/cn/finalteam/rxgalleryfinal/sample/SimpleRxGalleryFinal.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.sample; 2 | 3 | import android.app.Activity; 4 | import android.content.ContentValues; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.net.Uri; 8 | import android.os.Build; 9 | import android.os.Environment; 10 | import android.provider.MediaStore; 11 | 12 | import androidx.annotation.NonNull; 13 | import androidx.annotation.Nullable; 14 | import androidx.appcompat.app.AppCompatActivity; 15 | 16 | import com.yalantis.ucrop.UCrop; 17 | 18 | import java.io.File; 19 | import java.io.FileNotFoundException; 20 | 21 | /** 22 | * by y on 17/07/2017. 23 | *

24 | * 使用相机拍照并裁剪 25 | */ 26 | 27 | public class SimpleRxGalleryFinal { 28 | 29 | private static final String IMAGE_TYPE = "image/jpeg"; 30 | private static final int TYPE_CAMERA = 1111; 31 | 32 | private RxGalleryFinalCropListener listener = null; 33 | 34 | private Uri imagePath; 35 | 36 | 37 | private static final class SimpleRxGalleryFinalHolder { 38 | private static final SimpleRxGalleryFinal SIMPLE_RX_GALLERY_FINAL = new SimpleRxGalleryFinal(); 39 | } 40 | 41 | public static SimpleRxGalleryFinal get() { 42 | return SimpleRxGalleryFinalHolder.SIMPLE_RX_GALLERY_FINAL; 43 | } 44 | 45 | 46 | public SimpleRxGalleryFinal init(RxGalleryFinalCropListener listener) { 47 | this.listener = listener; 48 | return this; 49 | } 50 | 51 | 52 | public void openCamera() { 53 | Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 54 | imagePath = Uri.fromFile(getDiskCacheDir()); 55 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { 56 | intent.putExtra(MediaStore.EXTRA_OUTPUT, imagePath); 57 | } else { 58 | ContentValues contentValues = new ContentValues(1); 59 | contentValues.put(MediaStore.Images.Media.DATA, imagePath.getPath()); 60 | contentValues.put(MediaStore.Images.Media.MIME_TYPE, IMAGE_TYPE); 61 | Uri uri = listener.getSimpleActivity().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues); 62 | intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); 63 | } 64 | listener 65 | .getSimpleActivity() 66 | .startActivityForResult(intent, TYPE_CAMERA); 67 | } 68 | 69 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 70 | switch (resultCode) { 71 | case Activity.RESULT_CANCELED: 72 | listener.onCropCancel(); 73 | break; 74 | case UCrop.RESULT_ERROR: 75 | if (data != null) { 76 | Throwable cropError = UCrop.getError(data); 77 | if (cropError != null) { 78 | listener.onCropError(cropError.getMessage()); 79 | } else { 80 | listener.onCropError("裁剪出现未知错误"); 81 | } 82 | } else { 83 | listener.onCropError("获取相册图片出现错误"); 84 | } 85 | break; 86 | 87 | case Activity.RESULT_OK: 88 | switch (requestCode) { 89 | case TYPE_CAMERA: 90 | notifyImageToCamera(listener.getSimpleActivity(), imagePath); 91 | UCrop of = UCrop.of(imagePath, Uri.fromFile(getDiskCacheDir())); 92 | of.start(listener.getSimpleActivity()); 93 | break; 94 | case UCrop.REQUEST_CROP: 95 | listener.onCropSuccess(UCrop.getOutput(data)); 96 | break; 97 | } 98 | break; 99 | } 100 | } 101 | 102 | private File getDiskCacheDir() { 103 | String cachePath; 104 | if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) { 105 | File externalCacheDir = listener.getSimpleActivity().getExternalCacheDir(); 106 | if (externalCacheDir != null) { 107 | cachePath = externalCacheDir.getPath(); 108 | } else { 109 | cachePath = listener.getSimpleActivity().getCacheDir().getPath(); 110 | } 111 | } else { 112 | cachePath = listener.getSimpleActivity().getCacheDir().getPath(); 113 | } 114 | return new File(cachePath, imageName()); 115 | } 116 | 117 | private void notifyImageToCamera(Context context, Uri uri) { 118 | try { 119 | File file = new File(uri.getPath()); 120 | MediaStore.Images.Media.insertImage(context.getContentResolver(), file.getAbsolutePath(), file.getName(), null); 121 | } catch (FileNotFoundException e) { 122 | e.printStackTrace(); 123 | } 124 | context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri)); 125 | } 126 | 127 | private String imageName() { 128 | return System.currentTimeMillis() + ".jpg"; 129 | } 130 | 131 | 132 | public interface RxGalleryFinalCropListener { 133 | 134 | @NonNull 135 | AppCompatActivity getSimpleActivity(); 136 | 137 | 138 | /** 139 | * 裁剪被取消 140 | */ 141 | void onCropCancel(); 142 | 143 | /** 144 | * 裁剪成功 145 | * 146 | * @param uri 裁剪的 Uri , 有可能会为Null 147 | */ 148 | void onCropSuccess(@Nullable Uri uri); 149 | 150 | 151 | /** 152 | * 裁剪失败 153 | * 154 | * @param errorMessage 错误信息 155 | */ 156 | void onCropError(@NonNull String errorMessage); 157 | 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /sample/src/main/java/cn/finalteam/rxgalleryfinal/sample/imageloader/ImageLoaderActivity.java: -------------------------------------------------------------------------------- 1 | package cn.finalteam.rxgalleryfinal.sample.imageloader; 2 | 3 | import android.os.Bundle; 4 | import android.view.View; 5 | import android.widget.Toast; 6 | 7 | import androidx.annotation.Nullable; 8 | import androidx.appcompat.app.AppCompatActivity; 9 | import androidx.appcompat.widget.AppCompatCheckBox; 10 | 11 | import cn.finalteam.rxgalleryfinal.RxGalleryFinal; 12 | import cn.finalteam.rxgalleryfinal.imageloader.ImageLoaderType; 13 | import cn.finalteam.rxgalleryfinal.rxbus.RxBusResultDisposable; 14 | import cn.finalteam.rxgalleryfinal.rxbus.event.ImageRadioResultEvent; 15 | import cn.finalteam.rxgalleryfinal.sample.R; 16 | import cn.finalteam.rxgalleryfinal.utils.Logger; 17 | 18 | /** 19 | * by y on 2017/6/7. 20 | */ 21 | 22 | public class ImageLoaderActivity extends AppCompatActivity { 23 | 24 | private AppCompatCheckBox appCompatCheckBox; 25 | private RxGalleryFinal with; 26 | 27 | @Override 28 | protected void onCreate(@Nullable Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_imageloader); 31 | appCompatCheckBox = findViewById(R.id.cb_gif); 32 | findViewById(R.id.btn_glide).setOnClickListener(v -> start(ImageLoaderType.GLIDE)); 33 | findViewById(R.id.btn_picasso).setOnClickListener(v -> start(ImageLoaderType.PICASSO)); 34 | findViewById(R.id.btn_fresco).setOnClickListener(v -> start(ImageLoaderType.FRESCO)); 35 | findViewById(R.id.btn_universal).setOnClickListener(v -> start(ImageLoaderType.UNIVERSAL)); 36 | } 37 | 38 | private void start(ImageLoaderType imageLoaderType) { 39 | switch (imageLoaderType) { 40 | case PICASSO: 41 | case UNIVERSAL: 42 | Toast.makeText(getApplicationContext(), imageLoaderType + "不支持Gif", Toast.LENGTH_SHORT).show(); 43 | break; 44 | } 45 | if (with == null) 46 | with = RxGalleryFinal.with(this); 47 | with.image() 48 | .radio() 49 | .gif(appCompatCheckBox.isChecked()) 50 | .imageLoader(imageLoaderType) 51 | .subscribe(new RxBusResultDisposable() { 52 | @Override 53 | protected void onEvent(ImageRadioResultEvent imageRadioResultEvent) throws Exception { 54 | Toast.makeText(getBaseContext(), "选中了图片路径:" + imageRadioResultEvent.getResult().getOriginalPath(), Toast.LENGTH_SHORT).show(); 55 | } 56 | }).openGallery(); 57 | } 58 | 59 | @Override 60 | protected void onDestroy() { 61 | if (with != null) { 62 | Logger.i("RxGalleryFinal == null"); 63 | with = null; 64 | } 65 | super.onDestroy(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_imageloader.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 19 | 20 | 25 | 26 | 31 | 32 | 37 | 38 | 43 | 44 | -------------------------------------------------------------------------------- /sample/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 19 | 20 | 21 |